blob: 97a2227b212199432254330d322be94c49c80147 [file] [log] [blame]
Philipp Reisnerb411b362009-09-25 16:07:19 -07001/*
2 drbd_nl.c
3
4 This file is part of DRBD by Philipp Reisner and Lars Ellenberg.
5
6 Copyright (C) 2001-2008, LINBIT Information Technologies GmbH.
7 Copyright (C) 1999-2008, Philipp Reisner <philipp.reisner@linbit.com>.
8 Copyright (C) 2002-2008, Lars Ellenberg <lars.ellenberg@linbit.com>.
9
10 drbd is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2, or (at your option)
13 any later version.
14
15 drbd is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with drbd; see the file COPYING. If not, write to
22 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23
24 */
25
Philipp Reisnerb411b362009-09-25 16:07:19 -070026#include <linux/module.h>
27#include <linux/drbd.h>
28#include <linux/in.h>
29#include <linux/fs.h>
30#include <linux/file.h>
31#include <linux/slab.h>
Philipp Reisnerb411b362009-09-25 16:07:19 -070032#include <linux/blkpg.h>
33#include <linux/cpumask.h>
34#include "drbd_int.h"
Andreas Gruenbachera3603a62011-05-30 11:47:37 +020035#include "drbd_protocol.h"
Philipp Reisner265be2d2010-05-31 10:14:17 +020036#include "drbd_req.h"
Philipp Reisnerb411b362009-09-25 16:07:19 -070037#include "drbd_wrappers.h"
38#include <asm/unaligned.h>
Philipp Reisnerb411b362009-09-25 16:07:19 -070039#include <linux/drbd_limits.h>
Philipp Reisner87f7be42010-06-11 13:56:33 +020040#include <linux/kthread.h>
Philipp Reisnerb411b362009-09-25 16:07:19 -070041
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +010042#include <net/genetlink.h>
Philipp Reisnerb411b362009-09-25 16:07:19 -070043
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +010044/* .doit */
45// int drbd_adm_create_resource(struct sk_buff *skb, struct genl_info *info);
46// int drbd_adm_delete_resource(struct sk_buff *skb, struct genl_info *info);
47
48int drbd_adm_add_minor(struct sk_buff *skb, struct genl_info *info);
49int drbd_adm_delete_minor(struct sk_buff *skb, struct genl_info *info);
50
Andreas Gruenbacher789c1b62011-06-06 16:16:44 +020051int drbd_adm_new_resource(struct sk_buff *skb, struct genl_info *info);
52int drbd_adm_del_resource(struct sk_buff *skb, struct genl_info *info);
Lars Ellenberg85f75dd72011-03-15 16:26:37 +010053int drbd_adm_down(struct sk_buff *skb, struct genl_info *info);
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +010054
55int drbd_adm_set_role(struct sk_buff *skb, struct genl_info *info);
56int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info);
Lars Ellenbergf3990022011-03-23 14:31:09 +010057int drbd_adm_disk_opts(struct sk_buff *skb, struct genl_info *info);
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +010058int drbd_adm_detach(struct sk_buff *skb, struct genl_info *info);
59int drbd_adm_connect(struct sk_buff *skb, struct genl_info *info);
Lars Ellenbergf3990022011-03-23 14:31:09 +010060int drbd_adm_net_opts(struct sk_buff *skb, struct genl_info *info);
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +010061int drbd_adm_resize(struct sk_buff *skb, struct genl_info *info);
62int drbd_adm_start_ov(struct sk_buff *skb, struct genl_info *info);
63int drbd_adm_new_c_uuid(struct sk_buff *skb, struct genl_info *info);
64int drbd_adm_disconnect(struct sk_buff *skb, struct genl_info *info);
65int drbd_adm_invalidate(struct sk_buff *skb, struct genl_info *info);
66int drbd_adm_invalidate_peer(struct sk_buff *skb, struct genl_info *info);
67int drbd_adm_pause_sync(struct sk_buff *skb, struct genl_info *info);
68int drbd_adm_resume_sync(struct sk_buff *skb, struct genl_info *info);
69int drbd_adm_suspend_io(struct sk_buff *skb, struct genl_info *info);
70int drbd_adm_resume_io(struct sk_buff *skb, struct genl_info *info);
71int drbd_adm_outdate(struct sk_buff *skb, struct genl_info *info);
Lars Ellenbergf3990022011-03-23 14:31:09 +010072int drbd_adm_resource_opts(struct sk_buff *skb, struct genl_info *info);
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +010073int drbd_adm_get_status(struct sk_buff *skb, struct genl_info *info);
74int drbd_adm_get_timeout_type(struct sk_buff *skb, struct genl_info *info);
75/* .dumpit */
76int drbd_adm_get_status_all(struct sk_buff *skb, struct netlink_callback *cb);
77
78#include <linux/drbd_genl_api.h>
Andreas Gruenbacher01b39b52011-06-10 12:57:26 +020079#include "drbd_nla.h"
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +010080#include <linux/genl_magic_func.h>
81
82/* used blkdev_get_by_path, to claim our meta data device(s) */
Philipp Reisnerb411b362009-09-25 16:07:19 -070083static char *drbd_m_holder = "Hands off! this is DRBD's meta data device.";
84
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +010085/* Configuration is strictly serialized, because generic netlink message
86 * processing is strictly serialized by the genl_lock().
87 * Which means we can use one static global drbd_config_context struct.
88 */
89static struct drbd_config_context {
90 /* assigned from drbd_genlmsghdr */
91 unsigned int minor;
92 /* assigned from request attributes, if present */
93 unsigned int volume;
94#define VOLUME_UNSPECIFIED (-1U)
95 /* pointer into the request skb,
96 * limited lifetime! */
Andreas Gruenbacher7c3063c2011-06-09 17:52:12 +020097 char *resource_name;
Andreas Gruenbacher089c0752011-06-14 18:28:09 +020098 struct nlattr *my_addr;
99 struct nlattr *peer_addr;
Philipp Reisnerb411b362009-09-25 16:07:19 -0700100
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +0100101 /* reply buffer */
102 struct sk_buff *reply_skb;
103 /* pointer into reply buffer */
104 struct drbd_genlmsghdr *reply_dh;
105 /* resolved from attributes, if possible */
106 struct drbd_conf *mdev;
107 struct drbd_tconn *tconn;
108} adm_ctx;
109
110static void drbd_adm_send_reply(struct sk_buff *skb, struct genl_info *info)
111{
112 genlmsg_end(skb, genlmsg_data(nlmsg_data(nlmsg_hdr(skb))));
113 if (genlmsg_reply(skb, info))
114 printk(KERN_ERR "drbd: error sending genl reply\n");
Philipp Reisnerb411b362009-09-25 16:07:19 -0700115}
116
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +0100117/* Used on a fresh "drbd_adm_prepare"d reply_skb, this cannot fail: The only
118 * reason it could fail was no space in skb, and there are 4k available. */
Lars Ellenberg8432b312011-03-08 16:11:16 +0100119int drbd_msg_put_info(const char *info)
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +0100120{
121 struct sk_buff *skb = adm_ctx.reply_skb;
122 struct nlattr *nla;
123 int err = -EMSGSIZE;
Philipp Reisnerb411b362009-09-25 16:07:19 -0700124
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +0100125 if (!info || !info[0])
126 return 0;
127
128 nla = nla_nest_start(skb, DRBD_NLA_CFG_REPLY);
129 if (!nla)
130 return err;
131
132 err = nla_put_string(skb, T_info_text, info);
133 if (err) {
134 nla_nest_cancel(skb, nla);
135 return err;
136 } else
137 nla_nest_end(skb, nla);
138 return 0;
139}
140
141/* This would be a good candidate for a "pre_doit" hook,
142 * and per-family private info->pointers.
143 * But we need to stay compatible with older kernels.
144 * If it returns successfully, adm_ctx members are valid.
145 */
146#define DRBD_ADM_NEED_MINOR 1
Andreas Gruenbacher44e52cf2011-06-14 16:07:32 +0200147#define DRBD_ADM_NEED_RESOURCE 2
Andreas Gruenbacher089c0752011-06-14 18:28:09 +0200148#define DRBD_ADM_NEED_CONNECTION 4
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +0100149static int drbd_adm_prepare(struct sk_buff *skb, struct genl_info *info,
150 unsigned flags)
151{
152 struct drbd_genlmsghdr *d_in = info->userhdr;
153 const u8 cmd = info->genlhdr->cmd;
154 int err;
155
156 memset(&adm_ctx, 0, sizeof(adm_ctx));
157
158 /* genl_rcv_msg only checks for CAP_NET_ADMIN on "GENL_ADMIN_PERM" :( */
Philipp Reisner98683652012-11-09 14:18:43 +0100159 if (cmd != DRBD_ADM_GET_STATUS && !capable(CAP_NET_ADMIN))
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +0100160 return -EPERM;
161
162 adm_ctx.reply_skb = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
Andreas Gruenbacher1e2a2552011-05-24 14:17:08 +0200163 if (!adm_ctx.reply_skb) {
164 err = -ENOMEM;
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +0100165 goto fail;
Andreas Gruenbacher1e2a2552011-05-24 14:17:08 +0200166 }
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +0100167
168 adm_ctx.reply_dh = genlmsg_put_reply(adm_ctx.reply_skb,
169 info, &drbd_genl_family, 0, cmd);
170 /* put of a few bytes into a fresh skb of >= 4k will always succeed.
171 * but anyways */
Andreas Gruenbacher1e2a2552011-05-24 14:17:08 +0200172 if (!adm_ctx.reply_dh) {
173 err = -ENOMEM;
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +0100174 goto fail;
Andreas Gruenbacher1e2a2552011-05-24 14:17:08 +0200175 }
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +0100176
177 adm_ctx.reply_dh->minor = d_in->minor;
178 adm_ctx.reply_dh->ret_code = NO_ERROR;
179
Andreas Gruenbacher089c0752011-06-14 18:28:09 +0200180 adm_ctx.volume = VOLUME_UNSPECIFIED;
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +0100181 if (info->attrs[DRBD_NLA_CFG_CONTEXT]) {
182 struct nlattr *nla;
183 /* parse and validate only */
Lars Ellenbergf3990022011-03-23 14:31:09 +0100184 err = drbd_cfg_context_from_attrs(NULL, info);
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +0100185 if (err)
186 goto fail;
187
188 /* It was present, and valid,
189 * copy it over to the reply skb. */
190 err = nla_put_nohdr(adm_ctx.reply_skb,
191 info->attrs[DRBD_NLA_CFG_CONTEXT]->nla_len,
192 info->attrs[DRBD_NLA_CFG_CONTEXT]);
193 if (err)
194 goto fail;
195
196 /* and assign stuff to the global adm_ctx */
197 nla = nested_attr_tb[__nla_type(T_ctx_volume)];
Andreas Gruenbacher089c0752011-06-14 18:28:09 +0200198 if (nla)
199 adm_ctx.volume = nla_get_u32(nla);
Andreas Gruenbacher7c3063c2011-06-09 17:52:12 +0200200 nla = nested_attr_tb[__nla_type(T_ctx_resource_name)];
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +0100201 if (nla)
Andreas Gruenbacher7c3063c2011-06-09 17:52:12 +0200202 adm_ctx.resource_name = nla_data(nla);
Andreas Gruenbacher089c0752011-06-14 18:28:09 +0200203 adm_ctx.my_addr = nested_attr_tb[__nla_type(T_ctx_my_addr)];
204 adm_ctx.peer_addr = nested_attr_tb[__nla_type(T_ctx_peer_addr)];
205 if ((adm_ctx.my_addr &&
206 nla_len(adm_ctx.my_addr) > sizeof(adm_ctx.tconn->my_addr)) ||
207 (adm_ctx.peer_addr &&
208 nla_len(adm_ctx.peer_addr) > sizeof(adm_ctx.tconn->peer_addr))) {
209 err = -EINVAL;
210 goto fail;
211 }
212 }
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +0100213
214 adm_ctx.minor = d_in->minor;
215 adm_ctx.mdev = minor_to_mdev(d_in->minor);
Andreas Gruenbacher7c3063c2011-06-09 17:52:12 +0200216 adm_ctx.tconn = conn_get_by_name(adm_ctx.resource_name);
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +0100217
218 if (!adm_ctx.mdev && (flags & DRBD_ADM_NEED_MINOR)) {
219 drbd_msg_put_info("unknown minor");
220 return ERR_MINOR_INVALID;
221 }
Andreas Gruenbacher44e52cf2011-06-14 16:07:32 +0200222 if (!adm_ctx.tconn && (flags & DRBD_ADM_NEED_RESOURCE)) {
223 drbd_msg_put_info("unknown resource");
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +0100224 return ERR_INVALID_REQUEST;
225 }
226
Andreas Gruenbacher089c0752011-06-14 18:28:09 +0200227 if (flags & DRBD_ADM_NEED_CONNECTION) {
228 if (adm_ctx.tconn && !(flags & DRBD_ADM_NEED_RESOURCE)) {
229 drbd_msg_put_info("no resource name expected");
230 return ERR_INVALID_REQUEST;
231 }
232 if (adm_ctx.mdev) {
233 drbd_msg_put_info("no minor number expected");
234 return ERR_INVALID_REQUEST;
235 }
236 if (adm_ctx.my_addr && adm_ctx.peer_addr)
237 adm_ctx.tconn = conn_get_by_addrs(nla_data(adm_ctx.my_addr),
238 nla_len(adm_ctx.my_addr),
239 nla_data(adm_ctx.peer_addr),
240 nla_len(adm_ctx.peer_addr));
241 if (!adm_ctx.tconn) {
242 drbd_msg_put_info("unknown connection");
243 return ERR_INVALID_REQUEST;
244 }
245 }
246
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +0100247 /* some more paranoia, if the request was over-determined */
Lars Ellenberg527f4b22011-03-14 13:58:03 +0100248 if (adm_ctx.mdev && adm_ctx.tconn &&
249 adm_ctx.mdev->tconn != adm_ctx.tconn) {
Andreas Gruenbacher44e52cf2011-06-14 16:07:32 +0200250 pr_warning("request: minor=%u, resource=%s; but that minor belongs to connection %s\n",
Andreas Gruenbacher7c3063c2011-06-09 17:52:12 +0200251 adm_ctx.minor, adm_ctx.resource_name,
252 adm_ctx.mdev->tconn->name);
Andreas Gruenbacher44e52cf2011-06-14 16:07:32 +0200253 drbd_msg_put_info("minor exists in different resource");
Lars Ellenberg527f4b22011-03-14 13:58:03 +0100254 return ERR_INVALID_REQUEST;
255 }
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +0100256 if (adm_ctx.mdev &&
257 adm_ctx.volume != VOLUME_UNSPECIFIED &&
258 adm_ctx.volume != adm_ctx.mdev->vnr) {
259 pr_warning("request: minor=%u, volume=%u; but that minor is volume %u in %s\n",
260 adm_ctx.minor, adm_ctx.volume,
261 adm_ctx.mdev->vnr, adm_ctx.mdev->tconn->name);
Lars Ellenberg527f4b22011-03-14 13:58:03 +0100262 drbd_msg_put_info("minor exists as different volume");
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +0100263 return ERR_INVALID_REQUEST;
264 }
Philipp Reisner0ace9df2011-04-24 10:53:19 +0200265
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +0100266 return NO_ERROR;
267
268fail:
269 nlmsg_free(adm_ctx.reply_skb);
270 adm_ctx.reply_skb = NULL;
Andreas Gruenbacher1e2a2552011-05-24 14:17:08 +0200271 return err;
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +0100272}
273
274static int drbd_adm_finish(struct genl_info *info, int retcode)
275{
Philipp Reisner0ace9df2011-04-24 10:53:19 +0200276 if (adm_ctx.tconn) {
277 kref_put(&adm_ctx.tconn->kref, &conn_destroy);
278 adm_ctx.tconn = NULL;
279 }
280
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +0100281 if (!adm_ctx.reply_skb)
282 return -ENOMEM;
283
284 adm_ctx.reply_dh->ret_code = retcode;
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +0100285 drbd_adm_send_reply(adm_ctx.reply_skb, info);
286 return 0;
287}
Philipp Reisnerb411b362009-09-25 16:07:19 -0700288
Philipp Reisner6b75dce2011-03-16 17:39:12 +0100289static void setup_khelper_env(struct drbd_tconn *tconn, char **envp)
290{
291 char *afs;
292
Andreas Gruenbacher089c0752011-06-14 18:28:09 +0200293 /* FIXME: A future version will not allow this case. */
294 if (tconn->my_addr_len == 0 || tconn->peer_addr_len == 0)
295 return;
296
297 switch (((struct sockaddr *)&tconn->peer_addr)->sa_family) {
298 case AF_INET6:
299 afs = "ipv6";
300 snprintf(envp[4], 60, "DRBD_PEER_ADDRESS=%pI6",
301 &((struct sockaddr_in6 *)&tconn->peer_addr)->sin6_addr);
302 break;
303 case AF_INET:
304 afs = "ipv4";
305 snprintf(envp[4], 60, "DRBD_PEER_ADDRESS=%pI4",
306 &((struct sockaddr_in *)&tconn->peer_addr)->sin_addr);
307 break;
308 default:
309 afs = "ssocks";
310 snprintf(envp[4], 60, "DRBD_PEER_ADDRESS=%pI4",
311 &((struct sockaddr_in *)&tconn->peer_addr)->sin_addr);
Philipp Reisner6b75dce2011-03-16 17:39:12 +0100312 }
Andreas Gruenbacher089c0752011-06-14 18:28:09 +0200313 snprintf(envp[3], 20, "DRBD_PEER_AF=%s", afs);
Philipp Reisner6b75dce2011-03-16 17:39:12 +0100314}
Philipp Reisnerb411b362009-09-25 16:07:19 -0700315
316int drbd_khelper(struct drbd_conf *mdev, char *cmd)
317{
318 char *envp[] = { "HOME=/",
319 "TERM=linux",
320 "PATH=/sbin:/usr/sbin:/bin:/usr/bin",
Philipp Reisner6b75dce2011-03-16 17:39:12 +0100321 (char[20]) { }, /* address family */
322 (char[60]) { }, /* address */
Philipp Reisnerb411b362009-09-25 16:07:19 -0700323 NULL };
Philipp Reisner6b75dce2011-03-16 17:39:12 +0100324 char mb[12];
Philipp Reisnerb411b362009-09-25 16:07:19 -0700325 char *argv[] = {usermode_helper, cmd, mb, NULL };
Lars Ellenberg6f3465e2012-07-30 09:08:25 +0200326 struct drbd_tconn *tconn = mdev->tconn;
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +0100327 struct sib_info sib;
Philipp Reisnerb411b362009-09-25 16:07:19 -0700328 int ret;
329
Lars Ellenberg6f3465e2012-07-30 09:08:25 +0200330 if (current == tconn->worker.task)
331 set_bit(CALLBACK_PENDING, &tconn->flags);
Lars Ellenbergc2ba6862012-06-14 15:14:06 +0200332
Philipp Reisnerb411b362009-09-25 16:07:19 -0700333 snprintf(mb, 12, "minor-%d", mdev_to_minor(mdev));
Lars Ellenberg6f3465e2012-07-30 09:08:25 +0200334 setup_khelper_env(tconn, envp);
Philipp Reisnerb411b362009-09-25 16:07:19 -0700335
Lars Ellenberg1090c052010-07-19 17:41:04 +0200336 /* The helper may take some time.
337 * write out any unsynced meta data changes now */
338 drbd_md_sync(mdev);
339
Philipp Reisnerb411b362009-09-25 16:07:19 -0700340 dev_info(DEV, "helper command: %s %s %s\n", usermode_helper, cmd, mb);
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +0100341 sib.sib_reason = SIB_HELPER_PRE;
342 sib.helper_name = cmd;
343 drbd_bcast_event(mdev, &sib);
Oleg Nesterov70834d32012-03-23 15:02:46 -0700344 ret = call_usermodehelper(usermode_helper, argv, envp, UMH_WAIT_PROC);
Philipp Reisnerb411b362009-09-25 16:07:19 -0700345 if (ret)
346 dev_warn(DEV, "helper command: %s %s %s exit code %u (0x%x)\n",
347 usermode_helper, cmd, mb,
348 (ret >> 8) & 0xff, ret);
349 else
350 dev_info(DEV, "helper command: %s %s %s exit code %u (0x%x)\n",
351 usermode_helper, cmd, mb,
352 (ret >> 8) & 0xff, ret);
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +0100353 sib.sib_reason = SIB_HELPER_POST;
354 sib.helper_exit_code = ret;
355 drbd_bcast_event(mdev, &sib);
Philipp Reisnerb411b362009-09-25 16:07:19 -0700356
Lars Ellenberg6f3465e2012-07-30 09:08:25 +0200357 if (current == tconn->worker.task)
358 clear_bit(CALLBACK_PENDING, &tconn->flags);
Lars Ellenbergc2ba6862012-06-14 15:14:06 +0200359
Philipp Reisnerb411b362009-09-25 16:07:19 -0700360 if (ret < 0) /* Ignore any ERRNOs we got. */
361 ret = 0;
362
363 return ret;
364}
365
Rashika Kheria4b7a5302013-12-19 15:17:33 +0530366static int conn_khelper(struct drbd_tconn *tconn, char *cmd)
Philipp Reisnerb411b362009-09-25 16:07:19 -0700367{
Philipp Reisner6b75dce2011-03-16 17:39:12 +0100368 char *envp[] = { "HOME=/",
369 "TERM=linux",
370 "PATH=/sbin:/usr/sbin:/bin:/usr/bin",
371 (char[20]) { }, /* address family */
372 (char[60]) { }, /* address */
373 NULL };
374 char *argv[] = {usermode_helper, cmd, tconn->name, NULL };
375 int ret;
376
377 setup_khelper_env(tconn, envp);
378 conn_md_sync(tconn);
379
380 conn_info(tconn, "helper command: %s %s %s\n", usermode_helper, cmd, tconn->name);
381 /* TODO: conn_bcast_event() ?? */
382
Philipp Reisner98683652012-11-09 14:18:43 +0100383 ret = call_usermodehelper(usermode_helper, argv, envp, UMH_WAIT_PROC);
Philipp Reisner6b75dce2011-03-16 17:39:12 +0100384 if (ret)
385 conn_warn(tconn, "helper command: %s %s %s exit code %u (0x%x)\n",
386 usermode_helper, cmd, tconn->name,
387 (ret >> 8) & 0xff, ret);
388 else
389 conn_info(tconn, "helper command: %s %s %s exit code %u (0x%x)\n",
390 usermode_helper, cmd, tconn->name,
391 (ret >> 8) & 0xff, ret);
392 /* TODO: conn_bcast_event() ?? */
393
394 if (ret < 0) /* Ignore any ERRNOs we got. */
395 ret = 0;
396
397 return ret;
398}
399
Philipp Reisnercb703452011-03-24 11:03:07 +0100400static enum drbd_fencing_p highest_fencing_policy(struct drbd_tconn *tconn)
Philipp Reisnerb411b362009-09-25 16:07:19 -0700401{
Philipp Reisnercb703452011-03-24 11:03:07 +0100402 enum drbd_fencing_p fp = FP_NOT_AVAIL;
403 struct drbd_conf *mdev;
404 int vnr;
Philipp Reisnerb411b362009-09-25 16:07:19 -0700405
Philipp Reisner695d08f2011-04-11 22:53:32 -0700406 rcu_read_lock();
Philipp Reisnercb703452011-03-24 11:03:07 +0100407 idr_for_each_entry(&tconn->volumes, mdev, vnr) {
408 if (get_ldev_if_state(mdev, D_CONSISTENT)) {
Philipp Reisnerdaeda1c2011-05-03 15:00:55 +0200409 fp = max_t(enum drbd_fencing_p, fp,
410 rcu_dereference(mdev->ldev->disk_conf)->fencing);
Philipp Reisnercb703452011-03-24 11:03:07 +0100411 put_ldev(mdev);
412 }
Philipp Reisnerb411b362009-09-25 16:07:19 -0700413 }
Philipp Reisner695d08f2011-04-11 22:53:32 -0700414 rcu_read_unlock();
Philipp Reisnerb411b362009-09-25 16:07:19 -0700415
Philipp Reisnercb703452011-03-24 11:03:07 +0100416 return fp;
417}
418
419bool conn_try_outdate_peer(struct drbd_tconn *tconn)
420{
Philipp Reisner28e448b2013-06-25 16:50:06 +0200421 unsigned int connect_cnt;
Philipp Reisnercb703452011-03-24 11:03:07 +0100422 union drbd_state mask = { };
423 union drbd_state val = { };
424 enum drbd_fencing_p fp;
Philipp Reisnerb411b362009-09-25 16:07:19 -0700425 char *ex_to_string;
426 int r;
Philipp Reisnerb411b362009-09-25 16:07:19 -0700427
Philipp Reisnercb703452011-03-24 11:03:07 +0100428 if (tconn->cstate >= C_WF_REPORT_PARAMS) {
429 conn_err(tconn, "Expected cstate < C_WF_REPORT_PARAMS\n");
430 return false;
Philipp Reisnerb411b362009-09-25 16:07:19 -0700431 }
432
Philipp Reisner28e448b2013-06-25 16:50:06 +0200433 spin_lock_irq(&tconn->req_lock);
434 connect_cnt = tconn->connect_cnt;
435 spin_unlock_irq(&tconn->req_lock);
436
Philipp Reisnercb703452011-03-24 11:03:07 +0100437 fp = highest_fencing_policy(tconn);
438 switch (fp) {
439 case FP_NOT_AVAIL:
440 conn_warn(tconn, "Not fencing peer, I'm not even Consistent myself.\n");
441 goto out;
442 case FP_DONT_CARE:
443 return true;
444 default: ;
445 }
446
447 r = conn_khelper(tconn, "fence-peer");
Philipp Reisnerb411b362009-09-25 16:07:19 -0700448
449 switch ((r>>8) & 0xff) {
450 case 3: /* peer is inconsistent */
451 ex_to_string = "peer is inconsistent or worse";
Philipp Reisnercb703452011-03-24 11:03:07 +0100452 mask.pdsk = D_MASK;
453 val.pdsk = D_INCONSISTENT;
Philipp Reisnerb411b362009-09-25 16:07:19 -0700454 break;
455 case 4: /* peer got outdated, or was already outdated */
456 ex_to_string = "peer was fenced";
Philipp Reisnercb703452011-03-24 11:03:07 +0100457 mask.pdsk = D_MASK;
458 val.pdsk = D_OUTDATED;
Philipp Reisnerb411b362009-09-25 16:07:19 -0700459 break;
460 case 5: /* peer was down */
Philipp Reisnercb703452011-03-24 11:03:07 +0100461 if (conn_highest_disk(tconn) == D_UP_TO_DATE) {
Philipp Reisnerb411b362009-09-25 16:07:19 -0700462 /* we will(have) create(d) a new UUID anyways... */
463 ex_to_string = "peer is unreachable, assumed to be dead";
Philipp Reisnercb703452011-03-24 11:03:07 +0100464 mask.pdsk = D_MASK;
465 val.pdsk = D_OUTDATED;
Philipp Reisnerb411b362009-09-25 16:07:19 -0700466 } else {
467 ex_to_string = "peer unreachable, doing nothing since disk != UpToDate";
Philipp Reisnerb411b362009-09-25 16:07:19 -0700468 }
469 break;
470 case 6: /* Peer is primary, voluntarily outdate myself.
471 * This is useful when an unconnected R_SECONDARY is asked to
472 * become R_PRIMARY, but finds the other peer being active. */
473 ex_to_string = "peer is active";
Philipp Reisnercb703452011-03-24 11:03:07 +0100474 conn_warn(tconn, "Peer is primary, outdating myself.\n");
475 mask.disk = D_MASK;
476 val.disk = D_OUTDATED;
Philipp Reisnerb411b362009-09-25 16:07:19 -0700477 break;
478 case 7:
479 if (fp != FP_STONITH)
Philipp Reisnercb703452011-03-24 11:03:07 +0100480 conn_err(tconn, "fence-peer() = 7 && fencing != Stonith !!!\n");
Philipp Reisnerb411b362009-09-25 16:07:19 -0700481 ex_to_string = "peer was stonithed";
Philipp Reisnercb703452011-03-24 11:03:07 +0100482 mask.pdsk = D_MASK;
483 val.pdsk = D_OUTDATED;
Philipp Reisnerb411b362009-09-25 16:07:19 -0700484 break;
485 default:
486 /* The script is broken ... */
Philipp Reisnercb703452011-03-24 11:03:07 +0100487 conn_err(tconn, "fence-peer helper broken, returned %d\n", (r>>8)&0xff);
488 return false; /* Eventually leave IO frozen */
Philipp Reisnerb411b362009-09-25 16:07:19 -0700489 }
490
Philipp Reisnercb703452011-03-24 11:03:07 +0100491 conn_info(tconn, "fence-peer helper returned %d (%s)\n",
492 (r>>8) & 0xff, ex_to_string);
Philipp Reisnerfb22c402010-09-08 23:20:21 +0200493
Philipp Reisnercb703452011-03-24 11:03:07 +0100494 out:
Philipp Reisnerfb22c402010-09-08 23:20:21 +0200495
Philipp Reisnercb703452011-03-24 11:03:07 +0100496 /* Not using
497 conn_request_state(tconn, mask, val, CS_VERBOSE);
498 here, because we might were able to re-establish the connection in the
499 meantime. */
500 spin_lock_irq(&tconn->req_lock);
Philipp Reisner28e448b2013-06-25 16:50:06 +0200501 if (tconn->cstate < C_WF_REPORT_PARAMS && !test_bit(STATE_SENT, &tconn->flags)) {
502 if (tconn->connect_cnt != connect_cnt)
503 /* In case the connection was established and droped
504 while the fence-peer handler was running, ignore it */
505 conn_info(tconn, "Ignoring fence-peer exit code\n");
506 else
507 _conn_request_state(tconn, mask, val, CS_VERBOSE);
508 }
Philipp Reisnercb703452011-03-24 11:03:07 +0100509 spin_unlock_irq(&tconn->req_lock);
510
511 return conn_highest_pdsk(tconn) <= D_OUTDATED;
Philipp Reisnerb411b362009-09-25 16:07:19 -0700512}
513
Philipp Reisner87f7be42010-06-11 13:56:33 +0200514static int _try_outdate_peer_async(void *data)
515{
Philipp Reisnercb703452011-03-24 11:03:07 +0100516 struct drbd_tconn *tconn = (struct drbd_tconn *)data;
Philipp Reisner87f7be42010-06-11 13:56:33 +0200517
Philipp Reisnercb703452011-03-24 11:03:07 +0100518 conn_try_outdate_peer(tconn);
Philipp Reisner21423fa2011-05-17 14:19:41 +0200519
Philipp Reisner9dc9fbb2011-04-22 15:23:32 +0200520 kref_put(&tconn->kref, &conn_destroy);
Philipp Reisner87f7be42010-06-11 13:56:33 +0200521 return 0;
522}
523
Philipp Reisnercb703452011-03-24 11:03:07 +0100524void conn_try_outdate_peer_async(struct drbd_tconn *tconn)
Philipp Reisner87f7be42010-06-11 13:56:33 +0200525{
526 struct task_struct *opa;
527
Philipp Reisner9dc9fbb2011-04-22 15:23:32 +0200528 kref_get(&tconn->kref);
Philipp Reisnercb703452011-03-24 11:03:07 +0100529 opa = kthread_run(_try_outdate_peer_async, tconn, "drbd_async_h");
Philipp Reisner9dc9fbb2011-04-22 15:23:32 +0200530 if (IS_ERR(opa)) {
Philipp Reisnercb703452011-03-24 11:03:07 +0100531 conn_err(tconn, "out of mem, failed to invoke fence-peer helper\n");
Philipp Reisner9dc9fbb2011-04-22 15:23:32 +0200532 kref_put(&tconn->kref, &conn_destroy);
533 }
Philipp Reisner87f7be42010-06-11 13:56:33 +0200534}
Philipp Reisnerb411b362009-09-25 16:07:19 -0700535
Andreas Gruenbacherbf885f82010-12-08 00:39:32 +0100536enum drbd_state_rv
537drbd_set_role(struct drbd_conf *mdev, enum drbd_role new_role, int force)
Philipp Reisnerb411b362009-09-25 16:07:19 -0700538{
539 const int max_tries = 4;
Andreas Gruenbacherbf885f82010-12-08 00:39:32 +0100540 enum drbd_state_rv rv = SS_UNKNOWN_ERROR;
Philipp Reisner44ed1672011-04-19 17:10:19 +0200541 struct net_conf *nc;
Philipp Reisnerb411b362009-09-25 16:07:19 -0700542 int try = 0;
543 int forced = 0;
544 union drbd_state mask, val;
Philipp Reisnerb411b362009-09-25 16:07:19 -0700545
546 if (new_role == R_PRIMARY)
Philipp Reisner0625ac12011-02-07 14:49:19 +0100547 request_ping(mdev->tconn); /* Detect a dead peer ASAP */
Philipp Reisnerb411b362009-09-25 16:07:19 -0700548
Philipp Reisner8410da82011-02-11 20:11:10 +0100549 mutex_lock(mdev->state_mutex);
Philipp Reisnerb411b362009-09-25 16:07:19 -0700550
551 mask.i = 0; mask.role = R_MASK;
552 val.i = 0; val.role = new_role;
553
554 while (try++ < max_tries) {
Andreas Gruenbacherbf885f82010-12-08 00:39:32 +0100555 rv = _drbd_request_state(mdev, mask, val, CS_WAIT_COMPLETE);
Philipp Reisnerb411b362009-09-25 16:07:19 -0700556
557 /* in case we first succeeded to outdate,
558 * but now suddenly could establish a connection */
Andreas Gruenbacherbf885f82010-12-08 00:39:32 +0100559 if (rv == SS_CW_FAILED_BY_PEER && mask.pdsk != 0) {
Philipp Reisnerb411b362009-09-25 16:07:19 -0700560 val.pdsk = 0;
561 mask.pdsk = 0;
562 continue;
563 }
564
Andreas Gruenbacherbf885f82010-12-08 00:39:32 +0100565 if (rv == SS_NO_UP_TO_DATE_DISK && force &&
Philipp Reisnerd10a33c2010-03-04 15:11:39 +0100566 (mdev->state.disk < D_UP_TO_DATE &&
567 mdev->state.disk >= D_INCONSISTENT)) {
Philipp Reisnerb411b362009-09-25 16:07:19 -0700568 mask.disk = D_MASK;
569 val.disk = D_UP_TO_DATE;
570 forced = 1;
571 continue;
572 }
573
Andreas Gruenbacherbf885f82010-12-08 00:39:32 +0100574 if (rv == SS_NO_UP_TO_DATE_DISK &&
Philipp Reisnerb411b362009-09-25 16:07:19 -0700575 mdev->state.disk == D_CONSISTENT && mask.pdsk == 0) {
576 D_ASSERT(mdev->state.pdsk == D_UNKNOWN);
Philipp Reisnerb411b362009-09-25 16:07:19 -0700577
Philipp Reisnercb703452011-03-24 11:03:07 +0100578 if (conn_try_outdate_peer(mdev->tconn)) {
Philipp Reisnerb411b362009-09-25 16:07:19 -0700579 val.disk = D_UP_TO_DATE;
580 mask.disk = D_MASK;
581 }
Philipp Reisnerb411b362009-09-25 16:07:19 -0700582 continue;
583 }
584
Andreas Gruenbacherbf885f82010-12-08 00:39:32 +0100585 if (rv == SS_NOTHING_TO_DO)
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +0100586 goto out;
Andreas Gruenbacherbf885f82010-12-08 00:39:32 +0100587 if (rv == SS_PRIMARY_NOP && mask.pdsk == 0) {
Philipp Reisnercb703452011-03-24 11:03:07 +0100588 if (!conn_try_outdate_peer(mdev->tconn) && force) {
Philipp Reisnerb411b362009-09-25 16:07:19 -0700589 dev_warn(DEV, "Forced into split brain situation!\n");
Philipp Reisnercb703452011-03-24 11:03:07 +0100590 mask.pdsk = D_MASK;
591 val.pdsk = D_OUTDATED;
592
Philipp Reisnerb411b362009-09-25 16:07:19 -0700593 }
Philipp Reisnerb411b362009-09-25 16:07:19 -0700594 continue;
595 }
Andreas Gruenbacherbf885f82010-12-08 00:39:32 +0100596 if (rv == SS_TWO_PRIMARIES) {
Philipp Reisnerb411b362009-09-25 16:07:19 -0700597 /* Maybe the peer is detected as dead very soon...
598 retry at most once more in this case. */
Philipp Reisner44ed1672011-04-19 17:10:19 +0200599 int timeo;
600 rcu_read_lock();
601 nc = rcu_dereference(mdev->tconn->net_conf);
602 timeo = nc ? (nc->ping_timeo + 1) * HZ / 10 : 1;
603 rcu_read_unlock();
604 schedule_timeout_interruptible(timeo);
Philipp Reisnerb411b362009-09-25 16:07:19 -0700605 if (try < max_tries)
606 try = max_tries - 1;
607 continue;
608 }
Andreas Gruenbacherbf885f82010-12-08 00:39:32 +0100609 if (rv < SS_SUCCESS) {
610 rv = _drbd_request_state(mdev, mask, val,
Philipp Reisnerb411b362009-09-25 16:07:19 -0700611 CS_VERBOSE + CS_WAIT_COMPLETE);
Andreas Gruenbacherbf885f82010-12-08 00:39:32 +0100612 if (rv < SS_SUCCESS)
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +0100613 goto out;
Philipp Reisnerb411b362009-09-25 16:07:19 -0700614 }
615 break;
616 }
617
Andreas Gruenbacherbf885f82010-12-08 00:39:32 +0100618 if (rv < SS_SUCCESS)
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +0100619 goto out;
Philipp Reisnerb411b362009-09-25 16:07:19 -0700620
621 if (forced)
622 dev_warn(DEV, "Forced to consider local data as UpToDate!\n");
623
624 /* Wait until nothing is on the fly :) */
625 wait_event(mdev->misc_wait, atomic_read(&mdev->ap_pending_cnt) == 0);
626
Lars Ellenbergb6dd1a82011-11-28 15:04:49 +0100627 /* FIXME also wait for all pending P_BARRIER_ACK? */
628
Philipp Reisnerb411b362009-09-25 16:07:19 -0700629 if (new_role == R_SECONDARY) {
Andreas Gruenbacher81e84652010-12-09 15:03:57 +0100630 set_disk_ro(mdev->vdisk, true);
Philipp Reisnerb411b362009-09-25 16:07:19 -0700631 if (get_ldev(mdev)) {
632 mdev->ldev->md.uuid[UI_CURRENT] &= ~(u64)1;
633 put_ldev(mdev);
634 }
635 } else {
Philipp Reisnera0095502011-05-03 13:14:15 +0200636 mutex_lock(&mdev->tconn->conf_update);
Philipp Reisner91fd4da2011-04-20 17:47:29 +0200637 nc = mdev->tconn->net_conf;
Philipp Reisner44ed1672011-04-19 17:10:19 +0200638 if (nc)
Andreas Gruenbacher6139f602011-05-06 20:00:02 +0200639 nc->discard_my_data = 0; /* without copy; single bit op is atomic */
Philipp Reisnera0095502011-05-03 13:14:15 +0200640 mutex_unlock(&mdev->tconn->conf_update);
Philipp Reisner91fd4da2011-04-20 17:47:29 +0200641
Andreas Gruenbacher81e84652010-12-09 15:03:57 +0100642 set_disk_ro(mdev->vdisk, false);
Philipp Reisnerb411b362009-09-25 16:07:19 -0700643 if (get_ldev(mdev)) {
644 if (((mdev->state.conn < C_CONNECTED ||
645 mdev->state.pdsk <= D_FAILED)
646 && mdev->ldev->md.uuid[UI_BITMAP] == 0) || forced)
647 drbd_uuid_new_current(mdev);
648
649 mdev->ldev->md.uuid[UI_CURRENT] |= (u64)1;
650 put_ldev(mdev);
651 }
652 }
653
Lars Ellenberg19f843a2010-12-15 08:59:11 +0100654 /* writeout of activity log covered areas of the bitmap
655 * to stable storage done in after state change already */
Philipp Reisnerb411b362009-09-25 16:07:19 -0700656
657 if (mdev->state.conn >= C_WF_REPORT_PARAMS) {
658 /* if this was forced, we should consider sync */
659 if (forced)
660 drbd_send_uuids(mdev);
Lars Ellenbergf479ea02011-10-27 16:52:30 +0200661 drbd_send_current_state(mdev);
Philipp Reisnerb411b362009-09-25 16:07:19 -0700662 }
663
664 drbd_md_sync(mdev);
665
666 kobject_uevent(&disk_to_dev(mdev->vdisk)->kobj, KOBJ_CHANGE);
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +0100667out:
Philipp Reisner8410da82011-02-11 20:11:10 +0100668 mutex_unlock(mdev->state_mutex);
Andreas Gruenbacherbf885f82010-12-08 00:39:32 +0100669 return rv;
Philipp Reisnerb411b362009-09-25 16:07:19 -0700670}
671
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +0100672static const char *from_attrs_err_to_txt(int err)
Lars Ellenbergef50a3e2010-09-01 14:39:30 +0200673{
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +0100674 return err == -ENOMSG ? "required attribute missing" :
675 err == -EOPNOTSUPP ? "unknown mandatory attribute" :
Lars Ellenbergf3990022011-03-23 14:31:09 +0100676 err == -EEXIST ? "can not change invariant setting" :
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +0100677 "invalid attribute value";
Lars Ellenbergef50a3e2010-09-01 14:39:30 +0200678}
Philipp Reisnerb411b362009-09-25 16:07:19 -0700679
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +0100680int drbd_adm_set_role(struct sk_buff *skb, struct genl_info *info)
Philipp Reisnerb411b362009-09-25 16:07:19 -0700681{
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +0100682 struct set_role_parms parms;
683 int err;
684 enum drbd_ret_code retcode;
Philipp Reisnerb411b362009-09-25 16:07:19 -0700685
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +0100686 retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_MINOR);
687 if (!adm_ctx.reply_skb)
688 return retcode;
689 if (retcode != NO_ERROR)
690 goto out;
691
692 memset(&parms, 0, sizeof(parms));
693 if (info->attrs[DRBD_NLA_SET_ROLE_PARMS]) {
Lars Ellenbergf3990022011-03-23 14:31:09 +0100694 err = set_role_parms_from_attrs(&parms, info);
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +0100695 if (err) {
696 retcode = ERR_MANDATORY_TAG;
697 drbd_msg_put_info(from_attrs_err_to_txt(err));
698 goto out;
699 }
Philipp Reisnerb411b362009-09-25 16:07:19 -0700700 }
701
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +0100702 if (info->genlhdr->cmd == DRBD_ADM_PRIMARY)
703 retcode = drbd_set_role(adm_ctx.mdev, R_PRIMARY, parms.assume_uptodate);
704 else
705 retcode = drbd_set_role(adm_ctx.mdev, R_SECONDARY, 0);
706out:
707 drbd_adm_finish(info, retcode);
Philipp Reisnerb411b362009-09-25 16:07:19 -0700708 return 0;
709}
710
Lars Ellenbergae8bf312013-03-19 18:16:43 +0100711/* Initializes the md.*_offset members, so we are able to find
712 * the on disk meta data.
713 *
714 * We currently have two possible layouts:
715 * external:
716 * |----------- md_size_sect ------------------|
717 * [ 4k superblock ][ activity log ][ Bitmap ]
718 * | al_offset == 8 |
719 * | bm_offset = al_offset + X |
720 * ==> bitmap sectors = md_size_sect - bm_offset
721 *
722 * internal:
723 * |----------- md_size_sect ------------------|
724 * [data.....][ Bitmap ][ activity log ][ 4k superblock ]
725 * | al_offset < 0 |
726 * | bm_offset = al_offset - Y |
727 * ==> bitmap sectors = Y = al_offset - bm_offset
728 *
729 * Activity log size used to be fixed 32kB,
730 * but is about to become configurable.
731 */
Philipp Reisnerb411b362009-09-25 16:07:19 -0700732static void drbd_md_set_sector_offsets(struct drbd_conf *mdev,
733 struct drbd_backing_dev *bdev)
734{
735 sector_t md_size_sect = 0;
Lars Ellenbergc04ccaa2013-03-19 18:16:47 +0100736 unsigned int al_size_sect = bdev->md.al_size_4k * 8;
Philipp Reisnerdaeda1c2011-05-03 15:00:55 +0200737
Lars Ellenberg3a4d4eb2013-03-19 18:16:44 +0100738 bdev->md.md_offset = drbd_md_ss(bdev);
739
Lars Ellenberg68e41a42013-03-19 18:16:45 +0100740 switch (bdev->md.meta_dev_idx) {
Philipp Reisnerb411b362009-09-25 16:07:19 -0700741 default:
742 /* v07 style fixed size indexed meta data */
Lars Ellenbergae8bf312013-03-19 18:16:43 +0100743 bdev->md.md_size_sect = MD_128MB_SECT;
Lars Ellenbergae8bf312013-03-19 18:16:43 +0100744 bdev->md.al_offset = MD_4kB_SECT;
745 bdev->md.bm_offset = MD_4kB_SECT + al_size_sect;
Philipp Reisnerb411b362009-09-25 16:07:19 -0700746 break;
747 case DRBD_MD_INDEX_FLEX_EXT:
748 /* just occupy the full device; unit: sectors */
749 bdev->md.md_size_sect = drbd_get_capacity(bdev->md_bdev);
Lars Ellenbergae8bf312013-03-19 18:16:43 +0100750 bdev->md.al_offset = MD_4kB_SECT;
751 bdev->md.bm_offset = MD_4kB_SECT + al_size_sect;
Philipp Reisnerb411b362009-09-25 16:07:19 -0700752 break;
753 case DRBD_MD_INDEX_INTERNAL:
754 case DRBD_MD_INDEX_FLEX_INT:
Philipp Reisnerb411b362009-09-25 16:07:19 -0700755 /* al size is still fixed */
Lars Ellenbergae8bf312013-03-19 18:16:43 +0100756 bdev->md.al_offset = -al_size_sect;
Philipp Reisnerb411b362009-09-25 16:07:19 -0700757 /* we need (slightly less than) ~ this much bitmap sectors: */
758 md_size_sect = drbd_get_capacity(bdev->backing_bdev);
759 md_size_sect = ALIGN(md_size_sect, BM_SECT_PER_EXT);
760 md_size_sect = BM_SECT_TO_EXT(md_size_sect);
761 md_size_sect = ALIGN(md_size_sect, 8);
762
763 /* plus the "drbd meta data super block",
764 * and the activity log; */
Lars Ellenbergae8bf312013-03-19 18:16:43 +0100765 md_size_sect += MD_4kB_SECT + al_size_sect;
Philipp Reisnerb411b362009-09-25 16:07:19 -0700766
767 bdev->md.md_size_sect = md_size_sect;
768 /* bitmap offset is adjusted by 'super' block size */
Lars Ellenbergae8bf312013-03-19 18:16:43 +0100769 bdev->md.bm_offset = -md_size_sect + MD_4kB_SECT;
Philipp Reisnerb411b362009-09-25 16:07:19 -0700770 break;
771 }
772}
773
Lars Ellenberg4b0715f2010-12-14 15:13:04 +0100774/* input size is expected to be in KB */
Philipp Reisnerb411b362009-09-25 16:07:19 -0700775char *ppsize(char *buf, unsigned long long size)
776{
Lars Ellenberg4b0715f2010-12-14 15:13:04 +0100777 /* Needs 9 bytes at max including trailing NUL:
778 * -1ULL ==> "16384 EB" */
Philipp Reisnerb411b362009-09-25 16:07:19 -0700779 static char units[] = { 'K', 'M', 'G', 'T', 'P', 'E' };
780 int base = 0;
Lars Ellenberg4b0715f2010-12-14 15:13:04 +0100781 while (size >= 10000 && base < sizeof(units)-1) {
Philipp Reisnerb411b362009-09-25 16:07:19 -0700782 /* shift + round */
783 size = (size >> 10) + !!(size & (1<<9));
784 base++;
785 }
Lars Ellenberg4b0715f2010-12-14 15:13:04 +0100786 sprintf(buf, "%u %cB", (unsigned)size, units[base]);
Philipp Reisnerb411b362009-09-25 16:07:19 -0700787
788 return buf;
789}
790
791/* there is still a theoretical deadlock when called from receiver
792 * on an D_INCONSISTENT R_PRIMARY:
793 * remote READ does inc_ap_bio, receiver would need to receive answer
794 * packet from remote to dec_ap_bio again.
795 * receiver receive_sizes(), comes here,
796 * waits for ap_bio_cnt == 0. -> deadlock.
797 * but this cannot happen, actually, because:
798 * R_PRIMARY D_INCONSISTENT, and peer's disk is unreachable
799 * (not connected, or bad/no disk on peer):
800 * see drbd_fail_request_early, ap_bio_cnt is zero.
801 * R_PRIMARY D_INCONSISTENT, and C_SYNC_TARGET:
802 * peer may not initiate a resize.
803 */
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +0100804/* Note these are not to be confused with
805 * drbd_adm_suspend_io/drbd_adm_resume_io,
806 * which are (sub) state changes triggered by admin (drbdsetup),
807 * and can be long lived.
808 * This changes an mdev->flag, is triggered by drbd internals,
809 * and should be short-lived. */
Philipp Reisnerb411b362009-09-25 16:07:19 -0700810void drbd_suspend_io(struct drbd_conf *mdev)
811{
812 set_bit(SUSPEND_IO, &mdev->flags);
Philipp Reisner2aebfab2011-03-28 16:48:11 +0200813 if (drbd_suspended(mdev))
Philipp Reisner265be2d2010-05-31 10:14:17 +0200814 return;
Philipp Reisnerb411b362009-09-25 16:07:19 -0700815 wait_event(mdev->misc_wait, !atomic_read(&mdev->ap_bio_cnt));
816}
817
818void drbd_resume_io(struct drbd_conf *mdev)
819{
820 clear_bit(SUSPEND_IO, &mdev->flags);
821 wake_up(&mdev->misc_wait);
822}
823
824/**
825 * drbd_determine_dev_size() - Sets the right device size obeying all constraints
826 * @mdev: DRBD device.
827 *
828 * Returns 0 on success, negative return values indicate errors.
829 * You should call drbd_md_sync() after calling this function.
830 */
Philipp Reisnerd752b262013-06-25 16:50:08 +0200831enum determine_dev_size
832drbd_determine_dev_size(struct drbd_conf *mdev, enum dds_flags flags, struct resize_parms *rs) __must_hold(local)
Philipp Reisnerb411b362009-09-25 16:07:19 -0700833{
834 sector_t prev_first_sect, prev_size; /* previous meta location */
Lars Ellenbergcccac982013-03-19 18:16:46 +0100835 sector_t la_size_sect, u_size;
Philipp Reisnerd752b262013-06-25 16:50:08 +0200836 struct drbd_md *md = &mdev->ldev->md;
837 u32 prev_al_stripe_size_4k;
838 u32 prev_al_stripes;
Philipp Reisnerb411b362009-09-25 16:07:19 -0700839 sector_t size;
840 char ppb[10];
Philipp Reisnerd752b262013-06-25 16:50:08 +0200841 void *buffer;
Philipp Reisnerb411b362009-09-25 16:07:19 -0700842
843 int md_moved, la_size_changed;
Philipp Reisnere96c9632013-06-25 16:50:07 +0200844 enum determine_dev_size rv = DS_UNCHANGED;
Philipp Reisnerb411b362009-09-25 16:07:19 -0700845
846 /* race:
847 * application request passes inc_ap_bio,
848 * but then cannot get an AL-reference.
849 * this function later may wait on ap_bio_cnt == 0. -> deadlock.
850 *
851 * to avoid that:
852 * Suspend IO right here.
853 * still lock the act_log to not trigger ASSERTs there.
854 */
855 drbd_suspend_io(mdev);
Philipp Reisnerd752b262013-06-25 16:50:08 +0200856 buffer = drbd_md_get_buffer(mdev); /* Lock meta-data IO */
857 if (!buffer) {
858 drbd_resume_io(mdev);
859 return DS_ERROR;
860 }
Philipp Reisnerb411b362009-09-25 16:07:19 -0700861
862 /* no wait necessary anymore, actually we could assert that */
863 wait_event(mdev->al_wait, lc_try_lock(mdev->act_log));
864
865 prev_first_sect = drbd_md_first_sector(mdev->ldev);
866 prev_size = mdev->ldev->md.md_size_sect;
Lars Ellenbergcccac982013-03-19 18:16:46 +0100867 la_size_sect = mdev->ldev->md.la_size_sect;
Philipp Reisnerb411b362009-09-25 16:07:19 -0700868
Philipp Reisnerd752b262013-06-25 16:50:08 +0200869 if (rs) {
870 /* rs is non NULL if we should change the AL layout only */
871
872 prev_al_stripes = md->al_stripes;
873 prev_al_stripe_size_4k = md->al_stripe_size_4k;
874
875 md->al_stripes = rs->al_stripes;
876 md->al_stripe_size_4k = rs->al_stripe_size / 4;
877 md->al_size_4k = (u64)rs->al_stripes * rs->al_stripe_size / 4;
878 }
879
Philipp Reisnerb411b362009-09-25 16:07:19 -0700880 drbd_md_set_sector_offsets(mdev, mdev->ldev);
881
Philipp Reisnerdaeda1c2011-05-03 15:00:55 +0200882 rcu_read_lock();
883 u_size = rcu_dereference(mdev->ldev->disk_conf)->disk_size;
884 rcu_read_unlock();
Philipp Reisneref5e44a2011-05-03 13:27:43 +0200885 size = drbd_new_dev_size(mdev, mdev->ldev, u_size, flags & DDSF_FORCED);
Philipp Reisnerb411b362009-09-25 16:07:19 -0700886
Philipp Reisnerd752b262013-06-25 16:50:08 +0200887 if (size < la_size_sect) {
888 if (rs && u_size == 0) {
889 /* Remove "rs &&" later. This check should always be active, but
890 right now the receiver expects the permissive behavior */
891 dev_warn(DEV, "Implicit shrink not allowed. "
892 "Use --size=%llus for explicit shrink.\n",
893 (unsigned long long)size);
894 rv = DS_ERROR_SHRINK;
895 }
896 if (u_size > size)
897 rv = DS_ERROR_SPACE_MD;
898 if (rv != DS_UNCHANGED)
899 goto err_out;
900 }
901
Philipp Reisnerb411b362009-09-25 16:07:19 -0700902 if (drbd_get_capacity(mdev->this_bdev) != size ||
903 drbd_bm_capacity(mdev) != size) {
904 int err;
Philipp Reisner02d9a942010-03-24 16:23:03 +0100905 err = drbd_bm_resize(mdev, size, !(flags & DDSF_NO_RESYNC));
Philipp Reisnerb411b362009-09-25 16:07:19 -0700906 if (unlikely(err)) {
907 /* currently there is only one error: ENOMEM! */
908 size = drbd_bm_capacity(mdev)>>1;
909 if (size == 0) {
910 dev_err(DEV, "OUT OF MEMORY! "
911 "Could not allocate bitmap!\n");
912 } else {
913 dev_err(DEV, "BM resizing failed. "
914 "Leaving size unchanged at size = %lu KB\n",
915 (unsigned long)size);
916 }
Philipp Reisnere96c9632013-06-25 16:50:07 +0200917 rv = DS_ERROR;
Philipp Reisnerb411b362009-09-25 16:07:19 -0700918 }
919 /* racy, see comments above. */
920 drbd_set_my_capacity(mdev, size);
921 mdev->ldev->md.la_size_sect = size;
922 dev_info(DEV, "size = %s (%llu KB)\n", ppsize(ppb, size>>1),
923 (unsigned long long)size>>1);
924 }
Philipp Reisnerd752b262013-06-25 16:50:08 +0200925 if (rv <= DS_ERROR)
926 goto err_out;
Philipp Reisnerb411b362009-09-25 16:07:19 -0700927
Lars Ellenbergcccac982013-03-19 18:16:46 +0100928 la_size_changed = (la_size_sect != mdev->ldev->md.la_size_sect);
Philipp Reisnerb411b362009-09-25 16:07:19 -0700929
930 md_moved = prev_first_sect != drbd_md_first_sector(mdev->ldev)
931 || prev_size != mdev->ldev->md.md_size_sect;
932
Philipp Reisnerd752b262013-06-25 16:50:08 +0200933 if (la_size_changed || md_moved || rs) {
934 u32 prev_flags;
Andreas Gruenbacher24dccab2010-12-12 17:45:41 +0100935
Philipp Reisnerb411b362009-09-25 16:07:19 -0700936 drbd_al_shrink(mdev); /* All extents inactive. */
Philipp Reisnerd752b262013-06-25 16:50:08 +0200937
938 prev_flags = md->flags;
939 md->flags &= ~MDF_PRIMARY_IND;
940 drbd_md_write(mdev, buffer);
941
Philipp Reisnerb411b362009-09-25 16:07:19 -0700942 dev_info(DEV, "Writing the whole bitmap, %s\n",
943 la_size_changed && md_moved ? "size changed and md moved" :
944 la_size_changed ? "size changed" : "md moved");
Lars Ellenberg20ceb2b2011-01-21 10:56:44 +0100945 /* next line implicitly does drbd_suspend_io()+drbd_resume_io() */
Philipp Reisnerd752b262013-06-25 16:50:08 +0200946 drbd_bitmap_io(mdev, md_moved ? &drbd_bm_write_all : &drbd_bm_write,
947 "size changed", BM_LOCKED_MASK);
948 drbd_initialize_al(mdev, buffer);
949
950 md->flags = prev_flags;
951 drbd_md_write(mdev, buffer);
952
953 if (rs)
954 dev_info(DEV, "Changed AL layout to al-stripes = %d, al-stripe-size-kB = %d\n",
955 md->al_stripes, md->al_stripe_size_4k * 4);
Philipp Reisnerb411b362009-09-25 16:07:19 -0700956 }
957
Lars Ellenbergcccac982013-03-19 18:16:46 +0100958 if (size > la_size_sect)
Philipp Reisner57737ad2013-10-23 10:59:17 +0200959 rv = la_size_sect ? DS_GREW : DS_GREW_FROM_ZERO;
Lars Ellenbergcccac982013-03-19 18:16:46 +0100960 if (size < la_size_sect)
Philipp Reisnere96c9632013-06-25 16:50:07 +0200961 rv = DS_SHRUNK;
Philipp Reisnerd752b262013-06-25 16:50:08 +0200962
963 if (0) {
964 err_out:
965 if (rs) {
966 md->al_stripes = prev_al_stripes;
967 md->al_stripe_size_4k = prev_al_stripe_size_4k;
968 md->al_size_4k = (u64)prev_al_stripes * prev_al_stripe_size_4k;
969
970 drbd_md_set_sector_offsets(mdev, mdev->ldev);
971 }
972 }
Philipp Reisnerb411b362009-09-25 16:07:19 -0700973 lc_unlock(mdev->act_log);
974 wake_up(&mdev->al_wait);
Philipp Reisnerd752b262013-06-25 16:50:08 +0200975 drbd_md_put_buffer(mdev);
Philipp Reisnerb411b362009-09-25 16:07:19 -0700976 drbd_resume_io(mdev);
977
978 return rv;
979}
980
981sector_t
Philipp Reisneref5e44a2011-05-03 13:27:43 +0200982drbd_new_dev_size(struct drbd_conf *mdev, struct drbd_backing_dev *bdev,
983 sector_t u_size, int assume_peer_has_space)
Philipp Reisnerb411b362009-09-25 16:07:19 -0700984{
985 sector_t p_size = mdev->p_size; /* partner's disk size. */
Lars Ellenbergcccac982013-03-19 18:16:46 +0100986 sector_t la_size_sect = bdev->md.la_size_sect; /* last agreed size. */
Philipp Reisnerb411b362009-09-25 16:07:19 -0700987 sector_t m_size; /* my size */
Philipp Reisnerb411b362009-09-25 16:07:19 -0700988 sector_t size = 0;
989
990 m_size = drbd_get_max_capacity(bdev);
991
Philipp Reisnera393db62009-12-22 13:35:52 +0100992 if (mdev->state.conn < C_CONNECTED && assume_peer_has_space) {
993 dev_warn(DEV, "Resize while not connected was forced by the user!\n");
994 p_size = m_size;
995 }
996
Philipp Reisnerb411b362009-09-25 16:07:19 -0700997 if (p_size && m_size) {
998 size = min_t(sector_t, p_size, m_size);
999 } else {
Lars Ellenbergcccac982013-03-19 18:16:46 +01001000 if (la_size_sect) {
1001 size = la_size_sect;
Philipp Reisnerb411b362009-09-25 16:07:19 -07001002 if (m_size && m_size < size)
1003 size = m_size;
1004 if (p_size && p_size < size)
1005 size = p_size;
1006 } else {
1007 if (m_size)
1008 size = m_size;
1009 if (p_size)
1010 size = p_size;
1011 }
1012 }
1013
1014 if (size == 0)
1015 dev_err(DEV, "Both nodes diskless!\n");
1016
1017 if (u_size) {
1018 if (u_size > size)
1019 dev_err(DEV, "Requested disk size is too big (%lu > %lu)\n",
1020 (unsigned long)u_size>>1, (unsigned long)size>>1);
1021 else
1022 size = u_size;
1023 }
1024
1025 return size;
1026}
1027
1028/**
1029 * drbd_check_al_size() - Ensures that the AL is of the right size
1030 * @mdev: DRBD device.
1031 *
1032 * Returns -EBUSY if current al lru is still used, -ENOMEM when allocation
1033 * failed, and 0 on success. You should call drbd_md_sync() after you called
1034 * this function.
1035 */
Lars Ellenbergf3990022011-03-23 14:31:09 +01001036static int drbd_check_al_size(struct drbd_conf *mdev, struct disk_conf *dc)
Philipp Reisnerb411b362009-09-25 16:07:19 -07001037{
1038 struct lru_cache *n, *t;
1039 struct lc_element *e;
1040 unsigned int in_use;
1041 int i;
1042
Philipp Reisnerb411b362009-09-25 16:07:19 -07001043 if (mdev->act_log &&
Lars Ellenbergf3990022011-03-23 14:31:09 +01001044 mdev->act_log->nr_elements == dc->al_extents)
Philipp Reisnerb411b362009-09-25 16:07:19 -07001045 return 0;
1046
1047 in_use = 0;
1048 t = mdev->act_log;
Lars Ellenberg7ad651b2011-02-21 13:21:03 +01001049 n = lc_create("act_log", drbd_al_ext_cache, AL_UPDATES_PER_TRANSACTION,
Lars Ellenbergf3990022011-03-23 14:31:09 +01001050 dc->al_extents, sizeof(struct lc_element), 0);
Philipp Reisnerb411b362009-09-25 16:07:19 -07001051
1052 if (n == NULL) {
1053 dev_err(DEV, "Cannot allocate act_log lru!\n");
1054 return -ENOMEM;
1055 }
1056 spin_lock_irq(&mdev->al_lock);
1057 if (t) {
1058 for (i = 0; i < t->nr_elements; i++) {
1059 e = lc_element_by_index(t, i);
1060 if (e->refcnt)
1061 dev_err(DEV, "refcnt(%d)==%d\n",
1062 e->lc_number, e->refcnt);
1063 in_use += e->refcnt;
1064 }
1065 }
1066 if (!in_use)
1067 mdev->act_log = n;
1068 spin_unlock_irq(&mdev->al_lock);
1069 if (in_use) {
1070 dev_err(DEV, "Activity log still in use!\n");
1071 lc_destroy(n);
1072 return -EBUSY;
1073 } else {
1074 if (t)
1075 lc_destroy(t);
1076 }
1077 drbd_md_mark_dirty(mdev); /* we changed mdev->act_log->nr_elemens */
1078 return 0;
1079}
1080
Philipp Reisner99432fc2011-05-20 16:39:13 +02001081static void drbd_setup_queue_param(struct drbd_conf *mdev, unsigned int max_bio_size)
Philipp Reisnerb411b362009-09-25 16:07:19 -07001082{
1083 struct request_queue * const q = mdev->rq_queue;
Lars Ellenbergdb141b22012-06-25 19:15:58 +02001084 unsigned int max_hw_sectors = max_bio_size >> 9;
1085 unsigned int max_segments = 0;
Philipp Reisner99432fc2011-05-20 16:39:13 +02001086
1087 if (get_ldev_if_state(mdev, D_ATTACHING)) {
1088 struct request_queue * const b = mdev->ldev->backing_bdev->bd_disk->queue;
1089
1090 max_hw_sectors = min(queue_max_hw_sectors(b), max_bio_size >> 9);
Philipp Reisnerdaeda1c2011-05-03 15:00:55 +02001091 rcu_read_lock();
1092 max_segments = rcu_dereference(mdev->ldev->disk_conf)->max_bio_bvecs;
1093 rcu_read_unlock();
Philipp Reisner99432fc2011-05-20 16:39:13 +02001094 put_ldev(mdev);
1095 }
Philipp Reisnerb411b362009-09-25 16:07:19 -07001096
Philipp Reisnerb411b362009-09-25 16:07:19 -07001097 blk_queue_logical_block_size(q, 512);
Lars Ellenberg1816a2b2010-11-11 15:19:07 +01001098 blk_queue_max_hw_sectors(q, max_hw_sectors);
1099 /* This is the workaround for "bio would need to, but cannot, be split" */
1100 blk_queue_max_segments(q, max_segments ? max_segments : BLK_MAX_SEGMENTS);
1101 blk_queue_segment_boundary(q, PAGE_CACHE_SIZE-1);
Philipp Reisnerb411b362009-09-25 16:07:19 -07001102
Philipp Reisner99432fc2011-05-20 16:39:13 +02001103 if (get_ldev_if_state(mdev, D_ATTACHING)) {
1104 struct request_queue * const b = mdev->ldev->backing_bdev->bd_disk->queue;
Philipp Reisnerb411b362009-09-25 16:07:19 -07001105
Philipp Reisner99432fc2011-05-20 16:39:13 +02001106 blk_queue_stack_limits(q, b);
1107
1108 if (q->backing_dev_info.ra_pages != b->backing_dev_info.ra_pages) {
1109 dev_info(DEV, "Adjusting my ra_pages to backing device's (%lu -> %lu)\n",
1110 q->backing_dev_info.ra_pages,
1111 b->backing_dev_info.ra_pages);
1112 q->backing_dev_info.ra_pages = b->backing_dev_info.ra_pages;
1113 }
1114 put_ldev(mdev);
Philipp Reisnerb411b362009-09-25 16:07:19 -07001115 }
1116}
1117
Philipp Reisner99432fc2011-05-20 16:39:13 +02001118void drbd_reconsider_max_bio_size(struct drbd_conf *mdev)
1119{
Lars Ellenbergdb141b22012-06-25 19:15:58 +02001120 unsigned int now, new, local, peer;
Philipp Reisner99432fc2011-05-20 16:39:13 +02001121
1122 now = queue_max_hw_sectors(mdev->rq_queue) << 9;
1123 local = mdev->local_max_bio_size; /* Eventually last known value, from volatile memory */
1124 peer = mdev->peer_max_bio_size; /* Eventually last known value, from meta data */
1125
1126 if (get_ldev_if_state(mdev, D_ATTACHING)) {
1127 local = queue_max_hw_sectors(mdev->ldev->backing_bdev->bd_disk->queue) << 9;
1128 mdev->local_max_bio_size = local;
1129 put_ldev(mdev);
1130 }
Lars Ellenbergdb141b22012-06-25 19:15:58 +02001131 local = min(local, DRBD_MAX_BIO_SIZE);
Philipp Reisner99432fc2011-05-20 16:39:13 +02001132
1133 /* We may ignore peer limits if the peer is modern enough.
1134 Because new from 8.3.8 onwards the peer can use multiple
1135 BIOs for a single peer_request */
Lars Ellenberg35f47ef2013-10-23 10:59:19 +02001136 if (mdev->state.conn >= C_WF_REPORT_PARAMS) {
Philipp Reisner31890f42011-01-19 14:12:51 +01001137 if (mdev->tconn->agreed_pro_version < 94)
Lars Ellenberg35f47ef2013-10-23 10:59:19 +02001138 peer = min(mdev->peer_max_bio_size, DRBD_MAX_SIZE_H80_PACKET);
Philipp Reisner68093842011-06-30 15:43:06 +02001139 /* Correct old drbd (up to 8.3.7) if it believes it can do more than 32KiB */
Philipp Reisner31890f42011-01-19 14:12:51 +01001140 else if (mdev->tconn->agreed_pro_version == 94)
Philipp Reisner99432fc2011-05-20 16:39:13 +02001141 peer = DRBD_MAX_SIZE_H80_PACKET;
Philipp Reisner2ffca4f2011-06-30 15:43:06 +02001142 else if (mdev->tconn->agreed_pro_version < 100)
1143 peer = DRBD_MAX_BIO_SIZE_P95; /* drbd 8.3.8 onwards, before 8.4.0 */
1144 else
Philipp Reisner99432fc2011-05-20 16:39:13 +02001145 peer = DRBD_MAX_BIO_SIZE;
1146 }
1147
Lars Ellenbergdb141b22012-06-25 19:15:58 +02001148 new = min(local, peer);
Philipp Reisner99432fc2011-05-20 16:39:13 +02001149
1150 if (mdev->state.role == R_PRIMARY && new < now)
Lars Ellenbergdb141b22012-06-25 19:15:58 +02001151 dev_err(DEV, "ASSERT FAILED new < now; (%u < %u)\n", new, now);
Philipp Reisner99432fc2011-05-20 16:39:13 +02001152
1153 if (new != now)
1154 dev_info(DEV, "max BIO size = %u\n", new);
1155
1156 drbd_setup_queue_param(mdev, new);
1157}
1158
Philipp Reisnera18e9d12011-04-24 11:09:55 +02001159/* Starts the worker thread */
Philipp Reisner0e29d162011-02-18 14:23:11 +01001160static void conn_reconfig_start(struct drbd_tconn *tconn)
Philipp Reisnerb411b362009-09-25 16:07:19 -07001161{
Philipp Reisner0e29d162011-02-18 14:23:11 +01001162 drbd_thread_start(&tconn->worker);
1163 conn_flush_workqueue(tconn);
Philipp Reisnerb411b362009-09-25 16:07:19 -07001164}
1165
Philipp Reisnera18e9d12011-04-24 11:09:55 +02001166/* if still unconfigured, stops worker again. */
Philipp Reisner0e29d162011-02-18 14:23:11 +01001167static void conn_reconfig_done(struct drbd_tconn *tconn)
Philipp Reisnerb411b362009-09-25 16:07:19 -07001168{
Lars Ellenberg992d6e92011-05-02 11:47:18 +02001169 bool stop_threads;
Philipp Reisner0e29d162011-02-18 14:23:11 +01001170 spin_lock_irq(&tconn->req_lock);
Philipp Reisnere0e16652011-07-11 17:04:23 +02001171 stop_threads = conn_all_vols_unconf(tconn) &&
1172 tconn->cstate == C_STANDALONE;
Philipp Reisner0e29d162011-02-18 14:23:11 +01001173 spin_unlock_irq(&tconn->req_lock);
Lars Ellenberg992d6e92011-05-02 11:47:18 +02001174 if (stop_threads) {
1175 /* asender is implicitly stopped by receiver
Philipp Reisner81fa2e62011-05-04 15:10:30 +02001176 * in conn_disconnect() */
Lars Ellenberg992d6e92011-05-02 11:47:18 +02001177 drbd_thread_stop(&tconn->receiver);
1178 drbd_thread_stop(&tconn->worker);
1179 }
Philipp Reisnerb411b362009-09-25 16:07:19 -07001180}
1181
Philipp Reisner07782862010-08-31 12:00:50 +02001182/* Make sure IO is suspended before calling this function(). */
1183static void drbd_suspend_al(struct drbd_conf *mdev)
1184{
1185 int s = 0;
1186
Lars Ellenberg61610422011-02-21 13:20:54 +01001187 if (!lc_try_lock(mdev->act_log)) {
Philipp Reisner07782862010-08-31 12:00:50 +02001188 dev_warn(DEV, "Failed to lock al in drbd_suspend_al()\n");
1189 return;
1190 }
1191
Lars Ellenberg61610422011-02-21 13:20:54 +01001192 drbd_al_shrink(mdev);
Philipp Reisner87eeee42011-01-19 14:16:30 +01001193 spin_lock_irq(&mdev->tconn->req_lock);
Philipp Reisner07782862010-08-31 12:00:50 +02001194 if (mdev->state.conn < C_CONNECTED)
1195 s = !test_and_set_bit(AL_SUSPENDED, &mdev->flags);
Philipp Reisner87eeee42011-01-19 14:16:30 +01001196 spin_unlock_irq(&mdev->tconn->req_lock);
Lars Ellenberg61610422011-02-21 13:20:54 +01001197 lc_unlock(mdev->act_log);
Philipp Reisner07782862010-08-31 12:00:50 +02001198
1199 if (s)
1200 dev_info(DEV, "Suspended AL updates\n");
1201}
1202
Lars Ellenberg5979e362011-04-27 21:09:55 +02001203
1204static bool should_set_defaults(struct genl_info *info)
Philipp Reisnerb411b362009-09-25 16:07:19 -07001205{
Lars Ellenberg5979e362011-04-27 21:09:55 +02001206 unsigned flags = ((struct drbd_genlmsghdr*)info->userhdr)->flags;
1207 return 0 != (flags & DRBD_GENL_F_SET_DEFAULTS);
1208}
1209
Lars Ellenberg5bbcf5e2013-03-19 18:16:59 +01001210static unsigned int drbd_al_extents_max(struct drbd_backing_dev *bdev)
Philipp Reisnerd589a212011-05-04 10:06:52 +02001211{
Lars Ellenberg5bbcf5e2013-03-19 18:16:59 +01001212 /* This is limited by 16 bit "slot" numbers,
1213 * and by available on-disk context storage.
1214 *
1215 * Also (u16)~0 is special (denotes a "free" extent).
1216 *
1217 * One transaction occupies one 4kB on-disk block,
1218 * we have n such blocks in the on disk ring buffer,
1219 * the "current" transaction may fail (n-1),
1220 * and there is 919 slot numbers context information per transaction.
1221 *
1222 * 72 transaction blocks amounts to more than 2**16 context slots,
1223 * so cap there first.
1224 */
1225 const unsigned int max_al_nr = DRBD_AL_EXTENTS_MAX;
1226 const unsigned int sufficient_on_disk =
1227 (max_al_nr + AL_CONTEXT_PER_TRANSACTION -1)
1228 /AL_CONTEXT_PER_TRANSACTION;
Philipp Reisnerd589a212011-05-04 10:06:52 +02001229
Lars Ellenberg5bbcf5e2013-03-19 18:16:59 +01001230 unsigned int al_size_4k = bdev->md.al_size_4k;
1231
1232 if (al_size_4k > sufficient_on_disk)
1233 return max_al_nr;
1234
1235 return (al_size_4k - 1) * AL_CONTEXT_PER_TRANSACTION;
Philipp Reisnerd589a212011-05-04 10:06:52 +02001236}
1237
Lars Ellenbergf3990022011-03-23 14:31:09 +01001238int drbd_adm_disk_opts(struct sk_buff *skb, struct genl_info *info)
1239{
1240 enum drbd_ret_code retcode;
1241 struct drbd_conf *mdev;
Philipp Reisnerdaeda1c2011-05-03 15:00:55 +02001242 struct disk_conf *new_disk_conf, *old_disk_conf;
Philipp Reisner813472c2011-05-03 16:47:02 +02001243 struct fifo_buffer *old_plan = NULL, *new_plan = NULL;
Lars Ellenbergf3990022011-03-23 14:31:09 +01001244 int err, fifo_size;
Lars Ellenbergf3990022011-03-23 14:31:09 +01001245
1246 retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_MINOR);
1247 if (!adm_ctx.reply_skb)
1248 return retcode;
1249 if (retcode != NO_ERROR)
1250 goto out;
1251
1252 mdev = adm_ctx.mdev;
1253
1254 /* we also need a disk
1255 * to change the options on */
1256 if (!get_ldev(mdev)) {
1257 retcode = ERR_NO_DISK;
1258 goto out;
1259 }
1260
Philipp Reisnerdaeda1c2011-05-03 15:00:55 +02001261 new_disk_conf = kmalloc(sizeof(struct disk_conf), GFP_KERNEL);
Lars Ellenberg5ecc72c2011-04-27 21:14:57 +02001262 if (!new_disk_conf) {
Lars Ellenbergf3990022011-03-23 14:31:09 +01001263 retcode = ERR_NOMEM;
1264 goto fail;
1265 }
1266
Philipp Reisnerdaeda1c2011-05-03 15:00:55 +02001267 mutex_lock(&mdev->tconn->conf_update);
1268 old_disk_conf = mdev->ldev->disk_conf;
1269 *new_disk_conf = *old_disk_conf;
Lars Ellenberg5979e362011-04-27 21:09:55 +02001270 if (should_set_defaults(info))
Andreas Gruenbacherb966b5d2011-05-03 14:56:09 +02001271 set_disk_conf_defaults(new_disk_conf);
Lars Ellenberg5979e362011-04-27 21:09:55 +02001272
Lars Ellenberg5ecc72c2011-04-27 21:14:57 +02001273 err = disk_conf_from_attrs_for_change(new_disk_conf, info);
Andreas Gruenbacherc75b9b12011-05-24 14:18:31 +02001274 if (err && err != -ENOMSG) {
Lars Ellenbergf3990022011-03-23 14:31:09 +01001275 retcode = ERR_MANDATORY_TAG;
1276 drbd_msg_put_info(from_attrs_err_to_txt(err));
Philipp Reisner8e229432013-08-01 10:21:47 +02001277 goto fail_unlock;
Lars Ellenbergf3990022011-03-23 14:31:09 +01001278 }
1279
Lars Ellenberg5ecc72c2011-04-27 21:14:57 +02001280 if (!expect(new_disk_conf->resync_rate >= 1))
1281 new_disk_conf->resync_rate = 1;
Lars Ellenbergf3990022011-03-23 14:31:09 +01001282
Lars Ellenberg5bbcf5e2013-03-19 18:16:59 +01001283 if (new_disk_conf->al_extents < DRBD_AL_EXTENTS_MIN)
1284 new_disk_conf->al_extents = DRBD_AL_EXTENTS_MIN;
1285 if (new_disk_conf->al_extents > drbd_al_extents_max(mdev->ldev))
1286 new_disk_conf->al_extents = drbd_al_extents_max(mdev->ldev);
1287
1288 if (new_disk_conf->c_plan_ahead > DRBD_C_PLAN_AHEAD_MAX)
1289 new_disk_conf->c_plan_ahead = DRBD_C_PLAN_AHEAD_MAX;
Lars Ellenbergf3990022011-03-23 14:31:09 +01001290
Lars Ellenberg5ecc72c2011-04-27 21:14:57 +02001291 fifo_size = (new_disk_conf->c_plan_ahead * 10 * SLEEP_TIME) / HZ;
Philipp Reisner9958c852011-05-03 16:19:31 +02001292 if (fifo_size != mdev->rs_plan_s->size) {
Philipp Reisner813472c2011-05-03 16:47:02 +02001293 new_plan = fifo_alloc(fifo_size);
1294 if (!new_plan) {
Lars Ellenbergf3990022011-03-23 14:31:09 +01001295 dev_err(DEV, "kmalloc of fifo_buffer failed");
1296 retcode = ERR_NOMEM;
Philipp Reisnerdaeda1c2011-05-03 15:00:55 +02001297 goto fail_unlock;
Lars Ellenbergf3990022011-03-23 14:31:09 +01001298 }
1299 }
1300
Lars Ellenberg0ee98e22012-08-20 14:54:48 +02001301 drbd_suspend_io(mdev);
Lars Ellenbergf3990022011-03-23 14:31:09 +01001302 wait_event(mdev->al_wait, lc_try_lock(mdev->act_log));
1303 drbd_al_shrink(mdev);
Lars Ellenberg5ecc72c2011-04-27 21:14:57 +02001304 err = drbd_check_al_size(mdev, new_disk_conf);
Lars Ellenbergf3990022011-03-23 14:31:09 +01001305 lc_unlock(mdev->act_log);
1306 wake_up(&mdev->al_wait);
Lars Ellenberg0ee98e22012-08-20 14:54:48 +02001307 drbd_resume_io(mdev);
Lars Ellenbergf3990022011-03-23 14:31:09 +01001308
1309 if (err) {
1310 retcode = ERR_NOMEM;
Philipp Reisnerdaeda1c2011-05-03 15:00:55 +02001311 goto fail_unlock;
Lars Ellenbergf3990022011-03-23 14:31:09 +01001312 }
1313
Philipp Reisnerdc97b702011-05-03 14:27:15 +02001314 write_lock_irq(&global_state_lock);
Andreas Gruenbacher95f8efd2011-05-12 11:15:34 +02001315 retcode = drbd_resync_after_valid(mdev, new_disk_conf->resync_after);
Philipp Reisnerdc97b702011-05-03 14:27:15 +02001316 if (retcode == NO_ERROR) {
Philipp Reisnerdaeda1c2011-05-03 15:00:55 +02001317 rcu_assign_pointer(mdev->ldev->disk_conf, new_disk_conf);
Andreas Gruenbacher95f8efd2011-05-12 11:15:34 +02001318 drbd_resync_after_changed(mdev);
Philipp Reisnerdc97b702011-05-03 14:27:15 +02001319 }
1320 write_unlock_irq(&global_state_lock);
Lars Ellenbergf3990022011-03-23 14:31:09 +01001321
Philipp Reisnerdaeda1c2011-05-03 15:00:55 +02001322 if (retcode != NO_ERROR)
1323 goto fail_unlock;
Lars Ellenbergf3990022011-03-23 14:31:09 +01001324
Philipp Reisner813472c2011-05-03 16:47:02 +02001325 if (new_plan) {
1326 old_plan = mdev->rs_plan_s;
1327 rcu_assign_pointer(mdev->rs_plan_s, new_plan);
Philipp Reisner9958c852011-05-03 16:19:31 +02001328 }
Philipp Reisner9958c852011-05-03 16:19:31 +02001329
Philipp Reisnerc141ebd2011-05-05 16:13:10 +02001330 mutex_unlock(&mdev->tconn->conf_update);
Philipp Reisner27eb13e2012-03-30 14:12:15 +02001331
Philipp Reisner9a51ab12012-02-20 21:53:28 +01001332 if (new_disk_conf->al_updates)
Philipp Reisner4035e4c2012-10-01 18:04:12 +02001333 mdev->ldev->md.flags &= ~MDF_AL_DISABLED;
Philipp Reisner9a51ab12012-02-20 21:53:28 +01001334 else
1335 mdev->ldev->md.flags |= MDF_AL_DISABLED;
1336
Lars Ellenberg691631c2012-10-26 00:41:50 +02001337 if (new_disk_conf->md_flushes)
1338 clear_bit(MD_NO_FUA, &mdev->flags);
1339 else
1340 set_bit(MD_NO_FUA, &mdev->flags);
1341
Philipp Reisner27eb13e2012-03-30 14:12:15 +02001342 drbd_bump_write_ordering(mdev->tconn, WO_bdev_flush);
1343
Philipp Reisnerdaeda1c2011-05-03 15:00:55 +02001344 drbd_md_sync(mdev);
Lars Ellenbergf3990022011-03-23 14:31:09 +01001345
1346 if (mdev->state.conn >= C_CONNECTED)
1347 drbd_send_sync_param(mdev);
1348
Philipp Reisnerdaeda1c2011-05-03 15:00:55 +02001349 synchronize_rcu();
1350 kfree(old_disk_conf);
Philipp Reisner813472c2011-05-03 16:47:02 +02001351 kfree(old_plan);
Philipp Reisnercdfda632011-07-05 15:38:59 +02001352 mod_timer(&mdev->request_timer, jiffies + HZ);
Philipp Reisnerdaeda1c2011-05-03 15:00:55 +02001353 goto success;
1354
1355fail_unlock:
1356 mutex_unlock(&mdev->tconn->conf_update);
Lars Ellenbergf3990022011-03-23 14:31:09 +01001357 fail:
Lars Ellenberg5ecc72c2011-04-27 21:14:57 +02001358 kfree(new_disk_conf);
Philipp Reisner813472c2011-05-03 16:47:02 +02001359 kfree(new_plan);
Philipp Reisnerdaeda1c2011-05-03 15:00:55 +02001360success:
1361 put_ldev(mdev);
Lars Ellenbergf3990022011-03-23 14:31:09 +01001362 out:
1363 drbd_adm_finish(info, retcode);
1364 return 0;
1365}
1366
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01001367int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
Philipp Reisnerb411b362009-09-25 16:07:19 -07001368{
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01001369 struct drbd_conf *mdev;
1370 int err;
Andreas Gruenbacher116676c2010-12-08 13:33:11 +01001371 enum drbd_ret_code retcode;
Philipp Reisnerb411b362009-09-25 16:07:19 -07001372 enum determine_dev_size dd;
1373 sector_t max_possible_sectors;
1374 sector_t min_md_device_sectors;
1375 struct drbd_backing_dev *nbc = NULL; /* new_backing_conf */
Philipp Reisnerdaeda1c2011-05-03 15:00:55 +02001376 struct disk_conf *new_disk_conf = NULL;
Tejun Heoe525fd82010-11-13 11:55:17 +01001377 struct block_device *bdev;
Philipp Reisnerb411b362009-09-25 16:07:19 -07001378 struct lru_cache *resync_lru = NULL;
Philipp Reisner9958c852011-05-03 16:19:31 +02001379 struct fifo_buffer *new_plan = NULL;
Philipp Reisnerb411b362009-09-25 16:07:19 -07001380 union drbd_state ns, os;
Andreas Gruenbacherf2024e72010-12-10 13:44:05 +01001381 enum drbd_state_rv rv;
Philipp Reisner44ed1672011-04-19 17:10:19 +02001382 struct net_conf *nc;
Philipp Reisnerb411b362009-09-25 16:07:19 -07001383
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01001384 retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_MINOR);
1385 if (!adm_ctx.reply_skb)
1386 return retcode;
1387 if (retcode != NO_ERROR)
Lars Ellenberg40cbf082011-03-16 16:52:10 +01001388 goto finish;
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01001389
1390 mdev = adm_ctx.mdev;
Philipp Reisner0e29d162011-02-18 14:23:11 +01001391 conn_reconfig_start(mdev->tconn);
Philipp Reisnerb411b362009-09-25 16:07:19 -07001392
1393 /* if you want to reconfigure, please tear down first */
1394 if (mdev->state.disk > D_DISKLESS) {
1395 retcode = ERR_DISK_CONFIGURED;
1396 goto fail;
1397 }
Lars Ellenberg82f59cc2010-10-16 12:13:47 +02001398 /* It may just now have detached because of IO error. Make sure
1399 * drbd_ldev_destroy is done already, we may end up here very fast,
1400 * e.g. if someone calls attach from the on-io-error handler,
1401 * to realize a "hot spare" feature (not that I'd recommend that) */
1402 wait_event(mdev->misc_wait, !atomic_read(&mdev->local_cnt));
Philipp Reisnerb411b362009-09-25 16:07:19 -07001403
Lars Ellenberg383606e2012-06-14 14:21:32 +02001404 /* make sure there is no leftover from previous force-detach attempts */
Lars Ellenberg0c849662012-07-30 09:07:28 +02001405 clear_bit(FORCE_DETACH, &mdev->flags);
Lars Ellenbergedc9f5e2012-09-27 15:18:21 +02001406 clear_bit(WAS_IO_ERROR, &mdev->flags);
1407 clear_bit(WAS_READ_ERROR, &mdev->flags);
Lars Ellenberg383606e2012-06-14 14:21:32 +02001408
Lars Ellenberg0029d622012-06-14 18:02:52 +02001409 /* and no leftover from previously aborted resync or verify, either */
1410 mdev->rs_total = 0;
1411 mdev->rs_failed = 0;
1412 atomic_set(&mdev->rs_pending_cnt, 0);
1413
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01001414 /* allocation not in the IO path, drbdsetup context */
Philipp Reisnerb411b362009-09-25 16:07:19 -07001415 nbc = kzalloc(sizeof(struct drbd_backing_dev), GFP_KERNEL);
1416 if (!nbc) {
1417 retcode = ERR_NOMEM;
1418 goto fail;
1419 }
Philipp Reisner9f2247b2012-08-16 14:25:58 +02001420 spin_lock_init(&nbc->md.uuid_lock);
1421
Philipp Reisnerdaeda1c2011-05-03 15:00:55 +02001422 new_disk_conf = kzalloc(sizeof(struct disk_conf), GFP_KERNEL);
1423 if (!new_disk_conf) {
1424 retcode = ERR_NOMEM;
1425 goto fail;
1426 }
1427 nbc->disk_conf = new_disk_conf;
Philipp Reisnerb411b362009-09-25 16:07:19 -07001428
Philipp Reisnerdaeda1c2011-05-03 15:00:55 +02001429 set_disk_conf_defaults(new_disk_conf);
1430 err = disk_conf_from_attrs(new_disk_conf, info);
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01001431 if (err) {
Philipp Reisnerb411b362009-09-25 16:07:19 -07001432 retcode = ERR_MANDATORY_TAG;
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01001433 drbd_msg_put_info(from_attrs_err_to_txt(err));
Philipp Reisnerb411b362009-09-25 16:07:19 -07001434 goto fail;
1435 }
1436
Lars Ellenberg5bbcf5e2013-03-19 18:16:59 +01001437 if (new_disk_conf->c_plan_ahead > DRBD_C_PLAN_AHEAD_MAX)
1438 new_disk_conf->c_plan_ahead = DRBD_C_PLAN_AHEAD_MAX;
Philipp Reisnerd589a212011-05-04 10:06:52 +02001439
Philipp Reisner9958c852011-05-03 16:19:31 +02001440 new_plan = fifo_alloc((new_disk_conf->c_plan_ahead * 10 * SLEEP_TIME) / HZ);
1441 if (!new_plan) {
1442 retcode = ERR_NOMEM;
1443 goto fail;
1444 }
1445
Philipp Reisnerdaeda1c2011-05-03 15:00:55 +02001446 if (new_disk_conf->meta_dev_idx < DRBD_MD_INDEX_FLEX_INT) {
Philipp Reisnerb411b362009-09-25 16:07:19 -07001447 retcode = ERR_MD_IDX_INVALID;
1448 goto fail;
1449 }
1450
Lars Ellenberga3f8f7d2013-03-27 14:08:43 +01001451 write_lock_irq(&global_state_lock);
1452 retcode = drbd_resync_after_valid(mdev, new_disk_conf->resync_after);
1453 write_unlock_irq(&global_state_lock);
1454 if (retcode != NO_ERROR)
1455 goto fail;
1456
Philipp Reisner44ed1672011-04-19 17:10:19 +02001457 rcu_read_lock();
1458 nc = rcu_dereference(mdev->tconn->net_conf);
1459 if (nc) {
Philipp Reisnerdaeda1c2011-05-03 15:00:55 +02001460 if (new_disk_conf->fencing == FP_STONITH && nc->wire_protocol == DRBD_PROT_A) {
Philipp Reisner44ed1672011-04-19 17:10:19 +02001461 rcu_read_unlock();
Philipp Reisner47ff2d02010-06-18 13:56:57 +02001462 retcode = ERR_STONITH_AND_PROT_A;
1463 goto fail;
1464 }
1465 }
Philipp Reisner44ed1672011-04-19 17:10:19 +02001466 rcu_read_unlock();
Philipp Reisner47ff2d02010-06-18 13:56:57 +02001467
Philipp Reisnerdaeda1c2011-05-03 15:00:55 +02001468 bdev = blkdev_get_by_path(new_disk_conf->backing_dev,
Tejun Heod4d77622010-11-13 11:55:18 +01001469 FMODE_READ | FMODE_WRITE | FMODE_EXCL, mdev);
Tejun Heoe525fd82010-11-13 11:55:17 +01001470 if (IS_ERR(bdev)) {
Philipp Reisnerdaeda1c2011-05-03 15:00:55 +02001471 dev_err(DEV, "open(\"%s\") failed with %ld\n", new_disk_conf->backing_dev,
Tejun Heoe525fd82010-11-13 11:55:17 +01001472 PTR_ERR(bdev));
Philipp Reisnerb411b362009-09-25 16:07:19 -07001473 retcode = ERR_OPEN_DISK;
1474 goto fail;
1475 }
Tejun Heoe525fd82010-11-13 11:55:17 +01001476 nbc->backing_bdev = bdev;
Philipp Reisnerb411b362009-09-25 16:07:19 -07001477
Tejun Heoe525fd82010-11-13 11:55:17 +01001478 /*
1479 * meta_dev_idx >= 0: external fixed size, possibly multiple
1480 * drbd sharing one meta device. TODO in that case, paranoia
1481 * check that [md_bdev, meta_dev_idx] is not yet used by some
1482 * other drbd minor! (if you use drbd.conf + drbdadm, that
1483 * should check it for you already; but if you don't, or
1484 * someone fooled it, we need to double check here)
1485 */
Philipp Reisnerdaeda1c2011-05-03 15:00:55 +02001486 bdev = blkdev_get_by_path(new_disk_conf->meta_dev,
Tejun Heod4d77622010-11-13 11:55:18 +01001487 FMODE_READ | FMODE_WRITE | FMODE_EXCL,
Philipp Reisnerdaeda1c2011-05-03 15:00:55 +02001488 (new_disk_conf->meta_dev_idx < 0) ?
Tejun Heod4d77622010-11-13 11:55:18 +01001489 (void *)mdev : (void *)drbd_m_holder);
Tejun Heoe525fd82010-11-13 11:55:17 +01001490 if (IS_ERR(bdev)) {
Philipp Reisnerdaeda1c2011-05-03 15:00:55 +02001491 dev_err(DEV, "open(\"%s\") failed with %ld\n", new_disk_conf->meta_dev,
Tejun Heoe525fd82010-11-13 11:55:17 +01001492 PTR_ERR(bdev));
Philipp Reisnerb411b362009-09-25 16:07:19 -07001493 retcode = ERR_OPEN_MD_DISK;
1494 goto fail;
1495 }
Tejun Heoe525fd82010-11-13 11:55:17 +01001496 nbc->md_bdev = bdev;
Philipp Reisnerb411b362009-09-25 16:07:19 -07001497
Tejun Heoe525fd82010-11-13 11:55:17 +01001498 if ((nbc->backing_bdev == nbc->md_bdev) !=
Philipp Reisnerdaeda1c2011-05-03 15:00:55 +02001499 (new_disk_conf->meta_dev_idx == DRBD_MD_INDEX_INTERNAL ||
1500 new_disk_conf->meta_dev_idx == DRBD_MD_INDEX_FLEX_INT)) {
Tejun Heoe525fd82010-11-13 11:55:17 +01001501 retcode = ERR_MD_IDX_INVALID;
Philipp Reisnerb411b362009-09-25 16:07:19 -07001502 goto fail;
1503 }
1504
1505 resync_lru = lc_create("resync", drbd_bm_ext_cache,
Lars Ellenberg46a15bc2011-02-21 13:21:01 +01001506 1, 61, sizeof(struct bm_extent),
Philipp Reisnerb411b362009-09-25 16:07:19 -07001507 offsetof(struct bm_extent, lce));
1508 if (!resync_lru) {
1509 retcode = ERR_NOMEM;
Tejun Heoe525fd82010-11-13 11:55:17 +01001510 goto fail;
Philipp Reisnerb411b362009-09-25 16:07:19 -07001511 }
1512
Lars Ellenbergc04ccaa2013-03-19 18:16:47 +01001513 /* Read our meta data super block early.
1514 * This also sets other on-disk offsets. */
1515 retcode = drbd_md_read(mdev, nbc);
1516 if (retcode != NO_ERROR)
1517 goto fail;
Philipp Reisnerb411b362009-09-25 16:07:19 -07001518
Lars Ellenberg5bbcf5e2013-03-19 18:16:59 +01001519 if (new_disk_conf->al_extents < DRBD_AL_EXTENTS_MIN)
1520 new_disk_conf->al_extents = DRBD_AL_EXTENTS_MIN;
1521 if (new_disk_conf->al_extents > drbd_al_extents_max(nbc))
1522 new_disk_conf->al_extents = drbd_al_extents_max(nbc);
1523
Philipp Reisnerdaeda1c2011-05-03 15:00:55 +02001524 if (drbd_get_max_capacity(nbc) < new_disk_conf->disk_size) {
Philipp Reisnerb411b362009-09-25 16:07:19 -07001525 dev_err(DEV, "max capacity %llu smaller than disk size %llu\n",
1526 (unsigned long long) drbd_get_max_capacity(nbc),
Philipp Reisnerdaeda1c2011-05-03 15:00:55 +02001527 (unsigned long long) new_disk_conf->disk_size);
Lars Ellenberg7948bcd2011-06-06 15:36:04 +02001528 retcode = ERR_DISK_TOO_SMALL;
Tejun Heoe525fd82010-11-13 11:55:17 +01001529 goto fail;
Philipp Reisnerb411b362009-09-25 16:07:19 -07001530 }
1531
Philipp Reisnerdaeda1c2011-05-03 15:00:55 +02001532 if (new_disk_conf->meta_dev_idx < 0) {
Philipp Reisnerb411b362009-09-25 16:07:19 -07001533 max_possible_sectors = DRBD_MAX_SECTORS_FLEX;
1534 /* at least one MB, otherwise it does not make sense */
1535 min_md_device_sectors = (2<<10);
1536 } else {
1537 max_possible_sectors = DRBD_MAX_SECTORS;
Lars Ellenbergae8bf312013-03-19 18:16:43 +01001538 min_md_device_sectors = MD_128MB_SECT * (new_disk_conf->meta_dev_idx + 1);
Philipp Reisnerb411b362009-09-25 16:07:19 -07001539 }
1540
Philipp Reisnerb411b362009-09-25 16:07:19 -07001541 if (drbd_get_capacity(nbc->md_bdev) < min_md_device_sectors) {
Lars Ellenberg7948bcd2011-06-06 15:36:04 +02001542 retcode = ERR_MD_DISK_TOO_SMALL;
Philipp Reisnerb411b362009-09-25 16:07:19 -07001543 dev_warn(DEV, "refusing attach: md-device too small, "
1544 "at least %llu sectors needed for this meta-disk type\n",
1545 (unsigned long long) min_md_device_sectors);
Tejun Heoe525fd82010-11-13 11:55:17 +01001546 goto fail;
Philipp Reisnerb411b362009-09-25 16:07:19 -07001547 }
1548
1549 /* Make sure the new disk is big enough
1550 * (we may currently be R_PRIMARY with no local disk...) */
1551 if (drbd_get_max_capacity(nbc) <
1552 drbd_get_capacity(mdev->this_bdev)) {
Lars Ellenberg7948bcd2011-06-06 15:36:04 +02001553 retcode = ERR_DISK_TOO_SMALL;
Tejun Heoe525fd82010-11-13 11:55:17 +01001554 goto fail;
Philipp Reisnerb411b362009-09-25 16:07:19 -07001555 }
1556
1557 nbc->known_size = drbd_get_capacity(nbc->backing_bdev);
1558
Lars Ellenberg13529942009-10-12 19:07:49 +02001559 if (nbc->known_size > max_possible_sectors) {
1560 dev_warn(DEV, "==> truncating very big lower level device "
1561 "to currently maximum possible %llu sectors <==\n",
1562 (unsigned long long) max_possible_sectors);
Philipp Reisnerdaeda1c2011-05-03 15:00:55 +02001563 if (new_disk_conf->meta_dev_idx >= 0)
Lars Ellenberg13529942009-10-12 19:07:49 +02001564 dev_warn(DEV, "==>> using internal or flexible "
1565 "meta data may help <<==\n");
1566 }
1567
Philipp Reisnerb411b362009-09-25 16:07:19 -07001568 drbd_suspend_io(mdev);
1569 /* also wait for the last barrier ack. */
Lars Ellenbergb6dd1a82011-11-28 15:04:49 +01001570 /* FIXME see also https://daiquiri.linbit/cgi-bin/bugzilla/show_bug.cgi?id=171
1571 * We need a way to either ignore barrier acks for barriers sent before a device
1572 * was attached, or a way to wait for all pending barrier acks to come in.
1573 * As barriers are counted per resource,
1574 * we'd need to suspend io on all devices of a resource.
1575 */
Philipp Reisner2aebfab2011-03-28 16:48:11 +02001576 wait_event(mdev->misc_wait, !atomic_read(&mdev->ap_pending_cnt) || drbd_suspended(mdev));
Philipp Reisnerb411b362009-09-25 16:07:19 -07001577 /* and for any other previously queued work */
1578 drbd_flush_workqueue(mdev);
1579
Andreas Gruenbacherf2024e72010-12-10 13:44:05 +01001580 rv = _drbd_request_state(mdev, NS(disk, D_ATTACHING), CS_VERBOSE);
1581 retcode = rv; /* FIXME: Type mismatch. */
Philipp Reisnerb411b362009-09-25 16:07:19 -07001582 drbd_resume_io(mdev);
Andreas Gruenbacherf2024e72010-12-10 13:44:05 +01001583 if (rv < SS_SUCCESS)
Tejun Heoe525fd82010-11-13 11:55:17 +01001584 goto fail;
Philipp Reisnerb411b362009-09-25 16:07:19 -07001585
1586 if (!get_ldev_if_state(mdev, D_ATTACHING))
1587 goto force_diskless;
1588
Philipp Reisnerb411b362009-09-25 16:07:19 -07001589 if (!mdev->bitmap) {
1590 if (drbd_bm_init(mdev)) {
1591 retcode = ERR_NOMEM;
1592 goto force_diskless_dec;
1593 }
1594 }
1595
Philipp Reisnerb411b362009-09-25 16:07:19 -07001596 if (mdev->state.conn < C_CONNECTED &&
1597 mdev->state.role == R_PRIMARY &&
1598 (mdev->ed_uuid & ~((u64)1)) != (nbc->md.uuid[UI_CURRENT] & ~((u64)1))) {
1599 dev_err(DEV, "Can only attach to data with current UUID=%016llX\n",
1600 (unsigned long long)mdev->ed_uuid);
1601 retcode = ERR_DATA_NOT_CURRENT;
1602 goto force_diskless_dec;
1603 }
1604
1605 /* Since we are diskless, fix the activity log first... */
Philipp Reisnerdaeda1c2011-05-03 15:00:55 +02001606 if (drbd_check_al_size(mdev, new_disk_conf)) {
Philipp Reisnerb411b362009-09-25 16:07:19 -07001607 retcode = ERR_NOMEM;
1608 goto force_diskless_dec;
1609 }
1610
1611 /* Prevent shrinking of consistent devices ! */
1612 if (drbd_md_test_flag(nbc, MDF_CONSISTENT) &&
Philipp Reisnerdaeda1c2011-05-03 15:00:55 +02001613 drbd_new_dev_size(mdev, nbc, nbc->disk_conf->disk_size, 0) < nbc->md.la_size_sect) {
Philipp Reisnerb411b362009-09-25 16:07:19 -07001614 dev_warn(DEV, "refusing to truncate a consistent device\n");
Lars Ellenberg7948bcd2011-06-06 15:36:04 +02001615 retcode = ERR_DISK_TOO_SMALL;
Philipp Reisnerb411b362009-09-25 16:07:19 -07001616 goto force_diskless_dec;
1617 }
1618
Philipp Reisnerb411b362009-09-25 16:07:19 -07001619 /* Reset the "barriers don't work" bits here, then force meta data to
1620 * be written, to ensure we determine if barriers are supported. */
Andreas Gruenbachere5440462011-05-04 15:25:35 +02001621 if (new_disk_conf->md_flushes)
Philipp Reisnera8a4e512010-08-25 10:21:04 +02001622 clear_bit(MD_NO_FUA, &mdev->flags);
Philipp Reisnerb411b362009-09-25 16:07:19 -07001623 else
Andreas Gruenbachere5440462011-05-04 15:25:35 +02001624 set_bit(MD_NO_FUA, &mdev->flags);
Philipp Reisnerb411b362009-09-25 16:07:19 -07001625
1626 /* Point of no return reached.
1627 * Devices and memory are no longer released by error cleanup below.
1628 * now mdev takes over responsibility, and the state engine should
1629 * clean it up somewhere. */
1630 D_ASSERT(mdev->ldev == NULL);
1631 mdev->ldev = nbc;
1632 mdev->resync = resync_lru;
Philipp Reisner9958c852011-05-03 16:19:31 +02001633 mdev->rs_plan_s = new_plan;
Philipp Reisnerb411b362009-09-25 16:07:19 -07001634 nbc = NULL;
1635 resync_lru = NULL;
Philipp Reisnerdaeda1c2011-05-03 15:00:55 +02001636 new_disk_conf = NULL;
Philipp Reisner9958c852011-05-03 16:19:31 +02001637 new_plan = NULL;
Philipp Reisnerb411b362009-09-25 16:07:19 -07001638
Philipp Reisner4b0007c2011-11-09 20:12:34 +01001639 drbd_bump_write_ordering(mdev->tconn, WO_bdev_flush);
Philipp Reisnerb411b362009-09-25 16:07:19 -07001640
1641 if (drbd_md_test_flag(mdev->ldev, MDF_CRASHED_PRIMARY))
1642 set_bit(CRASHED_PRIMARY, &mdev->flags);
1643 else
1644 clear_bit(CRASHED_PRIMARY, &mdev->flags);
1645
Philipp Reisner894c6a92010-06-18 16:03:20 +02001646 if (drbd_md_test_flag(mdev->ldev, MDF_PRIMARY_IND) &&
Lars Ellenbergd5d7ebd2011-07-05 20:59:26 +02001647 !(mdev->state.role == R_PRIMARY && mdev->tconn->susp_nod))
Philipp Reisnerb411b362009-09-25 16:07:19 -07001648 set_bit(CRASHED_PRIMARY, &mdev->flags);
Philipp Reisnerb411b362009-09-25 16:07:19 -07001649
1650 mdev->send_cnt = 0;
1651 mdev->recv_cnt = 0;
1652 mdev->read_cnt = 0;
1653 mdev->writ_cnt = 0;
1654
Philipp Reisner99432fc2011-05-20 16:39:13 +02001655 drbd_reconsider_max_bio_size(mdev);
Philipp Reisnerb411b362009-09-25 16:07:19 -07001656
1657 /* If I am currently not R_PRIMARY,
1658 * but meta data primary indicator is set,
1659 * I just now recover from a hard crash,
1660 * and have been R_PRIMARY before that crash.
1661 *
1662 * Now, if I had no connection before that crash
1663 * (have been degraded R_PRIMARY), chances are that
1664 * I won't find my peer now either.
1665 *
1666 * In that case, and _only_ in that case,
1667 * we use the degr-wfc-timeout instead of the default,
1668 * so we can automatically recover from a crash of a
1669 * degraded but active "cluster" after a certain timeout.
1670 */
1671 clear_bit(USE_DEGR_WFC_T, &mdev->flags);
1672 if (mdev->state.role != R_PRIMARY &&
1673 drbd_md_test_flag(mdev->ldev, MDF_PRIMARY_IND) &&
1674 !drbd_md_test_flag(mdev->ldev, MDF_CONNECTED_IND))
1675 set_bit(USE_DEGR_WFC_T, &mdev->flags);
1676
Philipp Reisnerd752b262013-06-25 16:50:08 +02001677 dd = drbd_determine_dev_size(mdev, 0, NULL);
1678 if (dd <= DS_ERROR) {
Philipp Reisnerb411b362009-09-25 16:07:19 -07001679 retcode = ERR_NOMEM_BITMAP;
1680 goto force_diskless_dec;
Philipp Reisnere96c9632013-06-25 16:50:07 +02001681 } else if (dd == DS_GREW)
Philipp Reisnerb411b362009-09-25 16:07:19 -07001682 set_bit(RESYNC_AFTER_NEG, &mdev->flags);
1683
Philipp Reisner9a51ab12012-02-20 21:53:28 +01001684 if (drbd_md_test_flag(mdev->ldev, MDF_FULL_SYNC) ||
1685 (test_bit(CRASHED_PRIMARY, &mdev->flags) &&
1686 drbd_md_test_flag(mdev->ldev, MDF_AL_DISABLED))) {
Philipp Reisnerb411b362009-09-25 16:07:19 -07001687 dev_info(DEV, "Assuming that all blocks are out of sync "
1688 "(aka FullSync)\n");
Lars Ellenberg20ceb2b2011-01-21 10:56:44 +01001689 if (drbd_bitmap_io(mdev, &drbd_bmio_set_n_write,
1690 "set_n_write from attaching", BM_LOCKED_MASK)) {
Philipp Reisnerb411b362009-09-25 16:07:19 -07001691 retcode = ERR_IO_MD_DISK;
1692 goto force_diskless_dec;
1693 }
1694 } else {
Lars Ellenberg20ceb2b2011-01-21 10:56:44 +01001695 if (drbd_bitmap_io(mdev, &drbd_bm_read,
Andreas Gruenbacher22ab6a32010-12-13 01:44:11 +01001696 "read from attaching", BM_LOCKED_MASK)) {
Lars Ellenberg19f843a2010-12-15 08:59:11 +01001697 retcode = ERR_IO_MD_DISK;
1698 goto force_diskless_dec;
1699 }
Philipp Reisnerb411b362009-09-25 16:07:19 -07001700 }
1701
Philipp Reisner07782862010-08-31 12:00:50 +02001702 if (_drbd_bm_total_weight(mdev) == drbd_bm_bits(mdev))
1703 drbd_suspend_al(mdev); /* IO is still suspended here... */
1704
Philipp Reisner87eeee42011-01-19 14:16:30 +01001705 spin_lock_irq(&mdev->tconn->req_lock);
Philipp Reisner78bae592011-03-28 15:40:12 +02001706 os = drbd_read_state(mdev);
1707 ns = os;
Philipp Reisnerb411b362009-09-25 16:07:19 -07001708 /* If MDF_CONSISTENT is not set go into inconsistent state,
1709 otherwise investigate MDF_WasUpToDate...
1710 If MDF_WAS_UP_TO_DATE is not set go into D_OUTDATED disk state,
1711 otherwise into D_CONSISTENT state.
1712 */
1713 if (drbd_md_test_flag(mdev->ldev, MDF_CONSISTENT)) {
1714 if (drbd_md_test_flag(mdev->ldev, MDF_WAS_UP_TO_DATE))
1715 ns.disk = D_CONSISTENT;
1716 else
1717 ns.disk = D_OUTDATED;
1718 } else {
1719 ns.disk = D_INCONSISTENT;
1720 }
1721
1722 if (drbd_md_test_flag(mdev->ldev, MDF_PEER_OUT_DATED))
1723 ns.pdsk = D_OUTDATED;
1724
Philipp Reisnerdaeda1c2011-05-03 15:00:55 +02001725 rcu_read_lock();
1726 if (ns.disk == D_CONSISTENT &&
1727 (ns.pdsk == D_OUTDATED || rcu_dereference(mdev->ldev->disk_conf)->fencing == FP_DONT_CARE))
Philipp Reisnerb411b362009-09-25 16:07:19 -07001728 ns.disk = D_UP_TO_DATE;
1729
1730 /* All tests on MDF_PRIMARY_IND, MDF_CONNECTED_IND,
1731 MDF_CONSISTENT and MDF_WAS_UP_TO_DATE must happen before
1732 this point, because drbd_request_state() modifies these
1733 flags. */
1734
Philipp Reisner9a51ab12012-02-20 21:53:28 +01001735 if (rcu_dereference(mdev->ldev->disk_conf)->al_updates)
Philipp Reisner4035e4c2012-10-01 18:04:12 +02001736 mdev->ldev->md.flags &= ~MDF_AL_DISABLED;
Philipp Reisner9a51ab12012-02-20 21:53:28 +01001737 else
1738 mdev->ldev->md.flags |= MDF_AL_DISABLED;
1739
1740 rcu_read_unlock();
1741
Philipp Reisnerb411b362009-09-25 16:07:19 -07001742 /* In case we are C_CONNECTED postpone any decision on the new disk
1743 state after the negotiation phase. */
1744 if (mdev->state.conn == C_CONNECTED) {
1745 mdev->new_state_tmp.i = ns.i;
1746 ns.i = os.i;
1747 ns.disk = D_NEGOTIATING;
Philipp Reisnerdc66c742010-06-02 14:31:29 +02001748
1749 /* We expect to receive up-to-date UUIDs soon.
1750 To avoid a race in receive_state, free p_uuid while
1751 holding req_lock. I.e. atomic with the state change */
1752 kfree(mdev->p_uuid);
1753 mdev->p_uuid = NULL;
Philipp Reisnerb411b362009-09-25 16:07:19 -07001754 }
1755
1756 rv = _drbd_set_state(mdev, ns, CS_VERBOSE, NULL);
Philipp Reisner87eeee42011-01-19 14:16:30 +01001757 spin_unlock_irq(&mdev->tconn->req_lock);
Philipp Reisnerb411b362009-09-25 16:07:19 -07001758
1759 if (rv < SS_SUCCESS)
1760 goto force_diskless_dec;
1761
Philipp Reisnercdfda632011-07-05 15:38:59 +02001762 mod_timer(&mdev->request_timer, jiffies + HZ);
1763
Philipp Reisnerb411b362009-09-25 16:07:19 -07001764 if (mdev->state.role == R_PRIMARY)
1765 mdev->ldev->md.uuid[UI_CURRENT] |= (u64)1;
1766 else
1767 mdev->ldev->md.uuid[UI_CURRENT] &= ~(u64)1;
1768
1769 drbd_md_mark_dirty(mdev);
1770 drbd_md_sync(mdev);
1771
1772 kobject_uevent(&disk_to_dev(mdev->vdisk)->kobj, KOBJ_CHANGE);
1773 put_ldev(mdev);
Philipp Reisner0e29d162011-02-18 14:23:11 +01001774 conn_reconfig_done(mdev->tconn);
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01001775 drbd_adm_finish(info, retcode);
Philipp Reisnerb411b362009-09-25 16:07:19 -07001776 return 0;
1777
1778 force_diskless_dec:
1779 put_ldev(mdev);
1780 force_diskless:
Philipp Reisner9510b242011-07-01 17:00:57 +02001781 drbd_force_state(mdev, NS(disk, D_DISKLESS));
Philipp Reisnerb411b362009-09-25 16:07:19 -07001782 drbd_md_sync(mdev);
Philipp Reisnerb411b362009-09-25 16:07:19 -07001783 fail:
Lars Ellenberg40cbf082011-03-16 16:52:10 +01001784 conn_reconfig_done(mdev->tconn);
Philipp Reisnerb411b362009-09-25 16:07:19 -07001785 if (nbc) {
Tejun Heoe525fd82010-11-13 11:55:17 +01001786 if (nbc->backing_bdev)
1787 blkdev_put(nbc->backing_bdev,
1788 FMODE_READ | FMODE_WRITE | FMODE_EXCL);
1789 if (nbc->md_bdev)
1790 blkdev_put(nbc->md_bdev,
1791 FMODE_READ | FMODE_WRITE | FMODE_EXCL);
Philipp Reisnerb411b362009-09-25 16:07:19 -07001792 kfree(nbc);
1793 }
Philipp Reisnerdaeda1c2011-05-03 15:00:55 +02001794 kfree(new_disk_conf);
Philipp Reisnerb411b362009-09-25 16:07:19 -07001795 lc_destroy(resync_lru);
Philipp Reisner9958c852011-05-03 16:19:31 +02001796 kfree(new_plan);
Philipp Reisnerb411b362009-09-25 16:07:19 -07001797
Lars Ellenberg40cbf082011-03-16 16:52:10 +01001798 finish:
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01001799 drbd_adm_finish(info, retcode);
Philipp Reisnerb411b362009-09-25 16:07:19 -07001800 return 0;
1801}
1802
Philipp Reisnercdfda632011-07-05 15:38:59 +02001803static int adm_detach(struct drbd_conf *mdev, int force)
Philipp Reisnerb411b362009-09-25 16:07:19 -07001804{
Philipp Reisner19f83c72011-03-29 14:21:03 +02001805 enum drbd_state_rv retcode;
Lars Ellenberg9a0d9d02011-05-02 11:51:31 +02001806 int ret;
Philipp Reisner02ee8f92011-03-14 11:54:47 +01001807
Philipp Reisnercdfda632011-07-05 15:38:59 +02001808 if (force) {
Lars Ellenberg0c849662012-07-30 09:07:28 +02001809 set_bit(FORCE_DETACH, &mdev->flags);
Philipp Reisner02ee8f92011-03-14 11:54:47 +01001810 drbd_force_state(mdev, NS(disk, D_FAILED));
Philipp Reisnercdfda632011-07-05 15:38:59 +02001811 retcode = SS_SUCCESS;
Philipp Reisner02ee8f92011-03-14 11:54:47 +01001812 goto out;
1813 }
1814
Lars Ellenberg82f59cc2010-10-16 12:13:47 +02001815 drbd_suspend_io(mdev); /* so no-one is stuck in drbd_al_begin_io */
Lars Ellenberga2e91382011-10-06 17:30:26 +02001816 drbd_md_get_buffer(mdev); /* make sure there is no in-flight meta-data IO */
Lars Ellenberg9a0d9d02011-05-02 11:51:31 +02001817 retcode = drbd_request_state(mdev, NS(disk, D_FAILED));
Lars Ellenberga2e91382011-10-06 17:30:26 +02001818 drbd_md_put_buffer(mdev);
Lars Ellenberg9a0d9d02011-05-02 11:51:31 +02001819 /* D_FAILED will transition to DISKLESS. */
1820 ret = wait_event_interruptible(mdev->misc_wait,
1821 mdev->state.disk != D_FAILED);
Lars Ellenberg82f59cc2010-10-16 12:13:47 +02001822 drbd_resume_io(mdev);
Philipp Reisner9b2f61a2011-05-24 10:27:38 +02001823 if ((int)retcode == (int)SS_IS_DISKLESS)
Lars Ellenberg9a0d9d02011-05-02 11:51:31 +02001824 retcode = SS_NOTHING_TO_DO;
1825 if (ret)
1826 retcode = ERR_INTR;
Philipp Reisner02ee8f92011-03-14 11:54:47 +01001827out:
Lars Ellenberg85f75dd72011-03-15 16:26:37 +01001828 return retcode;
1829}
1830
Philipp Reisnerb411b362009-09-25 16:07:19 -07001831/* Detaching the disk is a process in multiple stages. First we need to lock
1832 * out application IO, in-flight IO, IO stuck in drbd_al_begin_io.
1833 * Then we transition to D_DISKLESS, and wait for put_ldev() to return all
1834 * internal references as well.
1835 * Only then we have finally detached. */
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01001836int drbd_adm_detach(struct sk_buff *skb, struct genl_info *info)
Philipp Reisnerb411b362009-09-25 16:07:19 -07001837{
1838 enum drbd_ret_code retcode;
Philipp Reisnercdfda632011-07-05 15:38:59 +02001839 struct detach_parms parms = { };
1840 int err;
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01001841
1842 retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_MINOR);
1843 if (!adm_ctx.reply_skb)
1844 return retcode;
1845 if (retcode != NO_ERROR)
1846 goto out;
1847
Philipp Reisnercdfda632011-07-05 15:38:59 +02001848 if (info->attrs[DRBD_NLA_DETACH_PARMS]) {
1849 err = detach_parms_from_attrs(&parms, info);
1850 if (err) {
1851 retcode = ERR_MANDATORY_TAG;
1852 drbd_msg_put_info(from_attrs_err_to_txt(err));
1853 goto out;
1854 }
1855 }
1856
1857 retcode = adm_detach(adm_ctx.mdev, parms.force_detach);
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01001858out:
1859 drbd_adm_finish(info, retcode);
Philipp Reisnerb411b362009-09-25 16:07:19 -07001860 return 0;
1861}
1862
Lars Ellenbergf3990022011-03-23 14:31:09 +01001863static bool conn_resync_running(struct drbd_tconn *tconn)
Philipp Reisnerb411b362009-09-25 16:07:19 -07001864{
Lars Ellenbergf3990022011-03-23 14:31:09 +01001865 struct drbd_conf *mdev;
Philipp Reisner695d08f2011-04-11 22:53:32 -07001866 bool rv = false;
Lars Ellenbergf3990022011-03-23 14:31:09 +01001867 int vnr;
1868
Philipp Reisner695d08f2011-04-11 22:53:32 -07001869 rcu_read_lock();
Lars Ellenbergf3990022011-03-23 14:31:09 +01001870 idr_for_each_entry(&tconn->volumes, mdev, vnr) {
1871 if (mdev->state.conn == C_SYNC_SOURCE ||
1872 mdev->state.conn == C_SYNC_TARGET ||
1873 mdev->state.conn == C_PAUSED_SYNC_S ||
Philipp Reisner695d08f2011-04-11 22:53:32 -07001874 mdev->state.conn == C_PAUSED_SYNC_T) {
1875 rv = true;
1876 break;
1877 }
Lars Ellenbergf3990022011-03-23 14:31:09 +01001878 }
Philipp Reisner695d08f2011-04-11 22:53:32 -07001879 rcu_read_unlock();
1880
1881 return rv;
Lars Ellenbergf3990022011-03-23 14:31:09 +01001882}
1883
1884static bool conn_ov_running(struct drbd_tconn *tconn)
1885{
1886 struct drbd_conf *mdev;
Philipp Reisner695d08f2011-04-11 22:53:32 -07001887 bool rv = false;
Lars Ellenbergf3990022011-03-23 14:31:09 +01001888 int vnr;
1889
Philipp Reisner695d08f2011-04-11 22:53:32 -07001890 rcu_read_lock();
Lars Ellenbergf3990022011-03-23 14:31:09 +01001891 idr_for_each_entry(&tconn->volumes, mdev, vnr) {
1892 if (mdev->state.conn == C_VERIFY_S ||
Philipp Reisner695d08f2011-04-11 22:53:32 -07001893 mdev->state.conn == C_VERIFY_T) {
1894 rv = true;
1895 break;
1896 }
Lars Ellenbergf3990022011-03-23 14:31:09 +01001897 }
Philipp Reisner695d08f2011-04-11 22:53:32 -07001898 rcu_read_unlock();
1899
1900 return rv;
Lars Ellenbergf3990022011-03-23 14:31:09 +01001901}
1902
Philipp Reisnercd643972011-04-13 18:00:59 -07001903static enum drbd_ret_code
Philipp Reisner44ed1672011-04-19 17:10:19 +02001904_check_net_options(struct drbd_tconn *tconn, struct net_conf *old_conf, struct net_conf *new_conf)
Philipp Reisnercd643972011-04-13 18:00:59 -07001905{
1906 struct drbd_conf *mdev;
1907 int i;
1908
Philipp Reisnerdcb20d12011-05-16 14:30:24 +02001909 if (old_conf && tconn->cstate == C_WF_REPORT_PARAMS && tconn->agreed_pro_version < 100) {
1910 if (new_conf->wire_protocol != old_conf->wire_protocol)
1911 return ERR_NEED_APV_100;
1912
1913 if (new_conf->two_primaries != old_conf->two_primaries)
1914 return ERR_NEED_APV_100;
1915
Philipp Reisnerdcb20d12011-05-16 14:30:24 +02001916 if (strcmp(new_conf->integrity_alg, old_conf->integrity_alg))
1917 return ERR_NEED_APV_100;
1918 }
1919
1920 if (!new_conf->two_primaries &&
1921 conn_highest_role(tconn) == R_PRIMARY &&
1922 conn_highest_peer(tconn) == R_PRIMARY)
1923 return ERR_NEED_ALLOW_TWO_PRI;
Philipp Reisnerb032b6f2011-04-13 18:16:10 -07001924
Philipp Reisnercd643972011-04-13 18:00:59 -07001925 if (new_conf->two_primaries &&
1926 (new_conf->wire_protocol != DRBD_PROT_C))
1927 return ERR_NOT_PROTO_C;
1928
Philipp Reisnercd643972011-04-13 18:00:59 -07001929 idr_for_each_entry(&tconn->volumes, mdev, i) {
1930 if (get_ldev(mdev)) {
Philipp Reisnerdaeda1c2011-05-03 15:00:55 +02001931 enum drbd_fencing_p fp = rcu_dereference(mdev->ldev->disk_conf)->fencing;
Philipp Reisnercd643972011-04-13 18:00:59 -07001932 put_ldev(mdev);
Philipp Reisner44ed1672011-04-19 17:10:19 +02001933 if (new_conf->wire_protocol == DRBD_PROT_A && fp == FP_STONITH)
Philipp Reisnercd643972011-04-13 18:00:59 -07001934 return ERR_STONITH_AND_PROT_A;
Philipp Reisnercd643972011-04-13 18:00:59 -07001935 }
Andreas Gruenbacher6139f602011-05-06 20:00:02 +02001936 if (mdev->state.role == R_PRIMARY && new_conf->discard_my_data)
Lars Ellenbergeb120102012-08-01 12:46:20 +02001937 return ERR_DISCARD_IMPOSSIBLE;
Philipp Reisnercd643972011-04-13 18:00:59 -07001938 }
Philipp Reisnercd643972011-04-13 18:00:59 -07001939
1940 if (new_conf->on_congestion != OC_BLOCK && new_conf->wire_protocol != DRBD_PROT_A)
1941 return ERR_CONG_NOT_PROTO_A;
1942
1943 return NO_ERROR;
1944}
1945
Philipp Reisner44ed1672011-04-19 17:10:19 +02001946static enum drbd_ret_code
1947check_net_options(struct drbd_tconn *tconn, struct net_conf *new_conf)
1948{
1949 static enum drbd_ret_code rv;
1950 struct drbd_conf *mdev;
1951 int i;
1952
1953 rcu_read_lock();
1954 rv = _check_net_options(tconn, rcu_dereference(tconn->net_conf), new_conf);
1955 rcu_read_unlock();
1956
1957 /* tconn->volumes protected by genl_lock() here */
1958 idr_for_each_entry(&tconn->volumes, mdev, i) {
1959 if (!mdev->bitmap) {
1960 if(drbd_bm_init(mdev))
1961 return ERR_NOMEM;
1962 }
1963 }
1964
1965 return rv;
1966}
1967
Philipp Reisner0fd0ea02011-04-27 11:27:47 +02001968struct crypto {
1969 struct crypto_hash *verify_tfm;
1970 struct crypto_hash *csums_tfm;
1971 struct crypto_hash *cram_hmac_tfm;
Andreas Gruenbacher8d412fc2011-04-27 20:59:18 +02001972 struct crypto_hash *integrity_tfm;
Philipp Reisner0fd0ea02011-04-27 11:27:47 +02001973};
1974
1975static int
Andreas Gruenbacher4b6ad6d2011-04-29 10:20:08 +02001976alloc_hash(struct crypto_hash **tfm, char *tfm_name, int err_alg)
Philipp Reisner0fd0ea02011-04-27 11:27:47 +02001977{
1978 if (!tfm_name[0])
1979 return NO_ERROR;
1980
1981 *tfm = crypto_alloc_hash(tfm_name, 0, CRYPTO_ALG_ASYNC);
1982 if (IS_ERR(*tfm)) {
1983 *tfm = NULL;
1984 return err_alg;
1985 }
1986
Philipp Reisner0fd0ea02011-04-27 11:27:47 +02001987 return NO_ERROR;
1988}
1989
1990static enum drbd_ret_code
1991alloc_crypto(struct crypto *crypto, struct net_conf *new_conf)
1992{
Philipp Reisnerb411b362009-09-25 16:07:19 -07001993 char hmac_name[CRYPTO_MAX_ALG_NAME];
Philipp Reisner0fd0ea02011-04-27 11:27:47 +02001994 enum drbd_ret_code rv;
Philipp Reisnerb411b362009-09-25 16:07:19 -07001995
Andreas Gruenbacher4b6ad6d2011-04-29 10:20:08 +02001996 rv = alloc_hash(&crypto->csums_tfm, new_conf->csums_alg,
1997 ERR_CSUMS_ALG);
Philipp Reisner0fd0ea02011-04-27 11:27:47 +02001998 if (rv != NO_ERROR)
1999 return rv;
Andreas Gruenbacher4b6ad6d2011-04-29 10:20:08 +02002000 rv = alloc_hash(&crypto->verify_tfm, new_conf->verify_alg,
2001 ERR_VERIFY_ALG);
Philipp Reisner0fd0ea02011-04-27 11:27:47 +02002002 if (rv != NO_ERROR)
2003 return rv;
Andreas Gruenbacher4b6ad6d2011-04-29 10:20:08 +02002004 rv = alloc_hash(&crypto->integrity_tfm, new_conf->integrity_alg,
2005 ERR_INTEGRITY_ALG);
Philipp Reisner0fd0ea02011-04-27 11:27:47 +02002006 if (rv != NO_ERROR)
2007 return rv;
Philipp Reisner0fd0ea02011-04-27 11:27:47 +02002008 if (new_conf->cram_hmac_alg[0] != 0) {
2009 snprintf(hmac_name, CRYPTO_MAX_ALG_NAME, "hmac(%s)",
2010 new_conf->cram_hmac_alg);
Philipp Reisnerb411b362009-09-25 16:07:19 -07002011
Andreas Gruenbacher4b6ad6d2011-04-29 10:20:08 +02002012 rv = alloc_hash(&crypto->cram_hmac_tfm, hmac_name,
2013 ERR_AUTH_ALG);
Philipp Reisner0fd0ea02011-04-27 11:27:47 +02002014 }
Philipp Reisner0fd0ea02011-04-27 11:27:47 +02002015
2016 return rv;
2017}
2018
2019static void free_crypto(struct crypto *crypto)
2020{
Philipp Reisner0fd0ea02011-04-27 11:27:47 +02002021 crypto_free_hash(crypto->cram_hmac_tfm);
Andreas Gruenbacher8d412fc2011-04-27 20:59:18 +02002022 crypto_free_hash(crypto->integrity_tfm);
Philipp Reisner0fd0ea02011-04-27 11:27:47 +02002023 crypto_free_hash(crypto->csums_tfm);
2024 crypto_free_hash(crypto->verify_tfm);
2025}
2026
Lars Ellenbergf3990022011-03-23 14:31:09 +01002027int drbd_adm_net_opts(struct sk_buff *skb, struct genl_info *info)
2028{
2029 enum drbd_ret_code retcode;
2030 struct drbd_tconn *tconn;
Philipp Reisner44ed1672011-04-19 17:10:19 +02002031 struct net_conf *old_conf, *new_conf = NULL;
Lars Ellenbergf3990022011-03-23 14:31:09 +01002032 int err;
2033 int ovr; /* online verify running */
2034 int rsr; /* re-sync running */
Philipp Reisner0fd0ea02011-04-27 11:27:47 +02002035 struct crypto crypto = { };
Lars Ellenbergf3990022011-03-23 14:31:09 +01002036
Andreas Gruenbacher089c0752011-06-14 18:28:09 +02002037 retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_CONNECTION);
Lars Ellenbergf3990022011-03-23 14:31:09 +01002038 if (!adm_ctx.reply_skb)
2039 return retcode;
2040 if (retcode != NO_ERROR)
2041 goto out;
2042
2043 tconn = adm_ctx.tconn;
2044
2045 new_conf = kzalloc(sizeof(struct net_conf), GFP_KERNEL);
2046 if (!new_conf) {
2047 retcode = ERR_NOMEM;
2048 goto out;
2049 }
2050
Lars Ellenbergf3990022011-03-23 14:31:09 +01002051 conn_reconfig_start(tconn);
2052
Andreas Gruenbacher88104ca2011-04-28 21:47:21 +02002053 mutex_lock(&tconn->data.mutex);
Philipp Reisnera0095502011-05-03 13:14:15 +02002054 mutex_lock(&tconn->conf_update);
Philipp Reisner91fd4da2011-04-20 17:47:29 +02002055 old_conf = tconn->net_conf;
Philipp Reisner44ed1672011-04-19 17:10:19 +02002056
2057 if (!old_conf) {
2058 drbd_msg_put_info("net conf missing, try connect");
2059 retcode = ERR_INVALID_REQUEST;
Philipp Reisner91fd4da2011-04-20 17:47:29 +02002060 goto fail;
Philipp Reisner44ed1672011-04-19 17:10:19 +02002061 }
2062
2063 *new_conf = *old_conf;
Lars Ellenberg5979e362011-04-27 21:09:55 +02002064 if (should_set_defaults(info))
Andreas Gruenbacherb966b5d2011-05-03 14:56:09 +02002065 set_net_conf_defaults(new_conf);
Philipp Reisner44ed1672011-04-19 17:10:19 +02002066
Lars Ellenbergf3990022011-03-23 14:31:09 +01002067 err = net_conf_from_attrs_for_change(new_conf, info);
Andreas Gruenbacherc75b9b12011-05-24 14:18:31 +02002068 if (err && err != -ENOMSG) {
Lars Ellenbergf3990022011-03-23 14:31:09 +01002069 retcode = ERR_MANDATORY_TAG;
2070 drbd_msg_put_info(from_attrs_err_to_txt(err));
2071 goto fail;
2072 }
2073
Philipp Reisnercd643972011-04-13 18:00:59 -07002074 retcode = check_net_options(tconn, new_conf);
2075 if (retcode != NO_ERROR)
2076 goto fail;
2077
Lars Ellenbergf3990022011-03-23 14:31:09 +01002078 /* re-sync running */
2079 rsr = conn_resync_running(tconn);
Philipp Reisner0fd0ea02011-04-27 11:27:47 +02002080 if (rsr && strcmp(new_conf->csums_alg, old_conf->csums_alg)) {
Lars Ellenbergf3990022011-03-23 14:31:09 +01002081 retcode = ERR_CSUMS_RESYNC_RUNNING;
Philipp Reisner91fd4da2011-04-20 17:47:29 +02002082 goto fail;
Lars Ellenbergf3990022011-03-23 14:31:09 +01002083 }
2084
Lars Ellenbergf3990022011-03-23 14:31:09 +01002085 /* online verify running */
2086 ovr = conn_ov_running(tconn);
Philipp Reisner0fd0ea02011-04-27 11:27:47 +02002087 if (ovr && strcmp(new_conf->verify_alg, old_conf->verify_alg)) {
2088 retcode = ERR_VERIFY_RUNNING;
2089 goto fail;
Lars Ellenbergf3990022011-03-23 14:31:09 +01002090 }
2091
Philipp Reisner0fd0ea02011-04-27 11:27:47 +02002092 retcode = alloc_crypto(&crypto, new_conf);
2093 if (retcode != NO_ERROR)
2094 goto fail;
Lars Ellenbergf3990022011-03-23 14:31:09 +01002095
Philipp Reisner44ed1672011-04-19 17:10:19 +02002096 rcu_assign_pointer(tconn->net_conf, new_conf);
Lars Ellenbergf3990022011-03-23 14:31:09 +01002097
2098 if (!rsr) {
2099 crypto_free_hash(tconn->csums_tfm);
Philipp Reisner0fd0ea02011-04-27 11:27:47 +02002100 tconn->csums_tfm = crypto.csums_tfm;
2101 crypto.csums_tfm = NULL;
Lars Ellenbergf3990022011-03-23 14:31:09 +01002102 }
2103 if (!ovr) {
2104 crypto_free_hash(tconn->verify_tfm);
Philipp Reisner0fd0ea02011-04-27 11:27:47 +02002105 tconn->verify_tfm = crypto.verify_tfm;
2106 crypto.verify_tfm = NULL;
Lars Ellenbergf3990022011-03-23 14:31:09 +01002107 }
2108
Andreas Gruenbacher8d412fc2011-04-27 20:59:18 +02002109 crypto_free_hash(tconn->integrity_tfm);
2110 tconn->integrity_tfm = crypto.integrity_tfm;
Philipp Reisnerd659f2a2011-05-16 17:38:45 +02002111 if (tconn->cstate >= C_WF_REPORT_PARAMS && tconn->agreed_pro_version >= 100)
Andreas Gruenbacher88104ca2011-04-28 21:47:21 +02002112 /* Do this without trying to take tconn->data.mutex again. */
Philipp Reisnerd659f2a2011-05-16 17:38:45 +02002113 __drbd_send_protocol(tconn, P_PROTOCOL_UPDATE);
Philipp Reisner0fd0ea02011-04-27 11:27:47 +02002114
Philipp Reisner0fd0ea02011-04-27 11:27:47 +02002115 crypto_free_hash(tconn->cram_hmac_tfm);
2116 tconn->cram_hmac_tfm = crypto.cram_hmac_tfm;
2117
Philipp Reisnera0095502011-05-03 13:14:15 +02002118 mutex_unlock(&tconn->conf_update);
Andreas Gruenbacher88104ca2011-04-28 21:47:21 +02002119 mutex_unlock(&tconn->data.mutex);
Philipp Reisner91fd4da2011-04-20 17:47:29 +02002120 synchronize_rcu();
2121 kfree(old_conf);
2122
Lars Ellenbergf3990022011-03-23 14:31:09 +01002123 if (tconn->cstate >= C_WF_REPORT_PARAMS)
2124 drbd_send_sync_param(minor_to_mdev(conn_lowest_minor(tconn)));
2125
Philipp Reisner91fd4da2011-04-20 17:47:29 +02002126 goto done;
2127
Lars Ellenbergf3990022011-03-23 14:31:09 +01002128 fail:
Philipp Reisnera0095502011-05-03 13:14:15 +02002129 mutex_unlock(&tconn->conf_update);
Andreas Gruenbacher88104ca2011-04-28 21:47:21 +02002130 mutex_unlock(&tconn->data.mutex);
Philipp Reisner0fd0ea02011-04-27 11:27:47 +02002131 free_crypto(&crypto);
Lars Ellenbergf3990022011-03-23 14:31:09 +01002132 kfree(new_conf);
Philipp Reisner91fd4da2011-04-20 17:47:29 +02002133 done:
Lars Ellenbergf3990022011-03-23 14:31:09 +01002134 conn_reconfig_done(tconn);
2135 out:
2136 drbd_adm_finish(info, retcode);
2137 return 0;
2138}
2139
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002140int drbd_adm_connect(struct sk_buff *skb, struct genl_info *info)
Philipp Reisnerb411b362009-09-25 16:07:19 -07002141{
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002142 struct drbd_conf *mdev;
Philipp Reisner44ed1672011-04-19 17:10:19 +02002143 struct net_conf *old_conf, *new_conf = NULL;
Philipp Reisner0fd0ea02011-04-27 11:27:47 +02002144 struct crypto crypto = { };
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002145 struct drbd_tconn *tconn;
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002146 enum drbd_ret_code retcode;
2147 int i;
2148 int err;
Philipp Reisnerb411b362009-09-25 16:07:19 -07002149
Andreas Gruenbacher44e52cf2011-06-14 16:07:32 +02002150 retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_RESOURCE);
Andreas Gruenbacher089c0752011-06-14 18:28:09 +02002151
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002152 if (!adm_ctx.reply_skb)
2153 return retcode;
2154 if (retcode != NO_ERROR)
2155 goto out;
Andreas Gruenbacher089c0752011-06-14 18:28:09 +02002156 if (!(adm_ctx.my_addr && adm_ctx.peer_addr)) {
2157 drbd_msg_put_info("connection endpoint(s) missing");
2158 retcode = ERR_INVALID_REQUEST;
2159 goto out;
2160 }
2161
2162 /* No need for _rcu here. All reconfiguration is
2163 * strictly serialized on genl_lock(). We are protected against
2164 * concurrent reconfiguration/addition/deletion */
2165 list_for_each_entry(tconn, &drbd_tconns, all_tconn) {
2166 if (nla_len(adm_ctx.my_addr) == tconn->my_addr_len &&
2167 !memcmp(nla_data(adm_ctx.my_addr), &tconn->my_addr, tconn->my_addr_len)) {
2168 retcode = ERR_LOCAL_ADDR;
2169 goto out;
2170 }
2171
2172 if (nla_len(adm_ctx.peer_addr) == tconn->peer_addr_len &&
2173 !memcmp(nla_data(adm_ctx.peer_addr), &tconn->peer_addr, tconn->peer_addr_len)) {
2174 retcode = ERR_PEER_ADDR;
2175 goto out;
2176 }
2177 }
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002178
2179 tconn = adm_ctx.tconn;
Philipp Reisner80883192011-02-18 14:56:45 +01002180 conn_reconfig_start(tconn);
Philipp Reisnerb411b362009-09-25 16:07:19 -07002181
Philipp Reisner80883192011-02-18 14:56:45 +01002182 if (tconn->cstate > C_STANDALONE) {
Philipp Reisnerb411b362009-09-25 16:07:19 -07002183 retcode = ERR_NET_CONFIGURED;
2184 goto fail;
2185 }
2186
Andreas Gruenbachera209b4a2011-08-17 12:43:25 +02002187 /* allocation not in the IO path, drbdsetup / netlink process context */
Lars Ellenberg5979e362011-04-27 21:09:55 +02002188 new_conf = kzalloc(sizeof(*new_conf), GFP_KERNEL);
Philipp Reisnerb411b362009-09-25 16:07:19 -07002189 if (!new_conf) {
2190 retcode = ERR_NOMEM;
2191 goto fail;
2192 }
2193
Andreas Gruenbacherb966b5d2011-05-03 14:56:09 +02002194 set_net_conf_defaults(new_conf);
Philipp Reisnerb411b362009-09-25 16:07:19 -07002195
Lars Ellenbergf3990022011-03-23 14:31:09 +01002196 err = net_conf_from_attrs(new_conf, info);
Lars Ellenberg25e40932011-08-19 10:39:00 +02002197 if (err && err != -ENOMSG) {
Philipp Reisnerb411b362009-09-25 16:07:19 -07002198 retcode = ERR_MANDATORY_TAG;
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002199 drbd_msg_put_info(from_attrs_err_to_txt(err));
Philipp Reisnerb411b362009-09-25 16:07:19 -07002200 goto fail;
2201 }
2202
Philipp Reisnercd643972011-04-13 18:00:59 -07002203 retcode = check_net_options(tconn, new_conf);
2204 if (retcode != NO_ERROR)
Philipp Reisnerb411b362009-09-25 16:07:19 -07002205 goto fail;
Philipp Reisner47ff2d02010-06-18 13:56:57 +02002206
Philipp Reisner0fd0ea02011-04-27 11:27:47 +02002207 retcode = alloc_crypto(&crypto, new_conf);
2208 if (retcode != NO_ERROR)
Philipp Reisner422028b2010-10-27 11:12:07 +02002209 goto fail;
Philipp Reisnerb411b362009-09-25 16:07:19 -07002210
2211 ((char *)new_conf->shared_secret)[SHARED_SECRET_MAX-1] = 0;
2212
Philipp Reisner80883192011-02-18 14:56:45 +01002213 conn_flush_workqueue(tconn);
Philipp Reisnerb411b362009-09-25 16:07:19 -07002214
Philipp Reisnera0095502011-05-03 13:14:15 +02002215 mutex_lock(&tconn->conf_update);
Philipp Reisner91fd4da2011-04-20 17:47:29 +02002216 old_conf = tconn->net_conf;
2217 if (old_conf) {
Philipp Reisnerb411b362009-09-25 16:07:19 -07002218 retcode = ERR_NET_CONFIGURED;
Philipp Reisnera0095502011-05-03 13:14:15 +02002219 mutex_unlock(&tconn->conf_update);
Philipp Reisnerb411b362009-09-25 16:07:19 -07002220 goto fail;
2221 }
Philipp Reisner44ed1672011-04-19 17:10:19 +02002222 rcu_assign_pointer(tconn->net_conf, new_conf);
Philipp Reisnerb411b362009-09-25 16:07:19 -07002223
Philipp Reisner91fd4da2011-04-20 17:47:29 +02002224 conn_free_crypto(tconn);
Philipp Reisner0fd0ea02011-04-27 11:27:47 +02002225 tconn->cram_hmac_tfm = crypto.cram_hmac_tfm;
Andreas Gruenbacher8d412fc2011-04-27 20:59:18 +02002226 tconn->integrity_tfm = crypto.integrity_tfm;
Philipp Reisner0fd0ea02011-04-27 11:27:47 +02002227 tconn->csums_tfm = crypto.csums_tfm;
2228 tconn->verify_tfm = crypto.verify_tfm;
Philipp Reisnerb411b362009-09-25 16:07:19 -07002229
Andreas Gruenbacher089c0752011-06-14 18:28:09 +02002230 tconn->my_addr_len = nla_len(adm_ctx.my_addr);
2231 memcpy(&tconn->my_addr, nla_data(adm_ctx.my_addr), tconn->my_addr_len);
2232 tconn->peer_addr_len = nla_len(adm_ctx.peer_addr);
2233 memcpy(&tconn->peer_addr, nla_data(adm_ctx.peer_addr), tconn->peer_addr_len);
2234
Philipp Reisnera0095502011-05-03 13:14:15 +02002235 mutex_unlock(&tconn->conf_update);
Philipp Reisner91fd4da2011-04-20 17:47:29 +02002236
Philipp Reisner695d08f2011-04-11 22:53:32 -07002237 rcu_read_lock();
Philipp Reisner80883192011-02-18 14:56:45 +01002238 idr_for_each_entry(&tconn->volumes, mdev, i) {
2239 mdev->send_cnt = 0;
2240 mdev->recv_cnt = 0;
Philipp Reisnerb411b362009-09-25 16:07:19 -07002241 }
Philipp Reisner695d08f2011-04-11 22:53:32 -07002242 rcu_read_unlock();
Philipp Reisnerb411b362009-09-25 16:07:19 -07002243
Lars Ellenberg5ee743e2011-04-26 16:22:25 +02002244 retcode = conn_request_state(tconn, NS(conn, C_UNCONNECTED), CS_VERBOSE);
Philipp Reisnerb411b362009-09-25 16:07:19 -07002245
Philipp Reisner80883192011-02-18 14:56:45 +01002246 conn_reconfig_done(tconn);
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002247 drbd_adm_finish(info, retcode);
Philipp Reisnerb411b362009-09-25 16:07:19 -07002248 return 0;
2249
2250fail:
Philipp Reisner0fd0ea02011-04-27 11:27:47 +02002251 free_crypto(&crypto);
Philipp Reisnerb411b362009-09-25 16:07:19 -07002252 kfree(new_conf);
2253
Philipp Reisner80883192011-02-18 14:56:45 +01002254 conn_reconfig_done(tconn);
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002255out:
2256 drbd_adm_finish(info, retcode);
Philipp Reisnerb411b362009-09-25 16:07:19 -07002257 return 0;
2258}
2259
Lars Ellenberg85f75dd72011-03-15 16:26:37 +01002260static enum drbd_state_rv conn_try_disconnect(struct drbd_tconn *tconn, bool force)
Philipp Reisnerb411b362009-09-25 16:07:19 -07002261{
Lars Ellenberg85f75dd72011-03-15 16:26:37 +01002262 enum drbd_state_rv rv;
Philipp Reisner2561b9c2010-12-03 15:22:48 +01002263
Lars Ellenbergf3dfa402011-05-02 10:45:05 +02002264 rv = conn_request_state(tconn, NS(conn, C_DISCONNECTING),
2265 force ? CS_HARD : 0);
Philipp Reisner2561b9c2010-12-03 15:22:48 +01002266
Lars Ellenberg85f75dd72011-03-15 16:26:37 +01002267 switch (rv) {
2268 case SS_NOTHING_TO_DO:
Lars Ellenbergf3dfa402011-05-02 10:45:05 +02002269 break;
Lars Ellenberg85f75dd72011-03-15 16:26:37 +01002270 case SS_ALREADY_STANDALONE:
2271 return SS_SUCCESS;
2272 case SS_PRIMARY_NOP:
2273 /* Our state checking code wants to see the peer outdated. */
Philipp Reisner2bd5ed52013-03-27 14:08:40 +01002274 rv = conn_request_state(tconn, NS2(conn, C_DISCONNECTING, pdsk, D_OUTDATED), 0);
2275
2276 if (rv == SS_OUTDATE_WO_CONN) /* lost connection before graceful disconnect succeeded */
2277 rv = conn_request_state(tconn, NS(conn, C_DISCONNECTING), CS_VERBOSE);
2278
Lars Ellenberg85f75dd72011-03-15 16:26:37 +01002279 break;
2280 case SS_CW_FAILED_BY_PEER:
Philipp Reisnerb411b362009-09-25 16:07:19 -07002281 /* The peer probably wants to see us outdated. */
Lars Ellenberg85f75dd72011-03-15 16:26:37 +01002282 rv = conn_request_state(tconn, NS2(conn, C_DISCONNECTING,
2283 disk, D_OUTDATED), 0);
2284 if (rv == SS_IS_DISKLESS || rv == SS_LOWER_THAN_OUTDATED) {
Lars Ellenbergf3dfa402011-05-02 10:45:05 +02002285 rv = conn_request_state(tconn, NS(conn, C_DISCONNECTING),
2286 CS_HARD);
Lars Ellenberg85f75dd72011-03-15 16:26:37 +01002287 }
2288 break;
2289 default:;
2290 /* no special handling necessary */
2291 }
2292
Lars Ellenbergf3dfa402011-05-02 10:45:05 +02002293 if (rv >= SS_SUCCESS) {
2294 enum drbd_state_rv rv2;
2295 /* No one else can reconfigure the network while I am here.
2296 * The state handling only uses drbd_thread_stop_nowait(),
2297 * we want to really wait here until the receiver is no more.
2298 */
2299 drbd_thread_stop(&adm_ctx.tconn->receiver);
2300
2301 /* Race breaker. This additional state change request may be
2302 * necessary, if this was a forced disconnect during a receiver
2303 * restart. We may have "killed" the receiver thread just
2304 * after drbdd_init() returned. Typically, we should be
2305 * C_STANDALONE already, now, and this becomes a no-op.
2306 */
2307 rv2 = conn_request_state(tconn, NS(conn, C_STANDALONE),
2308 CS_VERBOSE | CS_HARD);
2309 if (rv2 < SS_SUCCESS)
2310 conn_err(tconn,
2311 "unexpected rv2=%d in conn_try_disconnect()\n",
2312 rv2);
2313 }
Lars Ellenberg85f75dd72011-03-15 16:26:37 +01002314 return rv;
2315}
2316
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002317int drbd_adm_disconnect(struct sk_buff *skb, struct genl_info *info)
Philipp Reisnerb411b362009-09-25 16:07:19 -07002318{
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002319 struct disconnect_parms parms;
2320 struct drbd_tconn *tconn;
Lars Ellenberg85f75dd72011-03-15 16:26:37 +01002321 enum drbd_state_rv rv;
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002322 enum drbd_ret_code retcode;
2323 int err;
Philipp Reisnerb411b362009-09-25 16:07:19 -07002324
Andreas Gruenbacher089c0752011-06-14 18:28:09 +02002325 retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_CONNECTION);
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002326 if (!adm_ctx.reply_skb)
2327 return retcode;
2328 if (retcode != NO_ERROR)
Philipp Reisnerb411b362009-09-25 16:07:19 -07002329 goto fail;
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002330
2331 tconn = adm_ctx.tconn;
2332 memset(&parms, 0, sizeof(parms));
2333 if (info->attrs[DRBD_NLA_DISCONNECT_PARMS]) {
Lars Ellenbergf3990022011-03-23 14:31:09 +01002334 err = disconnect_parms_from_attrs(&parms, info);
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002335 if (err) {
2336 retcode = ERR_MANDATORY_TAG;
2337 drbd_msg_put_info(from_attrs_err_to_txt(err));
2338 goto fail;
Philipp Reisnerb411b362009-09-25 16:07:19 -07002339 }
2340 }
2341
Lars Ellenberg85f75dd72011-03-15 16:26:37 +01002342 rv = conn_try_disconnect(tconn, parms.force_disconnect);
2343 if (rv < SS_SUCCESS)
Lars Ellenbergf3dfa402011-05-02 10:45:05 +02002344 retcode = rv; /* FIXME: Type mismatch. */
2345 else
2346 retcode = NO_ERROR;
Philipp Reisnerb411b362009-09-25 16:07:19 -07002347 fail:
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002348 drbd_adm_finish(info, retcode);
Philipp Reisnerb411b362009-09-25 16:07:19 -07002349 return 0;
2350}
2351
2352void resync_after_online_grow(struct drbd_conf *mdev)
2353{
2354 int iass; /* I am sync source */
2355
2356 dev_info(DEV, "Resync of new storage after online grow\n");
2357 if (mdev->state.role != mdev->state.peer)
2358 iass = (mdev->state.role == R_PRIMARY);
2359 else
Lars Ellenberg427c0432012-08-01 12:43:01 +02002360 iass = test_bit(RESOLVE_CONFLICTS, &mdev->tconn->flags);
Philipp Reisnerb411b362009-09-25 16:07:19 -07002361
2362 if (iass)
2363 drbd_start_resync(mdev, C_SYNC_SOURCE);
2364 else
2365 _drbd_request_state(mdev, NS(conn, C_WF_SYNC_UUID), CS_VERBOSE + CS_SERIALIZE);
2366}
2367
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002368int drbd_adm_resize(struct sk_buff *skb, struct genl_info *info)
Philipp Reisnerb411b362009-09-25 16:07:19 -07002369{
Philipp Reisnerdaeda1c2011-05-03 15:00:55 +02002370 struct disk_conf *old_disk_conf, *new_disk_conf = NULL;
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002371 struct resize_parms rs;
2372 struct drbd_conf *mdev;
2373 enum drbd_ret_code retcode;
Philipp Reisnerb411b362009-09-25 16:07:19 -07002374 enum determine_dev_size dd;
Philipp Reisnerd752b262013-06-25 16:50:08 +02002375 bool change_al_layout = false;
Philipp Reisner6495d2c2010-03-24 16:07:04 +01002376 enum dds_flags ddsf;
Philipp Reisnerdaeda1c2011-05-03 15:00:55 +02002377 sector_t u_size;
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002378 int err;
Philipp Reisnerb411b362009-09-25 16:07:19 -07002379
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002380 retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_MINOR);
2381 if (!adm_ctx.reply_skb)
2382 return retcode;
2383 if (retcode != NO_ERROR)
Philipp Reisnerb411b362009-09-25 16:07:19 -07002384 goto fail;
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002385
Philipp Reisnerd752b262013-06-25 16:50:08 +02002386 mdev = adm_ctx.mdev;
2387 if (!get_ldev(mdev)) {
2388 retcode = ERR_NO_DISK;
2389 goto fail;
2390 }
2391
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002392 memset(&rs, 0, sizeof(struct resize_parms));
Philipp Reisnerd752b262013-06-25 16:50:08 +02002393 rs.al_stripes = mdev->ldev->md.al_stripes;
2394 rs.al_stripe_size = mdev->ldev->md.al_stripe_size_4k * 4;
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002395 if (info->attrs[DRBD_NLA_RESIZE_PARMS]) {
Lars Ellenbergf3990022011-03-23 14:31:09 +01002396 err = resize_parms_from_attrs(&rs, info);
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002397 if (err) {
2398 retcode = ERR_MANDATORY_TAG;
2399 drbd_msg_put_info(from_attrs_err_to_txt(err));
Philipp Reisnerd752b262013-06-25 16:50:08 +02002400 goto fail_ldev;
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002401 }
Philipp Reisnerb411b362009-09-25 16:07:19 -07002402 }
2403
2404 if (mdev->state.conn > C_CONNECTED) {
2405 retcode = ERR_RESIZE_RESYNC;
Philipp Reisnerd752b262013-06-25 16:50:08 +02002406 goto fail_ldev;
Philipp Reisnerb411b362009-09-25 16:07:19 -07002407 }
2408
2409 if (mdev->state.role == R_SECONDARY &&
2410 mdev->state.peer == R_SECONDARY) {
2411 retcode = ERR_NO_PRIMARY;
Philipp Reisnerd752b262013-06-25 16:50:08 +02002412 goto fail_ldev;
Philipp Reisnerb411b362009-09-25 16:07:19 -07002413 }
2414
Philipp Reisner31890f42011-01-19 14:12:51 +01002415 if (rs.no_resync && mdev->tconn->agreed_pro_version < 93) {
Philipp Reisner6495d2c2010-03-24 16:07:04 +01002416 retcode = ERR_NEED_APV_93;
Andreas Gruenbacher7b4e4d32011-09-28 22:15:04 +02002417 goto fail_ldev;
Philipp Reisner6495d2c2010-03-24 16:07:04 +01002418 }
2419
Philipp Reisnerdaeda1c2011-05-03 15:00:55 +02002420 rcu_read_lock();
2421 u_size = rcu_dereference(mdev->ldev->disk_conf)->disk_size;
2422 rcu_read_unlock();
2423 if (u_size != (sector_t)rs.resize_size) {
2424 new_disk_conf = kmalloc(sizeof(struct disk_conf), GFP_KERNEL);
2425 if (!new_disk_conf) {
2426 retcode = ERR_NOMEM;
Philipp Reisner9bcd2522011-09-29 13:00:14 +02002427 goto fail_ldev;
Philipp Reisnerdaeda1c2011-05-03 15:00:55 +02002428 }
2429 }
2430
Philipp Reisnerd752b262013-06-25 16:50:08 +02002431 if (mdev->ldev->md.al_stripes != rs.al_stripes ||
2432 mdev->ldev->md.al_stripe_size_4k != rs.al_stripe_size / 4) {
2433 u32 al_size_k = rs.al_stripes * rs.al_stripe_size;
2434
2435 if (al_size_k > (16 * 1024 * 1024)) {
2436 retcode = ERR_MD_LAYOUT_TOO_BIG;
2437 goto fail_ldev;
2438 }
2439
2440 if (al_size_k < MD_32kB_SECT/2) {
2441 retcode = ERR_MD_LAYOUT_TOO_SMALL;
2442 goto fail_ldev;
2443 }
2444
2445 if (mdev->state.conn != C_CONNECTED) {
2446 retcode = ERR_MD_LAYOUT_CONNECTED;
2447 goto fail_ldev;
2448 }
2449
2450 change_al_layout = true;
2451 }
2452
Philipp Reisner087c2492010-03-26 13:49:56 +01002453 if (mdev->ldev->known_size != drbd_get_capacity(mdev->ldev->backing_bdev))
Philipp Reisnerb411b362009-09-25 16:07:19 -07002454 mdev->ldev->known_size = drbd_get_capacity(mdev->ldev->backing_bdev);
Philipp Reisnerb411b362009-09-25 16:07:19 -07002455
Philipp Reisnerdaeda1c2011-05-03 15:00:55 +02002456 if (new_disk_conf) {
2457 mutex_lock(&mdev->tconn->conf_update);
2458 old_disk_conf = mdev->ldev->disk_conf;
2459 *new_disk_conf = *old_disk_conf;
2460 new_disk_conf->disk_size = (sector_t)rs.resize_size;
2461 rcu_assign_pointer(mdev->ldev->disk_conf, new_disk_conf);
2462 mutex_unlock(&mdev->tconn->conf_update);
2463 synchronize_rcu();
2464 kfree(old_disk_conf);
2465 }
2466
Philipp Reisner6495d2c2010-03-24 16:07:04 +01002467 ddsf = (rs.resize_force ? DDSF_FORCED : 0) | (rs.no_resync ? DDSF_NO_RESYNC : 0);
Philipp Reisnerd752b262013-06-25 16:50:08 +02002468 dd = drbd_determine_dev_size(mdev, ddsf, change_al_layout ? &rs : NULL);
Philipp Reisnerb411b362009-09-25 16:07:19 -07002469 drbd_md_sync(mdev);
2470 put_ldev(mdev);
Philipp Reisnere96c9632013-06-25 16:50:07 +02002471 if (dd == DS_ERROR) {
Philipp Reisnerb411b362009-09-25 16:07:19 -07002472 retcode = ERR_NOMEM_BITMAP;
2473 goto fail;
Philipp Reisnerd752b262013-06-25 16:50:08 +02002474 } else if (dd == DS_ERROR_SPACE_MD) {
2475 retcode = ERR_MD_LAYOUT_NO_FIT;
2476 goto fail;
2477 } else if (dd == DS_ERROR_SHRINK) {
2478 retcode = ERR_IMPLICIT_SHRINK;
2479 goto fail;
Philipp Reisnerb411b362009-09-25 16:07:19 -07002480 }
2481
Philipp Reisner087c2492010-03-26 13:49:56 +01002482 if (mdev->state.conn == C_CONNECTED) {
Philipp Reisnere96c9632013-06-25 16:50:07 +02002483 if (dd == DS_GREW)
Philipp Reisnerb411b362009-09-25 16:07:19 -07002484 set_bit(RESIZE_PENDING, &mdev->flags);
2485
2486 drbd_send_uuids(mdev);
Philipp Reisner6495d2c2010-03-24 16:07:04 +01002487 drbd_send_sizes(mdev, 1, ddsf);
Philipp Reisnerb411b362009-09-25 16:07:19 -07002488 }
2489
2490 fail:
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002491 drbd_adm_finish(info, retcode);
Philipp Reisnerb411b362009-09-25 16:07:19 -07002492 return 0;
Andreas Gruenbacher7b4e4d32011-09-28 22:15:04 +02002493
2494 fail_ldev:
2495 put_ldev(mdev);
2496 goto fail;
Philipp Reisnerb411b362009-09-25 16:07:19 -07002497}
2498
Lars Ellenbergf3990022011-03-23 14:31:09 +01002499int drbd_adm_resource_opts(struct sk_buff *skb, struct genl_info *info)
Philipp Reisnerb411b362009-09-25 16:07:19 -07002500{
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002501 enum drbd_ret_code retcode;
Lars Ellenbergf3990022011-03-23 14:31:09 +01002502 struct drbd_tconn *tconn;
Lars Ellenbergb57a1e22011-04-27 21:17:33 +02002503 struct res_opts res_opts;
Philipp Reisnerb411b362009-09-25 16:07:19 -07002504 int err;
Philipp Reisnerb411b362009-09-25 16:07:19 -07002505
Andreas Gruenbacher44e52cf2011-06-14 16:07:32 +02002506 retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_RESOURCE);
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002507 if (!adm_ctx.reply_skb)
2508 return retcode;
Philipp Reisnerb411b362009-09-25 16:07:19 -07002509 if (retcode != NO_ERROR)
2510 goto fail;
Lars Ellenbergf3990022011-03-23 14:31:09 +01002511 tconn = adm_ctx.tconn;
Philipp Reisnerb411b362009-09-25 16:07:19 -07002512
Lars Ellenbergb57a1e22011-04-27 21:17:33 +02002513 res_opts = tconn->res_opts;
Lars Ellenberg5979e362011-04-27 21:09:55 +02002514 if (should_set_defaults(info))
Andreas Gruenbacherb966b5d2011-05-03 14:56:09 +02002515 set_res_opts_defaults(&res_opts);
Philipp Reisnerb411b362009-09-25 16:07:19 -07002516
Lars Ellenbergb57a1e22011-04-27 21:17:33 +02002517 err = res_opts_from_attrs(&res_opts, info);
Andreas Gruenbacherc75b9b12011-05-24 14:18:31 +02002518 if (err && err != -ENOMSG) {
Philipp Reisnerb411b362009-09-25 16:07:19 -07002519 retcode = ERR_MANDATORY_TAG;
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002520 drbd_msg_put_info(from_attrs_err_to_txt(err));
Philipp Reisnerb411b362009-09-25 16:07:19 -07002521 goto fail;
2522 }
2523
Andreas Gruenbacherafbbfa82011-06-16 17:58:02 +02002524 err = set_resource_options(tconn, &res_opts);
2525 if (err) {
2526 retcode = ERR_INVALID_REQUEST;
2527 if (err == -ENOMEM)
Philipp Reisner778f2712010-07-06 11:14:00 +02002528 retcode = ERR_NOMEM;
Philipp Reisner778f2712010-07-06 11:14:00 +02002529 }
2530
Philipp Reisnerb411b362009-09-25 16:07:19 -07002531fail:
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002532 drbd_adm_finish(info, retcode);
Philipp Reisnerb411b362009-09-25 16:07:19 -07002533 return 0;
2534}
2535
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002536int drbd_adm_invalidate(struct sk_buff *skb, struct genl_info *info)
Philipp Reisnerb411b362009-09-25 16:07:19 -07002537{
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002538 struct drbd_conf *mdev;
2539 int retcode; /* enum drbd_ret_code rsp. enum drbd_state_rv */
2540
2541 retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_MINOR);
2542 if (!adm_ctx.reply_skb)
2543 return retcode;
2544 if (retcode != NO_ERROR)
2545 goto out;
2546
2547 mdev = adm_ctx.mdev;
Philipp Reisnerb411b362009-09-25 16:07:19 -07002548
Lars Ellenberg194bfb32011-01-18 10:38:01 +01002549 /* If there is still bitmap IO pending, probably because of a previous
Lars Ellenberg7ee1fb92012-06-19 10:27:58 +02002550 * resync just being finished, wait for it before requesting a new resync.
2551 * Also wait for it's after_state_ch(). */
Lars Ellenberga574daf2012-04-25 16:27:35 +02002552 drbd_suspend_io(mdev);
Lars Ellenberg194bfb32011-01-18 10:38:01 +01002553 wait_event(mdev->misc_wait, !test_bit(BITMAP_IO, &mdev->flags));
Lars Ellenberg7ee1fb92012-06-19 10:27:58 +02002554 drbd_flush_workqueue(mdev);
Lars Ellenberg194bfb32011-01-18 10:38:01 +01002555
Philipp Reisner0b2dafc2013-03-27 14:08:38 +01002556 /* If we happen to be C_STANDALONE R_SECONDARY, just change to
2557 * D_INCONSISTENT, and set all bits in the bitmap. Otherwise,
2558 * try to start a resync handshake as sync target for full sync.
Philipp Reisner9376d9f2013-03-27 14:08:36 +01002559 */
Philipp Reisner0b2dafc2013-03-27 14:08:38 +01002560 if (mdev->state.conn == C_STANDALONE && mdev->state.role == R_SECONDARY) {
2561 retcode = drbd_request_state(mdev, NS(disk, D_INCONSISTENT));
2562 if (retcode >= SS_SUCCESS) {
2563 if (drbd_bitmap_io(mdev, &drbd_bmio_set_n_write,
2564 "set_n_write from invalidate", BM_LOCKED_MASK))
2565 retcode = ERR_IO_MD_DISK;
2566 }
2567 } else
2568 retcode = drbd_request_state(mdev, NS(conn, C_STARTING_SYNC_T));
Lars Ellenberga574daf2012-04-25 16:27:35 +02002569 drbd_resume_io(mdev);
Philipp Reisnerb411b362009-09-25 16:07:19 -07002570
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002571out:
2572 drbd_adm_finish(info, retcode);
Philipp Reisnerb411b362009-09-25 16:07:19 -07002573 return 0;
2574}
2575
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002576static int drbd_adm_simple_request_state(struct sk_buff *skb, struct genl_info *info,
2577 union drbd_state mask, union drbd_state val)
Philipp Reisnerb411b362009-09-25 16:07:19 -07002578{
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002579 enum drbd_ret_code retcode;
Philipp Reisnerb411b362009-09-25 16:07:19 -07002580
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002581 retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_MINOR);
2582 if (!adm_ctx.reply_skb)
2583 return retcode;
2584 if (retcode != NO_ERROR)
2585 goto out;
Lars Ellenberg194bfb32011-01-18 10:38:01 +01002586
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002587 retcode = drbd_request_state(adm_ctx.mdev, mask, val);
2588out:
2589 drbd_adm_finish(info, retcode);
Philipp Reisnerb411b362009-09-25 16:07:19 -07002590 return 0;
2591}
2592
2593static int drbd_bmio_set_susp_al(struct drbd_conf *mdev)
2594{
2595 int rv;
2596
2597 rv = drbd_bmio_set_n_write(mdev);
2598 drbd_suspend_al(mdev);
2599 return rv;
2600}
2601
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002602int drbd_adm_invalidate_peer(struct sk_buff *skb, struct genl_info *info)
Philipp Reisnerb411b362009-09-25 16:07:19 -07002603{
Philipp Reisner25b0d6c2012-02-14 12:12:35 +01002604 int retcode; /* drbd_ret_code, drbd_state_rv */
2605 struct drbd_conf *mdev;
2606
2607 retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_MINOR);
2608 if (!adm_ctx.reply_skb)
2609 return retcode;
2610 if (retcode != NO_ERROR)
2611 goto out;
2612
2613 mdev = adm_ctx.mdev;
Philipp Reisnerb411b362009-09-25 16:07:19 -07002614
2615 /* If there is still bitmap IO pending, probably because of a previous
Lars Ellenberg7ee1fb92012-06-19 10:27:58 +02002616 * resync just being finished, wait for it before requesting a new resync.
2617 * Also wait for it's after_state_ch(). */
Lars Ellenberga574daf2012-04-25 16:27:35 +02002618 drbd_suspend_io(mdev);
Lars Ellenberg5016b822012-05-07 12:00:56 +02002619 wait_event(mdev->misc_wait, !test_bit(BITMAP_IO, &mdev->flags));
Lars Ellenberg7ee1fb92012-06-19 10:27:58 +02002620 drbd_flush_workqueue(mdev);
Philipp Reisnerb411b362009-09-25 16:07:19 -07002621
Philipp Reisner0b2dafc2013-03-27 14:08:38 +01002622 /* If we happen to be C_STANDALONE R_PRIMARY, just set all bits
2623 * in the bitmap. Otherwise, try to start a resync handshake
2624 * as sync source for full sync.
2625 */
2626 if (mdev->state.conn == C_STANDALONE && mdev->state.role == R_PRIMARY) {
2627 /* The peer will get a resync upon connect anyways. Just make that
2628 into a full resync. */
2629 retcode = drbd_request_state(mdev, NS(pdsk, D_INCONSISTENT));
2630 if (retcode >= SS_SUCCESS) {
2631 if (drbd_bitmap_io(mdev, &drbd_bmio_set_susp_al,
2632 "set_n_write from invalidate_peer",
2633 BM_LOCKED_SET_ALLOWED))
2634 retcode = ERR_IO_MD_DISK;
2635 }
2636 } else
2637 retcode = drbd_request_state(mdev, NS(conn, C_STARTING_SYNC_S));
Lars Ellenberga574daf2012-04-25 16:27:35 +02002638 drbd_resume_io(mdev);
Philipp Reisner07782862010-08-31 12:00:50 +02002639
Philipp Reisner25b0d6c2012-02-14 12:12:35 +01002640out:
2641 drbd_adm_finish(info, retcode);
Philipp Reisnerb411b362009-09-25 16:07:19 -07002642 return 0;
2643}
2644
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002645int drbd_adm_pause_sync(struct sk_buff *skb, struct genl_info *info)
Philipp Reisnerb411b362009-09-25 16:07:19 -07002646{
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002647 enum drbd_ret_code retcode;
Philipp Reisnerb411b362009-09-25 16:07:19 -07002648
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002649 retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_MINOR);
2650 if (!adm_ctx.reply_skb)
2651 return retcode;
2652 if (retcode != NO_ERROR)
2653 goto out;
2654
2655 if (drbd_request_state(adm_ctx.mdev, NS(user_isp, 1)) == SS_NOTHING_TO_DO)
Philipp Reisnerb411b362009-09-25 16:07:19 -07002656 retcode = ERR_PAUSE_IS_SET;
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002657out:
2658 drbd_adm_finish(info, retcode);
Philipp Reisnerb411b362009-09-25 16:07:19 -07002659 return 0;
2660}
2661
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002662int drbd_adm_resume_sync(struct sk_buff *skb, struct genl_info *info)
Philipp Reisnerb411b362009-09-25 16:07:19 -07002663{
Philipp Reisnerda9fbc22011-03-29 10:52:01 +02002664 union drbd_dev_state s;
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002665 enum drbd_ret_code retcode;
Philipp Reisnerb411b362009-09-25 16:07:19 -07002666
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002667 retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_MINOR);
2668 if (!adm_ctx.reply_skb)
2669 return retcode;
2670 if (retcode != NO_ERROR)
2671 goto out;
2672
2673 if (drbd_request_state(adm_ctx.mdev, NS(user_isp, 0)) == SS_NOTHING_TO_DO) {
2674 s = adm_ctx.mdev->state;
Philipp Reisnercd88d032011-01-20 11:46:41 +01002675 if (s.conn == C_PAUSED_SYNC_S || s.conn == C_PAUSED_SYNC_T) {
2676 retcode = s.aftr_isp ? ERR_PIC_AFTER_DEP :
2677 s.peer_isp ? ERR_PIC_PEER_DEP : ERR_PAUSE_IS_CLEAR;
2678 } else {
2679 retcode = ERR_PAUSE_IS_CLEAR;
2680 }
2681 }
Philipp Reisnerb411b362009-09-25 16:07:19 -07002682
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002683out:
2684 drbd_adm_finish(info, retcode);
Philipp Reisnerb411b362009-09-25 16:07:19 -07002685 return 0;
2686}
2687
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002688int drbd_adm_suspend_io(struct sk_buff *skb, struct genl_info *info)
Philipp Reisnerb411b362009-09-25 16:07:19 -07002689{
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002690 return drbd_adm_simple_request_state(skb, info, NS(susp, 1));
Philipp Reisnerb411b362009-09-25 16:07:19 -07002691}
2692
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002693int drbd_adm_resume_io(struct sk_buff *skb, struct genl_info *info)
Philipp Reisnerb411b362009-09-25 16:07:19 -07002694{
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002695 struct drbd_conf *mdev;
2696 int retcode; /* enum drbd_ret_code rsp. enum drbd_state_rv */
2697
2698 retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_MINOR);
2699 if (!adm_ctx.reply_skb)
2700 return retcode;
2701 if (retcode != NO_ERROR)
2702 goto out;
2703
2704 mdev = adm_ctx.mdev;
Philipp Reisner43a51822010-06-11 11:26:34 +02002705 if (test_bit(NEW_CUR_UUID, &mdev->flags)) {
2706 drbd_uuid_new_current(mdev);
2707 clear_bit(NEW_CUR_UUID, &mdev->flags);
Philipp Reisner43a51822010-06-11 11:26:34 +02002708 }
Philipp Reisner265be2d2010-05-31 10:14:17 +02002709 drbd_suspend_io(mdev);
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002710 retcode = drbd_request_state(mdev, NS3(susp, 0, susp_nod, 0, susp_fen, 0));
2711 if (retcode == SS_SUCCESS) {
Philipp Reisner265be2d2010-05-31 10:14:17 +02002712 if (mdev->state.conn < C_CONNECTED)
Philipp Reisner2f5cdd02011-02-21 14:29:27 +01002713 tl_clear(mdev->tconn);
Philipp Reisner265be2d2010-05-31 10:14:17 +02002714 if (mdev->state.disk == D_DISKLESS || mdev->state.disk == D_FAILED)
Philipp Reisner2f5cdd02011-02-21 14:29:27 +01002715 tl_restart(mdev->tconn, FAIL_FROZEN_DISK_IO);
Philipp Reisner265be2d2010-05-31 10:14:17 +02002716 }
2717 drbd_resume_io(mdev);
2718
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002719out:
2720 drbd_adm_finish(info, retcode);
Philipp Reisnerb411b362009-09-25 16:07:19 -07002721 return 0;
2722}
2723
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002724int drbd_adm_outdate(struct sk_buff *skb, struct genl_info *info)
Philipp Reisnerb411b362009-09-25 16:07:19 -07002725{
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002726 return drbd_adm_simple_request_state(skb, info, NS(disk, D_OUTDATED));
Philipp Reisnerb411b362009-09-25 16:07:19 -07002727}
2728
Rashika Kheria4b7a5302013-12-19 15:17:33 +05302729static int nla_put_drbd_cfg_context(struct sk_buff *skb,
2730 struct drbd_tconn *tconn, unsigned vnr)
Lars Ellenberg543cc102011-03-10 22:18:18 +01002731{
2732 struct nlattr *nla;
2733 nla = nla_nest_start(skb, DRBD_NLA_CFG_CONTEXT);
2734 if (!nla)
2735 goto nla_put_failure;
Andreas Gruenbacher26ec9282012-07-11 20:36:03 +02002736 if (vnr != VOLUME_UNSPECIFIED &&
2737 nla_put_u32(skb, T_ctx_volume, vnr))
2738 goto nla_put_failure;
2739 if (nla_put_string(skb, T_ctx_resource_name, tconn->name))
2740 goto nla_put_failure;
2741 if (tconn->my_addr_len &&
2742 nla_put(skb, T_ctx_my_addr, tconn->my_addr_len, &tconn->my_addr))
2743 goto nla_put_failure;
2744 if (tconn->peer_addr_len &&
2745 nla_put(skb, T_ctx_peer_addr, tconn->peer_addr_len, &tconn->peer_addr))
2746 goto nla_put_failure;
Lars Ellenberg543cc102011-03-10 22:18:18 +01002747 nla_nest_end(skb, nla);
Philipp Reisnerb411b362009-09-25 16:07:19 -07002748 return 0;
Lars Ellenberg543cc102011-03-10 22:18:18 +01002749
2750nla_put_failure:
2751 if (nla)
2752 nla_nest_cancel(skb, nla);
2753 return -EMSGSIZE;
Philipp Reisnerb411b362009-09-25 16:07:19 -07002754}
2755
Rashika Kheria4b7a5302013-12-19 15:17:33 +05302756static int nla_put_status_info(struct sk_buff *skb, struct drbd_conf *mdev,
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002757 const struct sib_info *sib)
Philipp Reisnerb411b362009-09-25 16:07:19 -07002758{
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002759 struct state_info *si = NULL; /* for sizeof(si->member); */
2760 struct nlattr *nla;
2761 int got_ldev;
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002762 int err = 0;
2763 int exclude_sensitive;
Philipp Reisnerb411b362009-09-25 16:07:19 -07002764
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002765 /* If sib != NULL, this is drbd_bcast_event, which anyone can listen
2766 * to. So we better exclude_sensitive information.
2767 *
2768 * If sib == NULL, this is drbd_adm_get_status, executed synchronously
2769 * in the context of the requesting user process. Exclude sensitive
2770 * information, unless current has superuser.
2771 *
2772 * NOTE: for drbd_adm_get_status_all(), this is a netlink dump, and
2773 * relies on the current implementation of netlink_dump(), which
2774 * executes the dump callback successively from netlink_recvmsg(),
2775 * always in the context of the receiving process */
2776 exclude_sensitive = sib || !capable(CAP_SYS_ADMIN);
Philipp Reisnerb411b362009-09-25 16:07:19 -07002777
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002778 got_ldev = get_ldev(mdev);
Philipp Reisnerb411b362009-09-25 16:07:19 -07002779
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002780 /* We need to add connection name and volume number information still.
2781 * Minor number is in drbd_genlmsghdr. */
Andreas Gruenbacher089c0752011-06-14 18:28:09 +02002782 if (nla_put_drbd_cfg_context(skb, mdev->tconn, mdev->vnr))
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002783 goto nla_put_failure;
Philipp Reisnerb411b362009-09-25 16:07:19 -07002784
Lars Ellenbergf3990022011-03-23 14:31:09 +01002785 if (res_opts_to_skb(skb, &mdev->tconn->res_opts, exclude_sensitive))
2786 goto nla_put_failure;
Philipp Reisnerb411b362009-09-25 16:07:19 -07002787
Philipp Reisnerdaeda1c2011-05-03 15:00:55 +02002788 rcu_read_lock();
Andreas Gruenbacherf9eb7bf2013-06-25 16:50:05 +02002789 if (got_ldev) {
2790 struct disk_conf *disk_conf;
Philipp Reisnerb411b362009-09-25 16:07:19 -07002791
Andreas Gruenbacherf9eb7bf2013-06-25 16:50:05 +02002792 disk_conf = rcu_dereference(mdev->ldev->disk_conf);
2793 err = disk_conf_to_skb(skb, disk_conf, exclude_sensitive);
2794 }
2795 if (!err) {
2796 struct net_conf *nc;
2797
2798 nc = rcu_dereference(mdev->tconn->net_conf);
2799 if (nc)
2800 err = net_conf_to_skb(skb, nc, exclude_sensitive);
2801 }
Philipp Reisner44ed1672011-04-19 17:10:19 +02002802 rcu_read_unlock();
2803 if (err)
2804 goto nla_put_failure;
Philipp Reisnerb411b362009-09-25 16:07:19 -07002805
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002806 nla = nla_nest_start(skb, DRBD_NLA_STATE_INFO);
2807 if (!nla)
2808 goto nla_put_failure;
Andreas Gruenbacher26ec9282012-07-11 20:36:03 +02002809 if (nla_put_u32(skb, T_sib_reason, sib ? sib->sib_reason : SIB_GET_STATUS_REPLY) ||
2810 nla_put_u32(skb, T_current_state, mdev->state.i) ||
2811 nla_put_u64(skb, T_ed_uuid, mdev->ed_uuid) ||
Philipp Marek3174f8c2012-03-03 21:04:30 +01002812 nla_put_u64(skb, T_capacity, drbd_get_capacity(mdev->this_bdev)) ||
2813 nla_put_u64(skb, T_send_cnt, mdev->send_cnt) ||
2814 nla_put_u64(skb, T_recv_cnt, mdev->recv_cnt) ||
2815 nla_put_u64(skb, T_read_cnt, mdev->read_cnt) ||
2816 nla_put_u64(skb, T_writ_cnt, mdev->writ_cnt) ||
2817 nla_put_u64(skb, T_al_writ_cnt, mdev->al_writ_cnt) ||
2818 nla_put_u64(skb, T_bm_writ_cnt, mdev->bm_writ_cnt) ||
2819 nla_put_u32(skb, T_ap_bio_cnt, atomic_read(&mdev->ap_bio_cnt)) ||
2820 nla_put_u32(skb, T_ap_pending_cnt, atomic_read(&mdev->ap_pending_cnt)) ||
2821 nla_put_u32(skb, T_rs_pending_cnt, atomic_read(&mdev->rs_pending_cnt)))
Andreas Gruenbacher26ec9282012-07-11 20:36:03 +02002822 goto nla_put_failure;
Philipp Reisnerb411b362009-09-25 16:07:19 -07002823
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002824 if (got_ldev) {
Philipp Reisner39a1aa7f2012-08-08 21:19:09 +02002825 int err;
2826
2827 spin_lock_irq(&mdev->ldev->md.uuid_lock);
2828 err = nla_put(skb, T_uuids, sizeof(si->uuids), mdev->ldev->md.uuid);
2829 spin_unlock_irq(&mdev->ldev->md.uuid_lock);
2830
2831 if (err)
2832 goto nla_put_failure;
2833
Andreas Gruenbacher26ec9282012-07-11 20:36:03 +02002834 if (nla_put_u32(skb, T_disk_flags, mdev->ldev->md.flags) ||
Andreas Gruenbacher26ec9282012-07-11 20:36:03 +02002835 nla_put_u64(skb, T_bits_total, drbd_bm_bits(mdev)) ||
2836 nla_put_u64(skb, T_bits_oos, drbd_bm_total_weight(mdev)))
2837 goto nla_put_failure;
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002838 if (C_SYNC_SOURCE <= mdev->state.conn &&
2839 C_PAUSED_SYNC_T >= mdev->state.conn) {
Andreas Gruenbacher26ec9282012-07-11 20:36:03 +02002840 if (nla_put_u64(skb, T_bits_rs_total, mdev->rs_total) ||
2841 nla_put_u64(skb, T_bits_rs_failed, mdev->rs_failed))
2842 goto nla_put_failure;
Philipp Reisnerb411b362009-09-25 16:07:19 -07002843 }
2844 }
Philipp Reisnerb411b362009-09-25 16:07:19 -07002845
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002846 if (sib) {
2847 switch(sib->sib_reason) {
2848 case SIB_SYNC_PROGRESS:
2849 case SIB_GET_STATUS_REPLY:
2850 break;
2851 case SIB_STATE_CHANGE:
Andreas Gruenbacher26ec9282012-07-11 20:36:03 +02002852 if (nla_put_u32(skb, T_prev_state, sib->os.i) ||
2853 nla_put_u32(skb, T_new_state, sib->ns.i))
2854 goto nla_put_failure;
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002855 break;
2856 case SIB_HELPER_POST:
Andreas Gruenbacher26ec9282012-07-11 20:36:03 +02002857 if (nla_put_u32(skb, T_helper_exit_code,
2858 sib->helper_exit_code))
2859 goto nla_put_failure;
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002860 /* fall through */
2861 case SIB_HELPER_PRE:
Andreas Gruenbacher26ec9282012-07-11 20:36:03 +02002862 if (nla_put_string(skb, T_helper, sib->helper_name))
2863 goto nla_put_failure;
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002864 break;
2865 }
2866 }
2867 nla_nest_end(skb, nla);
Philipp Reisnerb411b362009-09-25 16:07:19 -07002868
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002869 if (0)
2870nla_put_failure:
2871 err = -EMSGSIZE;
2872 if (got_ldev)
Philipp Reisnerb411b362009-09-25 16:07:19 -07002873 put_ldev(mdev);
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002874 return err;
Philipp Reisnerb411b362009-09-25 16:07:19 -07002875}
2876
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002877int drbd_adm_get_status(struct sk_buff *skb, struct genl_info *info)
Philipp Reisnerb411b362009-09-25 16:07:19 -07002878{
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002879 enum drbd_ret_code retcode;
2880 int err;
Philipp Reisnerb411b362009-09-25 16:07:19 -07002881
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002882 retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_MINOR);
2883 if (!adm_ctx.reply_skb)
2884 return retcode;
2885 if (retcode != NO_ERROR)
2886 goto out;
Philipp Reisnerb411b362009-09-25 16:07:19 -07002887
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002888 err = nla_put_status_info(adm_ctx.reply_skb, adm_ctx.mdev, NULL);
2889 if (err) {
2890 nlmsg_free(adm_ctx.reply_skb);
2891 return err;
2892 }
2893out:
2894 drbd_adm_finish(info, retcode);
2895 return 0;
Philipp Reisnerb411b362009-09-25 16:07:19 -07002896}
2897
Rashika Kheria4b7a5302013-12-19 15:17:33 +05302898static int get_one_status(struct sk_buff *skb, struct netlink_callback *cb)
Philipp Reisnerb411b362009-09-25 16:07:19 -07002899{
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002900 struct drbd_conf *mdev;
2901 struct drbd_genlmsghdr *dh;
Lars Ellenberg543cc102011-03-10 22:18:18 +01002902 struct drbd_tconn *pos = (struct drbd_tconn*)cb->args[0];
2903 struct drbd_tconn *tconn = NULL;
2904 struct drbd_tconn *tmp;
2905 unsigned volume = cb->args[1];
Philipp Reisnerb411b362009-09-25 16:07:19 -07002906
Lars Ellenberg543cc102011-03-10 22:18:18 +01002907 /* Open coded, deferred, iteration:
2908 * list_for_each_entry_safe(tconn, tmp, &drbd_tconns, all_tconn) {
2909 * idr_for_each_entry(&tconn->volumes, mdev, i) {
2910 * ...
2911 * }
2912 * }
2913 * where tconn is cb->args[0];
2914 * and i is cb->args[1];
2915 *
Lars Ellenberg71932ef2011-04-18 09:43:25 +02002916 * cb->args[2] indicates if we shall loop over all resources,
2917 * or just dump all volumes of a single resource.
2918 *
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002919 * This may miss entries inserted after this dump started,
2920 * or entries deleted before they are reached.
Lars Ellenberg543cc102011-03-10 22:18:18 +01002921 *
2922 * We need to make sure the mdev won't disappear while
2923 * we are looking at it, and revalidate our iterators
2924 * on each iteration.
2925 */
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002926
Philipp Reisner9dc9fbb2011-04-22 15:23:32 +02002927 /* synchronize with conn_create()/conn_destroy() */
Philipp Reisnerc141ebd2011-05-05 16:13:10 +02002928 rcu_read_lock();
Lars Ellenberg543cc102011-03-10 22:18:18 +01002929 /* revalidate iterator position */
Philipp Reisnerec0bddb2011-05-04 15:47:01 +02002930 list_for_each_entry_rcu(tmp, &drbd_tconns, all_tconn) {
Lars Ellenberg543cc102011-03-10 22:18:18 +01002931 if (pos == NULL) {
2932 /* first iteration */
2933 pos = tmp;
2934 tconn = pos;
2935 break;
2936 }
2937 if (tmp == pos) {
2938 tconn = pos;
2939 break;
2940 }
2941 }
2942 if (tconn) {
Lars Ellenberg71932ef2011-04-18 09:43:25 +02002943next_tconn:
Lars Ellenberg543cc102011-03-10 22:18:18 +01002944 mdev = idr_get_next(&tconn->volumes, &volume);
2945 if (!mdev) {
2946 /* No more volumes to dump on this tconn.
2947 * Advance tconn iterator. */
Philipp Reisnerec0bddb2011-05-04 15:47:01 +02002948 pos = list_entry_rcu(tconn->all_tconn.next,
2949 struct drbd_tconn, all_tconn);
Lars Ellenberg71932ef2011-04-18 09:43:25 +02002950 /* Did we dump any volume on this tconn yet? */
Lars Ellenberg543cc102011-03-10 22:18:18 +01002951 if (volume != 0) {
Lars Ellenberg71932ef2011-04-18 09:43:25 +02002952 /* If we reached the end of the list,
2953 * or only a single resource dump was requested,
2954 * we are done. */
2955 if (&pos->all_tconn == &drbd_tconns || cb->args[2])
2956 goto out;
Lars Ellenberg543cc102011-03-10 22:18:18 +01002957 volume = 0;
Lars Ellenberg71932ef2011-04-18 09:43:25 +02002958 tconn = pos;
Lars Ellenberg543cc102011-03-10 22:18:18 +01002959 goto next_tconn;
2960 }
2961 }
2962
Philipp Reisner98683652012-11-09 14:18:43 +01002963 dh = genlmsg_put(skb, NETLINK_CB(cb->skb).portid,
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002964 cb->nlh->nlmsg_seq, &drbd_genl_family,
2965 NLM_F_MULTI, DRBD_ADM_GET_STATUS);
2966 if (!dh)
Lars Ellenberg543cc102011-03-10 22:18:18 +01002967 goto out;
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002968
Lars Ellenberg543cc102011-03-10 22:18:18 +01002969 if (!mdev) {
Lars Ellenberg367d675d2011-07-11 23:49:55 +02002970 /* This is a tconn without a single volume.
2971 * Suprisingly enough, it may have a network
2972 * configuration. */
2973 struct net_conf *nc;
Lars Ellenberg543cc102011-03-10 22:18:18 +01002974 dh->minor = -1U;
2975 dh->ret_code = NO_ERROR;
Andreas Gruenbacher089c0752011-06-14 18:28:09 +02002976 if (nla_put_drbd_cfg_context(skb, tconn, VOLUME_UNSPECIFIED))
Lars Ellenberg367d675d2011-07-11 23:49:55 +02002977 goto cancel;
2978 nc = rcu_dereference(tconn->net_conf);
2979 if (nc && net_conf_to_skb(skb, nc, 1) != 0)
2980 goto cancel;
2981 goto done;
Lars Ellenberg543cc102011-03-10 22:18:18 +01002982 }
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002983
Lars Ellenberg543cc102011-03-10 22:18:18 +01002984 D_ASSERT(mdev->vnr == volume);
2985 D_ASSERT(mdev->tconn == tconn);
2986
2987 dh->minor = mdev_to_minor(mdev);
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002988 dh->ret_code = NO_ERROR;
2989
2990 if (nla_put_status_info(skb, mdev, NULL)) {
Lars Ellenberg367d675d2011-07-11 23:49:55 +02002991cancel:
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002992 genlmsg_cancel(skb, dh);
Lars Ellenberg543cc102011-03-10 22:18:18 +01002993 goto out;
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002994 }
Lars Ellenberg367d675d2011-07-11 23:49:55 +02002995done:
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01002996 genlmsg_end(skb, dh);
2997 }
2998
Lars Ellenberg543cc102011-03-10 22:18:18 +01002999out:
Philipp Reisnerc141ebd2011-05-05 16:13:10 +02003000 rcu_read_unlock();
Lars Ellenberg543cc102011-03-10 22:18:18 +01003001 /* where to start the next iteration */
3002 cb->args[0] = (long)pos;
3003 cb->args[1] = (pos == tconn) ? volume + 1 : 0;
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01003004
Lars Ellenberg543cc102011-03-10 22:18:18 +01003005 /* No more tconns/volumes/minors found results in an empty skb.
3006 * Which will terminate the dump. */
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01003007 return skb->len;
3008}
3009
Lars Ellenberg71932ef2011-04-18 09:43:25 +02003010/*
3011 * Request status of all resources, or of all volumes within a single resource.
3012 *
3013 * This is a dump, as the answer may not fit in a single reply skb otherwise.
3014 * Which means we cannot use the family->attrbuf or other such members, because
3015 * dump is NOT protected by the genl_lock(). During dump, we only have access
3016 * to the incoming skb, and need to opencode "parsing" of the nlattr payload.
3017 *
3018 * Once things are setup properly, we call into get_one_status().
Philipp Reisnerb411b362009-09-25 16:07:19 -07003019 */
Lars Ellenberg71932ef2011-04-18 09:43:25 +02003020int drbd_adm_get_status_all(struct sk_buff *skb, struct netlink_callback *cb)
Philipp Reisnerb411b362009-09-25 16:07:19 -07003021{
Lars Ellenberg71932ef2011-04-18 09:43:25 +02003022 const unsigned hdrlen = GENL_HDRLEN + GENL_MAGIC_FAMILY_HDRSZ;
3023 struct nlattr *nla;
Andreas Gruenbacher7c3063c2011-06-09 17:52:12 +02003024 const char *resource_name;
Lars Ellenberg71932ef2011-04-18 09:43:25 +02003025 struct drbd_tconn *tconn;
Andreas Gruenbacher7c3063c2011-06-09 17:52:12 +02003026 int maxtype;
Philipp Reisnerb411b362009-09-25 16:07:19 -07003027
Lars Ellenberg71932ef2011-04-18 09:43:25 +02003028 /* Is this a followup call? */
3029 if (cb->args[0]) {
3030 /* ... of a single resource dump,
3031 * and the resource iterator has been advanced already? */
3032 if (cb->args[2] && cb->args[2] != cb->args[0])
3033 return 0; /* DONE. */
3034 goto dump;
3035 }
Philipp Reisnerb411b362009-09-25 16:07:19 -07003036
Lars Ellenberg71932ef2011-04-18 09:43:25 +02003037 /* First call (from netlink_dump_start). We need to figure out
3038 * which resource(s) the user wants us to dump. */
3039 nla = nla_find(nlmsg_attrdata(cb->nlh, hdrlen),
3040 nlmsg_attrlen(cb->nlh, hdrlen),
3041 DRBD_NLA_CFG_CONTEXT);
Philipp Reisnerb411b362009-09-25 16:07:19 -07003042
Lars Ellenberg71932ef2011-04-18 09:43:25 +02003043 /* No explicit context given. Dump all. */
3044 if (!nla)
3045 goto dump;
Andreas Gruenbacher7c3063c2011-06-09 17:52:12 +02003046 maxtype = ARRAY_SIZE(drbd_cfg_context_nl_policy) - 1;
3047 nla = drbd_nla_find_nested(maxtype, nla, __nla_type(T_ctx_resource_name));
3048 if (IS_ERR(nla))
3049 return PTR_ERR(nla);
Lars Ellenberg71932ef2011-04-18 09:43:25 +02003050 /* context given, but no name present? */
3051 if (!nla)
3052 return -EINVAL;
Andreas Gruenbacher7c3063c2011-06-09 17:52:12 +02003053 resource_name = nla_data(nla);
3054 tconn = conn_get_by_name(resource_name);
Philipp Reisnerb411b362009-09-25 16:07:19 -07003055
Lars Ellenberg71932ef2011-04-18 09:43:25 +02003056 if (!tconn)
3057 return -ENODEV;
3058
Philipp Reisner0ace9df2011-04-24 10:53:19 +02003059 kref_put(&tconn->kref, &conn_destroy); /* get_one_status() (re)validates tconn by itself */
3060
Lars Ellenberg71932ef2011-04-18 09:43:25 +02003061 /* prime iterators, and set "filter" mode mark:
3062 * only dump this tconn. */
3063 cb->args[0] = (long)tconn;
3064 /* cb->args[1] = 0; passed in this way. */
3065 cb->args[2] = (long)tconn;
3066
3067dump:
3068 return get_one_status(skb, cb);
Philipp Reisnerb411b362009-09-25 16:07:19 -07003069}
3070
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01003071int drbd_adm_get_timeout_type(struct sk_buff *skb, struct genl_info *info)
Philipp Reisnerb411b362009-09-25 16:07:19 -07003072{
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01003073 enum drbd_ret_code retcode;
3074 struct timeout_parms tp;
3075 int err;
Philipp Reisnerb411b362009-09-25 16:07:19 -07003076
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01003077 retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_MINOR);
3078 if (!adm_ctx.reply_skb)
3079 return retcode;
3080 if (retcode != NO_ERROR)
3081 goto out;
3082
3083 tp.timeout_type =
3084 adm_ctx.mdev->state.pdsk == D_OUTDATED ? UT_PEER_OUTDATED :
3085 test_bit(USE_DEGR_WFC_T, &adm_ctx.mdev->flags) ? UT_DEGRADED :
3086 UT_DEFAULT;
3087
3088 err = timeout_parms_to_priv_skb(adm_ctx.reply_skb, &tp);
3089 if (err) {
3090 nlmsg_free(adm_ctx.reply_skb);
3091 return err;
Philipp Reisnerb411b362009-09-25 16:07:19 -07003092 }
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01003093out:
3094 drbd_adm_finish(info, retcode);
3095 return 0;
3096}
Lars Ellenberg873b0d52011-01-21 22:53:48 +01003097
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01003098int drbd_adm_start_ov(struct sk_buff *skb, struct genl_info *info)
3099{
3100 struct drbd_conf *mdev;
3101 enum drbd_ret_code retcode;
Lars Ellenberg58ffa582012-07-26 14:09:49 +02003102 struct start_ov_parms parms;
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01003103
3104 retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_MINOR);
3105 if (!adm_ctx.reply_skb)
3106 return retcode;
3107 if (retcode != NO_ERROR)
3108 goto out;
3109
3110 mdev = adm_ctx.mdev;
Lars Ellenberg58ffa582012-07-26 14:09:49 +02003111
3112 /* resume from last known position, if possible */
3113 parms.ov_start_sector = mdev->ov_start_sector;
3114 parms.ov_stop_sector = ULLONG_MAX;
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01003115 if (info->attrs[DRBD_NLA_START_OV_PARMS]) {
Lars Ellenbergf3990022011-03-23 14:31:09 +01003116 int err = start_ov_parms_from_attrs(&parms, info);
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01003117 if (err) {
3118 retcode = ERR_MANDATORY_TAG;
3119 drbd_msg_put_info(from_attrs_err_to_txt(err));
3120 goto out;
3121 }
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01003122 }
Lars Ellenberg58ffa582012-07-26 14:09:49 +02003123 /* w_make_ov_request expects position to be aligned */
3124 mdev->ov_start_sector = parms.ov_start_sector & ~(BM_SECT_PER_BIT-1);
3125 mdev->ov_stop_sector = parms.ov_stop_sector;
Lars Ellenberg873b0d52011-01-21 22:53:48 +01003126
3127 /* If there is still bitmap IO pending, e.g. previous resync or verify
3128 * just being finished, wait for it before requesting a new resync. */
Lars Ellenberga574daf2012-04-25 16:27:35 +02003129 drbd_suspend_io(mdev);
Lars Ellenberg873b0d52011-01-21 22:53:48 +01003130 wait_event(mdev->misc_wait, !test_bit(BITMAP_IO, &mdev->flags));
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01003131 retcode = drbd_request_state(mdev,NS(conn,C_VERIFY_S));
Lars Ellenberga574daf2012-04-25 16:27:35 +02003132 drbd_resume_io(mdev);
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01003133out:
3134 drbd_adm_finish(info, retcode);
Philipp Reisnerb411b362009-09-25 16:07:19 -07003135 return 0;
3136}
3137
3138
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01003139int drbd_adm_new_c_uuid(struct sk_buff *skb, struct genl_info *info)
Philipp Reisnerb411b362009-09-25 16:07:19 -07003140{
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01003141 struct drbd_conf *mdev;
3142 enum drbd_ret_code retcode;
Philipp Reisnerb411b362009-09-25 16:07:19 -07003143 int skip_initial_sync = 0;
3144 int err;
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01003145 struct new_c_uuid_parms args;
Philipp Reisnerb411b362009-09-25 16:07:19 -07003146
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01003147 retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_MINOR);
3148 if (!adm_ctx.reply_skb)
3149 return retcode;
3150 if (retcode != NO_ERROR)
3151 goto out_nolock;
Philipp Reisnerb411b362009-09-25 16:07:19 -07003152
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01003153 mdev = adm_ctx.mdev;
3154 memset(&args, 0, sizeof(args));
3155 if (info->attrs[DRBD_NLA_NEW_C_UUID_PARMS]) {
Lars Ellenbergf3990022011-03-23 14:31:09 +01003156 err = new_c_uuid_parms_from_attrs(&args, info);
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01003157 if (err) {
3158 retcode = ERR_MANDATORY_TAG;
3159 drbd_msg_put_info(from_attrs_err_to_txt(err));
3160 goto out_nolock;
3161 }
Philipp Reisnerb411b362009-09-25 16:07:19 -07003162 }
3163
Philipp Reisner8410da82011-02-11 20:11:10 +01003164 mutex_lock(mdev->state_mutex); /* Protects us against serialized state changes. */
Philipp Reisnerb411b362009-09-25 16:07:19 -07003165
3166 if (!get_ldev(mdev)) {
3167 retcode = ERR_NO_DISK;
3168 goto out;
3169 }
3170
3171 /* this is "skip initial sync", assume to be clean */
Philipp Reisner31890f42011-01-19 14:12:51 +01003172 if (mdev->state.conn == C_CONNECTED && mdev->tconn->agreed_pro_version >= 90 &&
Philipp Reisnerb411b362009-09-25 16:07:19 -07003173 mdev->ldev->md.uuid[UI_CURRENT] == UUID_JUST_CREATED && args.clear_bm) {
3174 dev_info(DEV, "Preparing to skip initial sync\n");
3175 skip_initial_sync = 1;
3176 } else if (mdev->state.conn != C_STANDALONE) {
3177 retcode = ERR_CONNECTED;
3178 goto out_dec;
3179 }
3180
3181 drbd_uuid_set(mdev, UI_BITMAP, 0); /* Rotate UI_BITMAP to History 1, etc... */
3182 drbd_uuid_new_current(mdev); /* New current, previous to UI_BITMAP */
3183
3184 if (args.clear_bm) {
Lars Ellenberg20ceb2b2011-01-21 10:56:44 +01003185 err = drbd_bitmap_io(mdev, &drbd_bmio_clear_n_write,
3186 "clear_n_write from new_c_uuid", BM_LOCKED_MASK);
Philipp Reisnerb411b362009-09-25 16:07:19 -07003187 if (err) {
3188 dev_err(DEV, "Writing bitmap failed with %d\n",err);
3189 retcode = ERR_IO_MD_DISK;
3190 }
3191 if (skip_initial_sync) {
3192 drbd_send_uuids_skip_initial_sync(mdev);
3193 _drbd_uuid_set(mdev, UI_BITMAP, 0);
Lars Ellenberg62b0da32011-01-20 13:25:21 +01003194 drbd_print_uuids(mdev, "cleared bitmap UUID");
Philipp Reisner87eeee42011-01-19 14:16:30 +01003195 spin_lock_irq(&mdev->tconn->req_lock);
Philipp Reisnerb411b362009-09-25 16:07:19 -07003196 _drbd_set_state(_NS2(mdev, disk, D_UP_TO_DATE, pdsk, D_UP_TO_DATE),
3197 CS_VERBOSE, NULL);
Philipp Reisner87eeee42011-01-19 14:16:30 +01003198 spin_unlock_irq(&mdev->tconn->req_lock);
Philipp Reisnerb411b362009-09-25 16:07:19 -07003199 }
3200 }
3201
3202 drbd_md_sync(mdev);
3203out_dec:
3204 put_ldev(mdev);
3205out:
Philipp Reisner8410da82011-02-11 20:11:10 +01003206 mutex_unlock(mdev->state_mutex);
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01003207out_nolock:
3208 drbd_adm_finish(info, retcode);
Philipp Reisnerb411b362009-09-25 16:07:19 -07003209 return 0;
3210}
3211
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01003212static enum drbd_ret_code
Andreas Gruenbacher7c3063c2011-06-09 17:52:12 +02003213drbd_check_resource_name(const char *name)
Philipp Reisnerb411b362009-09-25 16:07:19 -07003214{
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01003215 if (!name || !name[0]) {
Andreas Gruenbacher7c3063c2011-06-09 17:52:12 +02003216 drbd_msg_put_info("resource name missing");
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01003217 return ERR_MANDATORY_TAG;
3218 }
3219 /* if we want to use these in sysfs/configfs/debugfs some day,
3220 * we must not allow slashes */
3221 if (strchr(name, '/')) {
Andreas Gruenbacher7c3063c2011-06-09 17:52:12 +02003222 drbd_msg_put_info("invalid resource name");
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01003223 return ERR_INVALID_REQUEST;
3224 }
3225 return NO_ERROR;
3226}
Philipp Reisnerb411b362009-09-25 16:07:19 -07003227
Andreas Gruenbacher789c1b62011-06-06 16:16:44 +02003228int drbd_adm_new_resource(struct sk_buff *skb, struct genl_info *info)
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01003229{
3230 enum drbd_ret_code retcode;
Andreas Gruenbacherafbbfa82011-06-16 17:58:02 +02003231 struct res_opts res_opts;
3232 int err;
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01003233
3234 retcode = drbd_adm_prepare(skb, info, 0);
3235 if (!adm_ctx.reply_skb)
3236 return retcode;
3237 if (retcode != NO_ERROR)
3238 goto out;
3239
Andreas Gruenbacherafbbfa82011-06-16 17:58:02 +02003240 set_res_opts_defaults(&res_opts);
3241 err = res_opts_from_attrs(&res_opts, info);
3242 if (err && err != -ENOMSG) {
3243 retcode = ERR_MANDATORY_TAG;
3244 drbd_msg_put_info(from_attrs_err_to_txt(err));
3245 goto out;
Philipp Reisnerb411b362009-09-25 16:07:19 -07003246 }
3247
Andreas Gruenbacher7c3063c2011-06-09 17:52:12 +02003248 retcode = drbd_check_resource_name(adm_ctx.resource_name);
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01003249 if (retcode != NO_ERROR)
3250 goto out;
3251
3252 if (adm_ctx.tconn) {
Lars Ellenberg38f19612011-03-14 13:22:35 +01003253 if (info->nlhdr->nlmsg_flags & NLM_F_EXCL) {
3254 retcode = ERR_INVALID_REQUEST;
Andreas Gruenbacher789c1b62011-06-06 16:16:44 +02003255 drbd_msg_put_info("resource exists");
Lars Ellenberg38f19612011-03-14 13:22:35 +01003256 }
3257 /* else: still NO_ERROR */
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01003258 goto out;
Philipp Reisner9f5180e2009-10-06 09:30:14 +02003259 }
3260
Andreas Gruenbacherafbbfa82011-06-16 17:58:02 +02003261 if (!conn_create(adm_ctx.resource_name, &res_opts))
Philipp Reisnerb411b362009-09-25 16:07:19 -07003262 retcode = ERR_NOMEM;
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01003263out:
3264 drbd_adm_finish(info, retcode);
Philipp Reisnerb411b362009-09-25 16:07:19 -07003265 return 0;
3266}
3267
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01003268int drbd_adm_add_minor(struct sk_buff *skb, struct genl_info *info)
Philipp Reisnerb411b362009-09-25 16:07:19 -07003269{
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01003270 struct drbd_genlmsghdr *dh = info->userhdr;
3271 enum drbd_ret_code retcode;
Philipp Reisnerb411b362009-09-25 16:07:19 -07003272
Andreas Gruenbacher44e52cf2011-06-14 16:07:32 +02003273 retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_RESOURCE);
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01003274 if (!adm_ctx.reply_skb)
3275 return retcode;
3276 if (retcode != NO_ERROR)
3277 goto out;
Philipp Reisnerb411b362009-09-25 16:07:19 -07003278
Andreas Gruenbacherf2257a52011-07-14 16:00:40 +02003279 if (dh->minor > MINORMASK) {
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01003280 drbd_msg_put_info("requested minor out of range");
3281 retcode = ERR_INVALID_REQUEST;
3282 goto out;
3283 }
Andreas Gruenbacher0c8e36d2011-03-30 16:00:17 +02003284 if (adm_ctx.volume > DRBD_VOLUME_MAX) {
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01003285 drbd_msg_put_info("requested volume id out of range");
3286 retcode = ERR_INVALID_REQUEST;
3287 goto out;
Philipp Reisner774b3052011-02-22 02:07:03 -05003288 }
3289
Lars Ellenberg38f19612011-03-14 13:22:35 +01003290 /* drbd_adm_prepare made sure already
3291 * that mdev->tconn and mdev->vnr match the request. */
3292 if (adm_ctx.mdev) {
3293 if (info->nlhdr->nlmsg_flags & NLM_F_EXCL)
3294 retcode = ERR_MINOR_EXISTS;
3295 /* else: still NO_ERROR */
3296 goto out;
3297 }
3298
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01003299 retcode = conn_new_minor(adm_ctx.tconn, dh->minor, adm_ctx.volume);
3300out:
3301 drbd_adm_finish(info, retcode);
Philipp Reisner774b3052011-02-22 02:07:03 -05003302 return 0;
Philipp Reisnerb411b362009-09-25 16:07:19 -07003303}
3304
Lars Ellenberg85f75dd72011-03-15 16:26:37 +01003305static enum drbd_ret_code adm_delete_minor(struct drbd_conf *mdev)
Philipp Reisnerb411b362009-09-25 16:07:19 -07003306{
Lars Ellenberg85f75dd72011-03-15 16:26:37 +01003307 if (mdev->state.disk == D_DISKLESS &&
3308 /* no need to be mdev->state.conn == C_STANDALONE &&
3309 * we may want to delete a minor from a live replication group.
3310 */
3311 mdev->state.role == R_SECONDARY) {
Philipp Reisner369bea62011-07-06 23:04:44 +02003312 _drbd_request_state(mdev, NS(conn, C_WF_REPORT_PARAMS),
3313 CS_VERBOSE + CS_WAIT_COMPLETE);
Philipp Reisner81fa2e62011-05-04 15:10:30 +02003314 idr_remove(&mdev->tconn->volumes, mdev->vnr);
3315 idr_remove(&minors, mdev_to_minor(mdev));
Lars Ellenberg113fef92013-03-22 18:14:40 -06003316 destroy_workqueue(mdev->submit.wq);
Philipp Reisner81fa2e62011-05-04 15:10:30 +02003317 del_gendisk(mdev->vdisk);
3318 synchronize_rcu();
3319 kref_put(&mdev->kref, &drbd_minor_destroy);
Lars Ellenberg85f75dd72011-03-15 16:26:37 +01003320 return NO_ERROR;
3321 } else
3322 return ERR_MINOR_CONFIGURED;
Philipp Reisnerb411b362009-09-25 16:07:19 -07003323}
3324
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01003325int drbd_adm_delete_minor(struct sk_buff *skb, struct genl_info *info)
Philipp Reisner774b3052011-02-22 02:07:03 -05003326{
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01003327 enum drbd_ret_code retcode;
3328
3329 retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_MINOR);
3330 if (!adm_ctx.reply_skb)
3331 return retcode;
3332 if (retcode != NO_ERROR)
3333 goto out;
3334
Lars Ellenberg85f75dd72011-03-15 16:26:37 +01003335 retcode = adm_delete_minor(adm_ctx.mdev);
Lars Ellenberg85f75dd72011-03-15 16:26:37 +01003336out:
3337 drbd_adm_finish(info, retcode);
3338 return 0;
3339}
3340
3341int drbd_adm_down(struct sk_buff *skb, struct genl_info *info)
3342{
Lars Ellenbergf3dfa402011-05-02 10:45:05 +02003343 int retcode; /* enum drbd_ret_code rsp. enum drbd_state_rv */
Lars Ellenberg85f75dd72011-03-15 16:26:37 +01003344 struct drbd_conf *mdev;
3345 unsigned i;
3346
3347 retcode = drbd_adm_prepare(skb, info, 0);
3348 if (!adm_ctx.reply_skb)
3349 return retcode;
3350 if (retcode != NO_ERROR)
3351 goto out;
3352
3353 if (!adm_ctx.tconn) {
Andreas Gruenbacher789c1b62011-06-06 16:16:44 +02003354 retcode = ERR_RES_NOT_KNOWN;
Lars Ellenberg85f75dd72011-03-15 16:26:37 +01003355 goto out;
3356 }
3357
Lars Ellenberg85f75dd72011-03-15 16:26:37 +01003358 /* demote */
3359 idr_for_each_entry(&adm_ctx.tconn->volumes, mdev, i) {
3360 retcode = drbd_set_role(mdev, R_SECONDARY, 0);
3361 if (retcode < SS_SUCCESS) {
3362 drbd_msg_put_info("failed to demote");
Philipp Reisnerc141ebd2011-05-05 16:13:10 +02003363 goto out;
Lars Ellenberg85f75dd72011-03-15 16:26:37 +01003364 }
3365 }
3366
Lars Ellenbergf3dfa402011-05-02 10:45:05 +02003367 retcode = conn_try_disconnect(adm_ctx.tconn, 0);
3368 if (retcode < SS_SUCCESS) {
Lars Ellenberg85f75dd72011-03-15 16:26:37 +01003369 drbd_msg_put_info("failed to disconnect");
Lars Ellenbergf3dfa402011-05-02 10:45:05 +02003370 goto out;
Lars Ellenberg85f75dd72011-03-15 16:26:37 +01003371 }
3372
3373 /* detach */
3374 idr_for_each_entry(&adm_ctx.tconn->volumes, mdev, i) {
Philipp Reisnercdfda632011-07-05 15:38:59 +02003375 retcode = adm_detach(mdev, 0);
Lars Ellenberg27012382012-07-24 10:13:55 +02003376 if (retcode < SS_SUCCESS || retcode > NO_ERROR) {
Lars Ellenberg85f75dd72011-03-15 16:26:37 +01003377 drbd_msg_put_info("failed to detach");
Philipp Reisnerc141ebd2011-05-05 16:13:10 +02003378 goto out;
Lars Ellenberg85f75dd72011-03-15 16:26:37 +01003379 }
3380 }
3381
Lars Ellenbergf3dfa402011-05-02 10:45:05 +02003382 /* If we reach this, all volumes (of this tconn) are Secondary,
3383 * Disconnected, Diskless, aka Unconfigured. Make sure all threads have
Philipp Reisnerc141ebd2011-05-05 16:13:10 +02003384 * actually stopped, state handling only does drbd_thread_stop_nowait(). */
Lars Ellenbergf3dfa402011-05-02 10:45:05 +02003385 drbd_thread_stop(&adm_ctx.tconn->worker);
3386
3387 /* Now, nothing can fail anymore */
3388
Lars Ellenberg85f75dd72011-03-15 16:26:37 +01003389 /* delete volumes */
3390 idr_for_each_entry(&adm_ctx.tconn->volumes, mdev, i) {
3391 retcode = adm_delete_minor(mdev);
3392 if (retcode != NO_ERROR) {
3393 /* "can not happen" */
3394 drbd_msg_put_info("failed to delete volume");
Philipp Reisneref356262011-04-13 14:21:29 -07003395 goto out;
Lars Ellenberg85f75dd72011-03-15 16:26:37 +01003396 }
3397 }
3398
Lars Ellenberg85f75dd72011-03-15 16:26:37 +01003399 /* delete connection */
3400 if (conn_lowest_minor(adm_ctx.tconn) < 0) {
Philipp Reisnerec0bddb2011-05-04 15:47:01 +02003401 list_del_rcu(&adm_ctx.tconn->all_tconn);
3402 synchronize_rcu();
Philipp Reisner9dc9fbb2011-04-22 15:23:32 +02003403 kref_put(&adm_ctx.tconn->kref, &conn_destroy);
3404
Lars Ellenberg85f75dd72011-03-15 16:26:37 +01003405 retcode = NO_ERROR;
3406 } else {
3407 /* "can not happen" */
Andreas Gruenbacher789c1b62011-06-06 16:16:44 +02003408 retcode = ERR_RES_IN_USE;
Lars Ellenberg85f75dd72011-03-15 16:26:37 +01003409 drbd_msg_put_info("failed to delete connection");
Lars Ellenberg85f75dd72011-03-15 16:26:37 +01003410 }
Philipp Reisneref356262011-04-13 14:21:29 -07003411 goto out;
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01003412out:
3413 drbd_adm_finish(info, retcode);
Philipp Reisner774b3052011-02-22 02:07:03 -05003414 return 0;
3415}
3416
Andreas Gruenbacher789c1b62011-06-06 16:16:44 +02003417int drbd_adm_del_resource(struct sk_buff *skb, struct genl_info *info)
Philipp Reisner774b3052011-02-22 02:07:03 -05003418{
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01003419 enum drbd_ret_code retcode;
3420
Andreas Gruenbacher44e52cf2011-06-14 16:07:32 +02003421 retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_RESOURCE);
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01003422 if (!adm_ctx.reply_skb)
3423 return retcode;
3424 if (retcode != NO_ERROR)
3425 goto out;
3426
3427 if (conn_lowest_minor(adm_ctx.tconn) < 0) {
Philipp Reisnerec0bddb2011-05-04 15:47:01 +02003428 list_del_rcu(&adm_ctx.tconn->all_tconn);
3429 synchronize_rcu();
Philipp Reisner9dc9fbb2011-04-22 15:23:32 +02003430 kref_put(&adm_ctx.tconn->kref, &conn_destroy);
3431
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01003432 retcode = NO_ERROR;
Philipp Reisner774b3052011-02-22 02:07:03 -05003433 } else {
Andreas Gruenbacher789c1b62011-06-06 16:16:44 +02003434 retcode = ERR_RES_IN_USE;
Philipp Reisner774b3052011-02-22 02:07:03 -05003435 }
3436
Lars Ellenberg992d6e92011-05-02 11:47:18 +02003437 if (retcode == NO_ERROR)
3438 drbd_thread_stop(&adm_ctx.tconn->worker);
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01003439out:
3440 drbd_adm_finish(info, retcode);
Philipp Reisner774b3052011-02-22 02:07:03 -05003441 return 0;
3442}
3443
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01003444void drbd_bcast_event(struct drbd_conf *mdev, const struct sib_info *sib)
Philipp Reisnerb411b362009-09-25 16:07:19 -07003445{
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01003446 static atomic_t drbd_genl_seq = ATOMIC_INIT(2); /* two. */
3447 struct sk_buff *msg;
3448 struct drbd_genlmsghdr *d_out;
3449 unsigned seq;
3450 int err = -ENOMEM;
Philipp Reisnerb411b362009-09-25 16:07:19 -07003451
Philipp Reisneref86b772012-12-06 10:34:34 +01003452 if (sib->sib_reason == SIB_SYNC_PROGRESS) {
3453 if (time_after(jiffies, mdev->rs_last_bcast + HZ))
3454 mdev->rs_last_bcast = jiffies;
3455 else
3456 return;
3457 }
Philipp Reisner328e0f122012-10-19 14:37:47 +02003458
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01003459 seq = atomic_inc_return(&drbd_genl_seq);
3460 msg = genlmsg_new(NLMSG_GOODSIZE, GFP_NOIO);
3461 if (!msg)
3462 goto failed;
Philipp Reisnerb411b362009-09-25 16:07:19 -07003463
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01003464 err = -EMSGSIZE;
3465 d_out = genlmsg_put(msg, 0, seq, &drbd_genl_family, 0, DRBD_EVENT);
3466 if (!d_out) /* cannot happen, but anyways. */
3467 goto nla_put_failure;
3468 d_out->minor = mdev_to_minor(mdev);
Andreas Gruenbacher6f9b5f82011-05-06 01:03:32 +02003469 d_out->ret_code = NO_ERROR;
Philipp Reisnerb411b362009-09-25 16:07:19 -07003470
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01003471 if (nla_put_status_info(msg, mdev, sib))
3472 goto nla_put_failure;
3473 genlmsg_end(msg, d_out);
3474 err = drbd_genl_multicast_events(msg, 0);
3475 /* msg has been consumed or freed in netlink_broadcast() */
3476 if (err && err != -ESRCH)
3477 goto failed;
Philipp Reisnerb411b362009-09-25 16:07:19 -07003478
Philipp Reisnerb411b362009-09-25 16:07:19 -07003479 return;
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01003480
3481nla_put_failure:
3482 nlmsg_free(msg);
3483failed:
3484 dev_err(DEV, "Error %d while broadcasting event. "
3485 "Event seq:%u sib_reason:%u\n",
3486 err, seq, sib->sib_reason);
Philipp Reisnerb411b362009-09-25 16:07:19 -07003487}