blob: 52ebd9a9b03278e913b418e5c0db19c14c11b6d7 [file] [log] [blame]
Philipp Reisnerb8907332011-01-27 14:07:51 +01001/*
2 drbd_state.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 Thanks to Carter Burden, Bart Grantham and Gennadiy Nerubayev
11 from Logicworks, Inc. for making SDP replication support possible.
12
13 drbd is free software; you can redistribute it and/or modify
14 it under the terms of the GNU General Public License as published by
15 the Free Software Foundation; either version 2, or (at your option)
16 any later version.
17
18 drbd is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with drbd; see the file COPYING. If not, write to
25 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
26 */
27
28#include <linux/drbd_limits.h>
29#include "drbd_int.h"
30#include "drbd_req.h"
31
32struct after_state_chg_work {
33 struct drbd_work w;
34 union drbd_state os;
35 union drbd_state ns;
36 enum chg_state_flags flags;
37 struct completion *done;
38};
39
Andreas Gruenbacher99920dc2011-03-16 15:31:39 +010040static int w_after_state_ch(struct drbd_work *w, int unused);
Philipp Reisnerb8907332011-01-27 14:07:51 +010041static void after_state_ch(struct drbd_conf *mdev, union drbd_state os,
42 union drbd_state ns, enum chg_state_flags flags);
Philipp Reisner0e29d162011-02-18 14:23:11 +010043static void after_all_state_ch(struct drbd_tconn *tconn);
Philipp Reisnera75f34a2011-02-09 15:10:33 +010044static enum drbd_state_rv is_valid_state(struct drbd_conf *, union drbd_state);
45static enum drbd_state_rv is_valid_soft_transition(union drbd_state, union drbd_state);
Philipp Reisner35095022011-02-09 16:29:33 +010046static enum drbd_state_rv is_valid_transition(union drbd_state os, union drbd_state ns);
Philipp Reisner4308a0a2011-02-10 11:24:38 +010047static union drbd_state sanitize_state(struct drbd_conf *mdev, union drbd_state ns,
48 const char **warn_sync_abort);
Philipp Reisnerb8907332011-01-27 14:07:51 +010049
Philipp Reisner2aebfab2011-03-28 16:48:11 +020050static inline bool is_susp(union drbd_state s)
51{
52 return s.susp || s.susp_nod || s.susp_fen;
53}
54
Lars Ellenbergd0456c72011-03-10 23:28:13 +010055bool conn_all_vols_unconf(struct drbd_tconn *tconn)
Philipp Reisner0e29d162011-02-18 14:23:11 +010056{
57 struct drbd_conf *mdev;
Philipp Reisner695d08f2011-04-11 22:53:32 -070058 bool rv = true;
Philipp Reisnere90285e2011-03-22 12:51:21 +010059 int vnr;
Philipp Reisner0e29d162011-02-18 14:23:11 +010060
Philipp Reisner695d08f2011-04-11 22:53:32 -070061 rcu_read_lock();
Philipp Reisnere90285e2011-03-22 12:51:21 +010062 idr_for_each_entry(&tconn->volumes, mdev, vnr) {
Lars Ellenbergd0456c72011-03-10 23:28:13 +010063 if (mdev->state.disk != D_DISKLESS ||
64 mdev->state.conn != C_STANDALONE ||
Philipp Reisner695d08f2011-04-11 22:53:32 -070065 mdev->state.role != R_SECONDARY) {
66 rv = false;
67 break;
68 }
Philipp Reisner0e29d162011-02-18 14:23:11 +010069 }
Philipp Reisner695d08f2011-04-11 22:53:32 -070070 rcu_read_unlock();
71
72 return rv;
Philipp Reisner0e29d162011-02-18 14:23:11 +010073}
74
Philipp Reisnercb703452011-03-24 11:03:07 +010075/* Unfortunately the states where not correctly ordered, when
76 they where defined. therefore can not use max_t() here. */
77static enum drbd_role max_role(enum drbd_role role1, enum drbd_role role2)
78{
79 if (role1 == R_PRIMARY || role2 == R_PRIMARY)
80 return R_PRIMARY;
81 if (role1 == R_SECONDARY || role2 == R_SECONDARY)
82 return R_SECONDARY;
83 return R_UNKNOWN;
84}
85static enum drbd_role min_role(enum drbd_role role1, enum drbd_role role2)
86{
87 if (role1 == R_UNKNOWN || role2 == R_UNKNOWN)
88 return R_UNKNOWN;
89 if (role1 == R_SECONDARY || role2 == R_SECONDARY)
90 return R_SECONDARY;
91 return R_PRIMARY;
92}
93
94enum drbd_role conn_highest_role(struct drbd_tconn *tconn)
95{
96 enum drbd_role role = R_UNKNOWN;
97 struct drbd_conf *mdev;
98 int vnr;
99
Philipp Reisner695d08f2011-04-11 22:53:32 -0700100 rcu_read_lock();
Philipp Reisnercb703452011-03-24 11:03:07 +0100101 idr_for_each_entry(&tconn->volumes, mdev, vnr)
102 role = max_role(role, mdev->state.role);
Philipp Reisner695d08f2011-04-11 22:53:32 -0700103 rcu_read_unlock();
Philipp Reisnercb703452011-03-24 11:03:07 +0100104
105 return role;
106}
107
108enum drbd_role conn_highest_peer(struct drbd_tconn *tconn)
109{
110 enum drbd_role peer = R_UNKNOWN;
111 struct drbd_conf *mdev;
112 int vnr;
113
Philipp Reisner695d08f2011-04-11 22:53:32 -0700114 rcu_read_lock();
Philipp Reisnercb703452011-03-24 11:03:07 +0100115 idr_for_each_entry(&tconn->volumes, mdev, vnr)
116 peer = max_role(peer, mdev->state.peer);
Philipp Reisner695d08f2011-04-11 22:53:32 -0700117 rcu_read_unlock();
Philipp Reisnercb703452011-03-24 11:03:07 +0100118
119 return peer;
120}
121
122enum drbd_disk_state conn_highest_disk(struct drbd_tconn *tconn)
123{
124 enum drbd_disk_state ds = D_DISKLESS;
125 struct drbd_conf *mdev;
126 int vnr;
127
Philipp Reisner695d08f2011-04-11 22:53:32 -0700128 rcu_read_lock();
Philipp Reisnercb703452011-03-24 11:03:07 +0100129 idr_for_each_entry(&tconn->volumes, mdev, vnr)
130 ds = max_t(enum drbd_disk_state, ds, mdev->state.disk);
Philipp Reisner695d08f2011-04-11 22:53:32 -0700131 rcu_read_unlock();
Philipp Reisnercb703452011-03-24 11:03:07 +0100132
133 return ds;
134}
135
Philipp Reisner46692652011-03-29 18:15:49 +0200136enum drbd_disk_state conn_lowest_disk(struct drbd_tconn *tconn)
137{
138 enum drbd_disk_state ds = D_MASK;
139 struct drbd_conf *mdev;
140 int vnr;
141
Philipp Reisner695d08f2011-04-11 22:53:32 -0700142 rcu_read_lock();
Philipp Reisner46692652011-03-29 18:15:49 +0200143 idr_for_each_entry(&tconn->volumes, mdev, vnr)
144 ds = min_t(enum drbd_disk_state, ds, mdev->state.disk);
Philipp Reisner695d08f2011-04-11 22:53:32 -0700145 rcu_read_unlock();
Philipp Reisner46692652011-03-29 18:15:49 +0200146
147 return ds;
148}
149
Philipp Reisnercb703452011-03-24 11:03:07 +0100150enum drbd_disk_state conn_highest_pdsk(struct drbd_tconn *tconn)
151{
152 enum drbd_disk_state ds = D_DISKLESS;
153 struct drbd_conf *mdev;
154 int vnr;
155
Philipp Reisner695d08f2011-04-11 22:53:32 -0700156 rcu_read_lock();
Philipp Reisnercb703452011-03-24 11:03:07 +0100157 idr_for_each_entry(&tconn->volumes, mdev, vnr)
158 ds = max_t(enum drbd_disk_state, ds, mdev->state.pdsk);
Philipp Reisner695d08f2011-04-11 22:53:32 -0700159 rcu_read_unlock();
Philipp Reisnercb703452011-03-24 11:03:07 +0100160
161 return ds;
162}
163
Philipp Reisner19f83c72011-03-29 14:21:03 +0200164enum drbd_conns conn_lowest_conn(struct drbd_tconn *tconn)
165{
166 enum drbd_conns conn = C_MASK;
167 struct drbd_conf *mdev;
168 int vnr;
169
Philipp Reisner695d08f2011-04-11 22:53:32 -0700170 rcu_read_lock();
Philipp Reisner19f83c72011-03-29 14:21:03 +0200171 idr_for_each_entry(&tconn->volumes, mdev, vnr)
172 conn = min_t(enum drbd_conns, conn, mdev->state.conn);
Philipp Reisner695d08f2011-04-11 22:53:32 -0700173 rcu_read_unlock();
Philipp Reisner19f83c72011-03-29 14:21:03 +0200174
175 return conn;
176}
177
Philipp Reisnerb8907332011-01-27 14:07:51 +0100178/**
179 * cl_wide_st_chg() - true if the state change is a cluster wide one
180 * @mdev: DRBD device.
181 * @os: old (current) state.
182 * @ns: new (wanted) state.
183 */
184static int cl_wide_st_chg(struct drbd_conf *mdev,
185 union drbd_state os, union drbd_state ns)
186{
187 return (os.conn >= C_CONNECTED && ns.conn >= C_CONNECTED &&
188 ((os.role != R_PRIMARY && ns.role == R_PRIMARY) ||
189 (os.conn != C_STARTING_SYNC_T && ns.conn == C_STARTING_SYNC_T) ||
190 (os.conn != C_STARTING_SYNC_S && ns.conn == C_STARTING_SYNC_S) ||
191 (os.disk != D_DISKLESS && ns.disk == D_DISKLESS))) ||
192 (os.conn >= C_CONNECTED && ns.conn == C_DISCONNECTING) ||
193 (os.conn == C_CONNECTED && ns.conn == C_VERIFY_S);
194}
195
Philipp Reisner56707f92011-02-16 14:57:50 +0100196static union drbd_state
197apply_mask_val(union drbd_state os, union drbd_state mask, union drbd_state val)
198{
199 union drbd_state ns;
200 ns.i = (os.i & ~mask.i) | val.i;
201 return ns;
202}
203
Philipp Reisnerb8907332011-01-27 14:07:51 +0100204enum drbd_state_rv
205drbd_change_state(struct drbd_conf *mdev, enum chg_state_flags f,
206 union drbd_state mask, union drbd_state val)
207{
208 unsigned long flags;
Philipp Reisner56707f92011-02-16 14:57:50 +0100209 union drbd_state ns;
Philipp Reisnerb8907332011-01-27 14:07:51 +0100210 enum drbd_state_rv rv;
211
212 spin_lock_irqsave(&mdev->tconn->req_lock, flags);
Philipp Reisner78bae592011-03-28 15:40:12 +0200213 ns = apply_mask_val(drbd_read_state(mdev), mask, val);
Philipp Reisnerb8907332011-01-27 14:07:51 +0100214 rv = _drbd_set_state(mdev, ns, f, NULL);
Philipp Reisnerb8907332011-01-27 14:07:51 +0100215 spin_unlock_irqrestore(&mdev->tconn->req_lock, flags);
216
217 return rv;
218}
219
220/**
221 * drbd_force_state() - Impose a change which happens outside our control on our state
222 * @mdev: DRBD device.
223 * @mask: mask of state bits to change.
224 * @val: value of new state bits.
225 */
226void drbd_force_state(struct drbd_conf *mdev,
227 union drbd_state mask, union drbd_state val)
228{
229 drbd_change_state(mdev, CS_HARD, mask, val);
230}
231
232static enum drbd_state_rv
233_req_st_cond(struct drbd_conf *mdev, union drbd_state mask,
234 union drbd_state val)
235{
236 union drbd_state os, ns;
237 unsigned long flags;
238 enum drbd_state_rv rv;
239
240 if (test_and_clear_bit(CL_ST_CHG_SUCCESS, &mdev->flags))
241 return SS_CW_SUCCESS;
242
243 if (test_and_clear_bit(CL_ST_CHG_FAIL, &mdev->flags))
244 return SS_CW_FAILED_BY_PEER;
245
Philipp Reisnerb8907332011-01-27 14:07:51 +0100246 spin_lock_irqsave(&mdev->tconn->req_lock, flags);
Philipp Reisner78bae592011-03-28 15:40:12 +0200247 os = drbd_read_state(mdev);
Philipp Reisner56707f92011-02-16 14:57:50 +0100248 ns = sanitize_state(mdev, apply_mask_val(os, mask, val), NULL);
Philipp Reisner35095022011-02-09 16:29:33 +0100249 rv = is_valid_transition(os, ns);
250 if (rv == SS_SUCCESS)
251 rv = SS_UNKNOWN_ERROR; /* cont waiting, otherwise fail. */
Philipp Reisnerb8907332011-01-27 14:07:51 +0100252
253 if (!cl_wide_st_chg(mdev, os, ns))
254 rv = SS_CW_NO_NEED;
Philipp Reisner35095022011-02-09 16:29:33 +0100255 if (rv == SS_UNKNOWN_ERROR) {
Philipp Reisnerb8907332011-01-27 14:07:51 +0100256 rv = is_valid_state(mdev, ns);
257 if (rv == SS_SUCCESS) {
Philipp Reisnera75f34a2011-02-09 15:10:33 +0100258 rv = is_valid_soft_transition(os, ns);
Philipp Reisnerb8907332011-01-27 14:07:51 +0100259 if (rv == SS_SUCCESS)
260 rv = SS_UNKNOWN_ERROR; /* cont waiting, otherwise fail. */
261 }
262 }
263 spin_unlock_irqrestore(&mdev->tconn->req_lock, flags);
264
265 return rv;
266}
267
268/**
269 * drbd_req_state() - Perform an eventually cluster wide state change
270 * @mdev: DRBD device.
271 * @mask: mask of state bits to change.
272 * @val: value of new state bits.
273 * @f: flags
274 *
275 * Should not be called directly, use drbd_request_state() or
276 * _drbd_request_state().
277 */
278static enum drbd_state_rv
279drbd_req_state(struct drbd_conf *mdev, union drbd_state mask,
280 union drbd_state val, enum chg_state_flags f)
281{
282 struct completion done;
283 unsigned long flags;
284 union drbd_state os, ns;
285 enum drbd_state_rv rv;
286
287 init_completion(&done);
288
289 if (f & CS_SERIALIZE)
Philipp Reisner8410da82011-02-11 20:11:10 +0100290 mutex_lock(mdev->state_mutex);
Philipp Reisnerb8907332011-01-27 14:07:51 +0100291
292 spin_lock_irqsave(&mdev->tconn->req_lock, flags);
Philipp Reisner78bae592011-03-28 15:40:12 +0200293 os = drbd_read_state(mdev);
Philipp Reisner56707f92011-02-16 14:57:50 +0100294 ns = sanitize_state(mdev, apply_mask_val(os, mask, val), NULL);
Philipp Reisner35095022011-02-09 16:29:33 +0100295 rv = is_valid_transition(os, ns);
Lars Ellenberg3c5e5f62011-03-15 16:04:09 +0100296 if (rv < SS_SUCCESS) {
297 spin_unlock_irqrestore(&mdev->tconn->req_lock, flags);
Philipp Reisner35095022011-02-09 16:29:33 +0100298 goto abort;
Lars Ellenberg3c5e5f62011-03-15 16:04:09 +0100299 }
Philipp Reisnerb8907332011-01-27 14:07:51 +0100300
301 if (cl_wide_st_chg(mdev, os, ns)) {
302 rv = is_valid_state(mdev, ns);
303 if (rv == SS_SUCCESS)
Philipp Reisnera75f34a2011-02-09 15:10:33 +0100304 rv = is_valid_soft_transition(os, ns);
Philipp Reisnerb8907332011-01-27 14:07:51 +0100305 spin_unlock_irqrestore(&mdev->tconn->req_lock, flags);
306
307 if (rv < SS_SUCCESS) {
308 if (f & CS_VERBOSE)
309 print_st_err(mdev, os, ns, rv);
310 goto abort;
311 }
312
Andreas Gruenbacherd24ae212011-03-16 01:19:27 +0100313 if (drbd_send_state_req(mdev, mask, val)) {
Philipp Reisnerb8907332011-01-27 14:07:51 +0100314 rv = SS_CW_FAILED_BY_PEER;
315 if (f & CS_VERBOSE)
316 print_st_err(mdev, os, ns, rv);
317 goto abort;
318 }
319
320 wait_event(mdev->state_wait,
321 (rv = _req_st_cond(mdev, mask, val)));
322
323 if (rv < SS_SUCCESS) {
Philipp Reisnerb8907332011-01-27 14:07:51 +0100324 if (f & CS_VERBOSE)
325 print_st_err(mdev, os, ns, rv);
326 goto abort;
327 }
328 spin_lock_irqsave(&mdev->tconn->req_lock, flags);
Philipp Reisner78bae592011-03-28 15:40:12 +0200329 ns = apply_mask_val(drbd_read_state(mdev), mask, val);
Philipp Reisnerb8907332011-01-27 14:07:51 +0100330 rv = _drbd_set_state(mdev, ns, f, &done);
Philipp Reisnerb8907332011-01-27 14:07:51 +0100331 } else {
332 rv = _drbd_set_state(mdev, ns, f, &done);
333 }
334
335 spin_unlock_irqrestore(&mdev->tconn->req_lock, flags);
336
337 if (f & CS_WAIT_COMPLETE && rv == SS_SUCCESS) {
338 D_ASSERT(current != mdev->tconn->worker.task);
339 wait_for_completion(&done);
340 }
341
342abort:
343 if (f & CS_SERIALIZE)
Philipp Reisner8410da82011-02-11 20:11:10 +0100344 mutex_unlock(mdev->state_mutex);
Philipp Reisnerb8907332011-01-27 14:07:51 +0100345
346 return rv;
347}
348
349/**
350 * _drbd_request_state() - Request a state change (with flags)
351 * @mdev: DRBD device.
352 * @mask: mask of state bits to change.
353 * @val: value of new state bits.
354 * @f: flags
355 *
356 * Cousin of drbd_request_state(), useful with the CS_WAIT_COMPLETE
357 * flag, or when logging of failed state change requests is not desired.
358 */
359enum drbd_state_rv
360_drbd_request_state(struct drbd_conf *mdev, union drbd_state mask,
361 union drbd_state val, enum chg_state_flags f)
362{
363 enum drbd_state_rv rv;
364
365 wait_event(mdev->state_wait,
366 (rv = drbd_req_state(mdev, mask, val, f)) != SS_IN_TRANSIENT_STATE);
367
368 return rv;
369}
370
371static void print_st(struct drbd_conf *mdev, char *name, union drbd_state ns)
372{
373 dev_err(DEV, " %s = { cs:%s ro:%s/%s ds:%s/%s %c%c%c%c%c%c }\n",
374 name,
375 drbd_conn_str(ns.conn),
376 drbd_role_str(ns.role),
377 drbd_role_str(ns.peer),
378 drbd_disk_str(ns.disk),
379 drbd_disk_str(ns.pdsk),
380 is_susp(ns) ? 's' : 'r',
381 ns.aftr_isp ? 'a' : '-',
382 ns.peer_isp ? 'p' : '-',
383 ns.user_isp ? 'u' : '-',
384 ns.susp_fen ? 'F' : '-',
385 ns.susp_nod ? 'N' : '-'
386 );
387}
388
389void print_st_err(struct drbd_conf *mdev, union drbd_state os,
390 union drbd_state ns, enum drbd_state_rv err)
391{
392 if (err == SS_IN_TRANSIENT_STATE)
393 return;
394 dev_err(DEV, "State change failed: %s\n", drbd_set_st_err_str(err));
395 print_st(mdev, " state", os);
396 print_st(mdev, "wanted", ns);
397}
398
Philipp Reisner435693e2011-03-25 15:11:30 +0100399static long print_state_change(char *pb, union drbd_state os, union drbd_state ns,
Philipp Reisnerbbeb6412011-02-10 13:45:46 +0100400 enum chg_state_flags flags)
401{
Philipp Reisner435693e2011-03-25 15:11:30 +0100402 char *pbp;
Philipp Reisnerbbeb6412011-02-10 13:45:46 +0100403 pbp = pb;
404 *pbp = 0;
Philipp Reisner706cb242011-03-29 15:20:27 +0200405
Philipp Reisner435693e2011-03-25 15:11:30 +0100406 if (ns.role != os.role && flags & CS_DC_ROLE)
Philipp Reisnerbbeb6412011-02-10 13:45:46 +0100407 pbp += sprintf(pbp, "role( %s -> %s ) ",
408 drbd_role_str(os.role),
409 drbd_role_str(ns.role));
Philipp Reisner435693e2011-03-25 15:11:30 +0100410 if (ns.peer != os.peer && flags & CS_DC_PEER)
Philipp Reisnerbbeb6412011-02-10 13:45:46 +0100411 pbp += sprintf(pbp, "peer( %s -> %s ) ",
412 drbd_role_str(os.peer),
413 drbd_role_str(ns.peer));
Philipp Reisner435693e2011-03-25 15:11:30 +0100414 if (ns.conn != os.conn && flags & CS_DC_CONN)
Philipp Reisnerbbeb6412011-02-10 13:45:46 +0100415 pbp += sprintf(pbp, "conn( %s -> %s ) ",
416 drbd_conn_str(os.conn),
417 drbd_conn_str(ns.conn));
Philipp Reisner435693e2011-03-25 15:11:30 +0100418 if (ns.disk != os.disk && flags & CS_DC_DISK)
Philipp Reisnerbbeb6412011-02-10 13:45:46 +0100419 pbp += sprintf(pbp, "disk( %s -> %s ) ",
420 drbd_disk_str(os.disk),
421 drbd_disk_str(ns.disk));
Philipp Reisner435693e2011-03-25 15:11:30 +0100422 if (ns.pdsk != os.pdsk && flags & CS_DC_PDSK)
Philipp Reisnerbbeb6412011-02-10 13:45:46 +0100423 pbp += sprintf(pbp, "pdsk( %s -> %s ) ",
424 drbd_disk_str(os.pdsk),
425 drbd_disk_str(ns.pdsk));
Philipp Reisner706cb242011-03-29 15:20:27 +0200426
427 return pbp - pb;
428}
429
430static void drbd_pr_state_change(struct drbd_conf *mdev, union drbd_state os, union drbd_state ns,
431 enum chg_state_flags flags)
432{
433 char pb[300];
434 char *pbp = pb;
435
436 pbp += print_state_change(pbp, os, ns, flags ^ CS_DC_MASK);
437
Philipp Reisnerbbeb6412011-02-10 13:45:46 +0100438 if (ns.aftr_isp != os.aftr_isp)
439 pbp += sprintf(pbp, "aftr_isp( %d -> %d ) ",
440 os.aftr_isp,
441 ns.aftr_isp);
442 if (ns.peer_isp != os.peer_isp)
443 pbp += sprintf(pbp, "peer_isp( %d -> %d ) ",
444 os.peer_isp,
445 ns.peer_isp);
446 if (ns.user_isp != os.user_isp)
447 pbp += sprintf(pbp, "user_isp( %d -> %d ) ",
448 os.user_isp,
449 ns.user_isp);
Philipp Reisner435693e2011-03-25 15:11:30 +0100450
Philipp Reisner706cb242011-03-29 15:20:27 +0200451 if (pbp != pb)
Philipp Reisnerbbeb6412011-02-10 13:45:46 +0100452 dev_info(DEV, "%s\n", pb);
453}
Philipp Reisnerb8907332011-01-27 14:07:51 +0100454
Philipp Reisner435693e2011-03-25 15:11:30 +0100455static void conn_pr_state_change(struct drbd_tconn *tconn, union drbd_state os, union drbd_state ns,
456 enum chg_state_flags flags)
457{
458 char pb[300];
Philipp Reisner706cb242011-03-29 15:20:27 +0200459 char *pbp = pb;
Philipp Reisner435693e2011-03-25 15:11:30 +0100460
Philipp Reisner706cb242011-03-29 15:20:27 +0200461 pbp += print_state_change(pbp, os, ns, flags);
462
463 if (is_susp(ns) != is_susp(os) && flags & CS_DC_SUSP)
464 pbp += sprintf(pbp, "susp( %d -> %d ) ",
465 is_susp(os),
466 is_susp(ns));
467
468 if (pbp != pb)
Philipp Reisner435693e2011-03-25 15:11:30 +0100469 conn_info(tconn, "%s\n", pb);
470}
471
472
Philipp Reisnerb8907332011-01-27 14:07:51 +0100473/**
474 * is_valid_state() - Returns an SS_ error code if ns is not valid
475 * @mdev: DRBD device.
476 * @ns: State to consider.
477 */
478static enum drbd_state_rv
479is_valid_state(struct drbd_conf *mdev, union drbd_state ns)
480{
481 /* See drbd_state_sw_errors in drbd_strings.c */
482
483 enum drbd_fencing_p fp;
484 enum drbd_state_rv rv = SS_SUCCESS;
485
486 fp = FP_DONT_CARE;
487 if (get_ldev(mdev)) {
488 fp = mdev->ldev->dc.fencing;
489 put_ldev(mdev);
490 }
491
492 if (get_net_conf(mdev->tconn)) {
Philipp Reisner047e95e22011-03-16 14:43:36 +0100493 if (!mdev->tconn->net_conf->two_primaries && ns.role == R_PRIMARY) {
494 if (ns.peer == R_PRIMARY)
495 rv = SS_TWO_PRIMARIES;
Philipp Reisnercb703452011-03-24 11:03:07 +0100496 else if (conn_highest_peer(mdev->tconn) == R_PRIMARY)
Philipp Reisner047e95e22011-03-16 14:43:36 +0100497 rv = SS_O_VOL_PEER_PRI;
498 }
Philipp Reisnerb8907332011-01-27 14:07:51 +0100499 put_net_conf(mdev->tconn);
500 }
501
502 if (rv <= 0)
503 /* already found a reason to abort */;
504 else if (ns.role == R_SECONDARY && mdev->open_cnt)
505 rv = SS_DEVICE_IN_USE;
506
507 else if (ns.role == R_PRIMARY && ns.conn < C_CONNECTED && ns.disk < D_UP_TO_DATE)
508 rv = SS_NO_UP_TO_DATE_DISK;
509
510 else if (fp >= FP_RESOURCE &&
511 ns.role == R_PRIMARY && ns.conn < C_CONNECTED && ns.pdsk >= D_UNKNOWN)
512 rv = SS_PRIMARY_NOP;
513
514 else if (ns.role == R_PRIMARY && ns.disk <= D_INCONSISTENT && ns.pdsk <= D_INCONSISTENT)
515 rv = SS_NO_UP_TO_DATE_DISK;
516
517 else if (ns.conn > C_CONNECTED && ns.disk < D_INCONSISTENT)
518 rv = SS_NO_LOCAL_DISK;
519
520 else if (ns.conn > C_CONNECTED && ns.pdsk < D_INCONSISTENT)
521 rv = SS_NO_REMOTE_DISK;
522
523 else if (ns.conn > C_CONNECTED && ns.disk < D_UP_TO_DATE && ns.pdsk < D_UP_TO_DATE)
524 rv = SS_NO_UP_TO_DATE_DISK;
525
526 else if ((ns.conn == C_CONNECTED ||
527 ns.conn == C_WF_BITMAP_S ||
528 ns.conn == C_SYNC_SOURCE ||
529 ns.conn == C_PAUSED_SYNC_S) &&
530 ns.disk == D_OUTDATED)
531 rv = SS_CONNECTED_OUTDATES;
532
533 else if ((ns.conn == C_VERIFY_S || ns.conn == C_VERIFY_T) &&
Lars Ellenbergf3990022011-03-23 14:31:09 +0100534 (mdev->tconn->net_conf->verify_alg[0] == 0))
Philipp Reisnerb8907332011-01-27 14:07:51 +0100535 rv = SS_NO_VERIFY_ALG;
536
537 else if ((ns.conn == C_VERIFY_S || ns.conn == C_VERIFY_T) &&
538 mdev->tconn->agreed_pro_version < 88)
539 rv = SS_NOT_SUPPORTED;
540
541 else if (ns.conn >= C_CONNECTED && ns.pdsk == D_UNKNOWN)
542 rv = SS_CONNECTED_OUTDATES;
543
544 return rv;
545}
546
547/**
Philipp Reisnera75f34a2011-02-09 15:10:33 +0100548 * is_valid_soft_transition() - Returns an SS_ error code if the state transition is not possible
Philipp Reisner35095022011-02-09 16:29:33 +0100549 * This function limits state transitions that may be declined by DRBD. I.e.
550 * user requests (aka soft transitions).
Philipp Reisnerb8907332011-01-27 14:07:51 +0100551 * @mdev: DRBD device.
552 * @ns: new state.
553 * @os: old state.
554 */
555static enum drbd_state_rv
Philipp Reisnera75f34a2011-02-09 15:10:33 +0100556is_valid_soft_transition(union drbd_state os, union drbd_state ns)
Philipp Reisnerb8907332011-01-27 14:07:51 +0100557{
558 enum drbd_state_rv rv = SS_SUCCESS;
559
560 if ((ns.conn == C_STARTING_SYNC_T || ns.conn == C_STARTING_SYNC_S) &&
561 os.conn > C_CONNECTED)
562 rv = SS_RESYNC_RUNNING;
563
564 if (ns.conn == C_DISCONNECTING && os.conn == C_STANDALONE)
565 rv = SS_ALREADY_STANDALONE;
566
567 if (ns.disk > D_ATTACHING && os.disk == D_DISKLESS)
568 rv = SS_IS_DISKLESS;
569
570 if (ns.conn == C_WF_CONNECTION && os.conn < C_UNCONNECTED)
571 rv = SS_NO_NET_CONFIG;
572
573 if (ns.disk == D_OUTDATED && os.disk < D_OUTDATED && os.disk != D_ATTACHING)
574 rv = SS_LOWER_THAN_OUTDATED;
575
576 if (ns.conn == C_DISCONNECTING && os.conn == C_UNCONNECTED)
577 rv = SS_IN_TRANSIENT_STATE;
578
Philipp Reisner2325eb62011-03-15 16:56:18 +0100579 /* if (ns.conn == os.conn && ns.conn == C_WF_REPORT_PARAMS)
580 rv = SS_IN_TRANSIENT_STATE; */
Philipp Reisnerb8907332011-01-27 14:07:51 +0100581
582 if ((ns.conn == C_VERIFY_S || ns.conn == C_VERIFY_T) && os.conn < C_CONNECTED)
583 rv = SS_NEED_CONNECTION;
584
585 if ((ns.conn == C_VERIFY_S || ns.conn == C_VERIFY_T) &&
586 ns.conn != os.conn && os.conn > C_CONNECTED)
587 rv = SS_RESYNC_RUNNING;
588
589 if ((ns.conn == C_STARTING_SYNC_S || ns.conn == C_STARTING_SYNC_T) &&
590 os.conn < C_CONNECTED)
591 rv = SS_NEED_CONNECTION;
592
593 if ((ns.conn == C_SYNC_TARGET || ns.conn == C_SYNC_SOURCE)
594 && os.conn < C_WF_REPORT_PARAMS)
595 rv = SS_NEED_CONNECTION; /* No NetworkFailure -> SyncTarget etc... */
596
597 return rv;
598}
599
Philipp Reisnerfda74112011-02-10 10:38:06 +0100600static enum drbd_state_rv
601is_valid_conn_transition(enum drbd_conns oc, enum drbd_conns nc)
602{
603 enum drbd_state_rv rv = SS_SUCCESS;
604
605 /* Disallow Network errors to configure a device's network part */
606 if ((nc >= C_TIMEOUT && nc <= C_TEAR_DOWN) && oc <= C_DISCONNECTING)
607 rv = SS_NEED_CONNECTION;
608
609 /* After a network error only C_UNCONNECTED or C_DISCONNECTING may follow. */
610 if (oc >= C_TIMEOUT && oc <= C_TEAR_DOWN && nc != C_UNCONNECTED && nc != C_DISCONNECTING)
611 rv = SS_IN_TRANSIENT_STATE;
612
613 /* After C_DISCONNECTING only C_STANDALONE may follow */
614 if (oc == C_DISCONNECTING && nc != C_STANDALONE)
615 rv = SS_IN_TRANSIENT_STATE;
616
617 return rv;
618}
619
620
Philipp Reisnerb8907332011-01-27 14:07:51 +0100621/**
Philipp Reisner35095022011-02-09 16:29:33 +0100622 * is_valid_transition() - Returns an SS_ error code if the state transition is not possible
623 * This limits hard state transitions. Hard state transitions are facts there are
624 * imposed on DRBD by the environment. E.g. disk broke or network broke down.
625 * But those hard state transitions are still not allowed to do everything.
626 * @ns: new state.
627 * @os: old state.
628 */
629static enum drbd_state_rv
630is_valid_transition(union drbd_state os, union drbd_state ns)
631{
Philipp Reisnerfda74112011-02-10 10:38:06 +0100632 enum drbd_state_rv rv;
Philipp Reisner35095022011-02-09 16:29:33 +0100633
Philipp Reisnerfda74112011-02-10 10:38:06 +0100634 rv = is_valid_conn_transition(os.conn, ns.conn);
Philipp Reisner35095022011-02-09 16:29:33 +0100635
636 /* we cannot fail (again) if we already detached */
637 if (ns.disk == D_FAILED && os.disk == D_DISKLESS)
638 rv = SS_IS_DISKLESS;
639
Philipp Reisner4308a0a2011-02-10 11:24:38 +0100640 /* if we are only D_ATTACHING yet,
641 * we can (and should) go directly to D_DISKLESS. */
642 if (ns.disk == D_FAILED && os.disk == D_ATTACHING) {
643 printk("TODO: FIX ME\n");
644 rv = SS_IS_DISKLESS;
645 }
646
Philipp Reisner35095022011-02-09 16:29:33 +0100647 return rv;
648}
649
650/**
Philipp Reisnerb8907332011-01-27 14:07:51 +0100651 * sanitize_state() - Resolves implicitly necessary additional changes to a state transition
652 * @mdev: DRBD device.
653 * @os: old state.
654 * @ns: new state.
655 * @warn_sync_abort:
656 *
657 * When we loose connection, we have to set the state of the peers disk (pdsk)
658 * to D_UNKNOWN. This rule and many more along those lines are in this function.
659 */
Philipp Reisner4308a0a2011-02-10 11:24:38 +0100660static union drbd_state sanitize_state(struct drbd_conf *mdev, union drbd_state ns,
661 const char **warn_sync_abort)
Philipp Reisnerb8907332011-01-27 14:07:51 +0100662{
663 enum drbd_fencing_p fp;
664 enum drbd_disk_state disk_min, disk_max, pdsk_min, pdsk_max;
665
666 fp = FP_DONT_CARE;
667 if (get_ldev(mdev)) {
668 fp = mdev->ldev->dc.fencing;
669 put_ldev(mdev);
670 }
671
Philipp Reisner35095022011-02-09 16:29:33 +0100672 /* Implications from connection to peer and peer_isp */
Philipp Reisnerb8907332011-01-27 14:07:51 +0100673 if (ns.conn < C_CONNECTED) {
674 ns.peer_isp = 0;
675 ns.peer = R_UNKNOWN;
676 if (ns.pdsk > D_UNKNOWN || ns.pdsk < D_INCONSISTENT)
677 ns.pdsk = D_UNKNOWN;
678 }
679
680 /* Clear the aftr_isp when becoming unconfigured */
681 if (ns.conn == C_STANDALONE && ns.disk == D_DISKLESS && ns.role == R_SECONDARY)
682 ns.aftr_isp = 0;
683
Philipp Reisner4308a0a2011-02-10 11:24:38 +0100684 /* An implication of the disk states onto the connection state */
Philipp Reisnerb8907332011-01-27 14:07:51 +0100685 /* Abort resync if a disk fails/detaches */
Philipp Reisner4308a0a2011-02-10 11:24:38 +0100686 if (ns.conn > C_CONNECTED && (ns.disk <= D_FAILED || ns.pdsk <= D_FAILED)) {
Philipp Reisnerb8907332011-01-27 14:07:51 +0100687 if (warn_sync_abort)
688 *warn_sync_abort =
Philipp Reisner4308a0a2011-02-10 11:24:38 +0100689 ns.conn == C_VERIFY_S || ns.conn == C_VERIFY_T ?
Philipp Reisnerb8907332011-01-27 14:07:51 +0100690 "Online-verify" : "Resync";
691 ns.conn = C_CONNECTED;
692 }
693
694 /* Connection breaks down before we finished "Negotiating" */
695 if (ns.conn < C_CONNECTED && ns.disk == D_NEGOTIATING &&
696 get_ldev_if_state(mdev, D_NEGOTIATING)) {
697 if (mdev->ed_uuid == mdev->ldev->md.uuid[UI_CURRENT]) {
698 ns.disk = mdev->new_state_tmp.disk;
699 ns.pdsk = mdev->new_state_tmp.pdsk;
700 } else {
701 dev_alert(DEV, "Connection lost while negotiating, no data!\n");
702 ns.disk = D_DISKLESS;
703 ns.pdsk = D_UNKNOWN;
704 }
705 put_ldev(mdev);
706 }
707
708 /* D_CONSISTENT and D_OUTDATED vanish when we get connected */
709 if (ns.conn >= C_CONNECTED && ns.conn < C_AHEAD) {
710 if (ns.disk == D_CONSISTENT || ns.disk == D_OUTDATED)
711 ns.disk = D_UP_TO_DATE;
712 if (ns.pdsk == D_CONSISTENT || ns.pdsk == D_OUTDATED)
713 ns.pdsk = D_UP_TO_DATE;
714 }
715
716 /* Implications of the connection stat on the disk states */
717 disk_min = D_DISKLESS;
718 disk_max = D_UP_TO_DATE;
719 pdsk_min = D_INCONSISTENT;
720 pdsk_max = D_UNKNOWN;
721 switch ((enum drbd_conns)ns.conn) {
722 case C_WF_BITMAP_T:
723 case C_PAUSED_SYNC_T:
724 case C_STARTING_SYNC_T:
725 case C_WF_SYNC_UUID:
726 case C_BEHIND:
727 disk_min = D_INCONSISTENT;
728 disk_max = D_OUTDATED;
729 pdsk_min = D_UP_TO_DATE;
730 pdsk_max = D_UP_TO_DATE;
731 break;
732 case C_VERIFY_S:
733 case C_VERIFY_T:
734 disk_min = D_UP_TO_DATE;
735 disk_max = D_UP_TO_DATE;
736 pdsk_min = D_UP_TO_DATE;
737 pdsk_max = D_UP_TO_DATE;
738 break;
739 case C_CONNECTED:
740 disk_min = D_DISKLESS;
741 disk_max = D_UP_TO_DATE;
742 pdsk_min = D_DISKLESS;
743 pdsk_max = D_UP_TO_DATE;
744 break;
745 case C_WF_BITMAP_S:
746 case C_PAUSED_SYNC_S:
747 case C_STARTING_SYNC_S:
748 case C_AHEAD:
749 disk_min = D_UP_TO_DATE;
750 disk_max = D_UP_TO_DATE;
751 pdsk_min = D_INCONSISTENT;
752 pdsk_max = D_CONSISTENT; /* D_OUTDATED would be nice. But explicit outdate necessary*/
753 break;
754 case C_SYNC_TARGET:
755 disk_min = D_INCONSISTENT;
756 disk_max = D_INCONSISTENT;
757 pdsk_min = D_UP_TO_DATE;
758 pdsk_max = D_UP_TO_DATE;
759 break;
760 case C_SYNC_SOURCE:
761 disk_min = D_UP_TO_DATE;
762 disk_max = D_UP_TO_DATE;
763 pdsk_min = D_INCONSISTENT;
764 pdsk_max = D_INCONSISTENT;
765 break;
766 case C_STANDALONE:
767 case C_DISCONNECTING:
768 case C_UNCONNECTED:
769 case C_TIMEOUT:
770 case C_BROKEN_PIPE:
771 case C_NETWORK_FAILURE:
772 case C_PROTOCOL_ERROR:
773 case C_TEAR_DOWN:
774 case C_WF_CONNECTION:
775 case C_WF_REPORT_PARAMS:
776 case C_MASK:
777 break;
778 }
779 if (ns.disk > disk_max)
780 ns.disk = disk_max;
781
782 if (ns.disk < disk_min) {
783 dev_warn(DEV, "Implicitly set disk from %s to %s\n",
784 drbd_disk_str(ns.disk), drbd_disk_str(disk_min));
785 ns.disk = disk_min;
786 }
787 if (ns.pdsk > pdsk_max)
788 ns.pdsk = pdsk_max;
789
790 if (ns.pdsk < pdsk_min) {
791 dev_warn(DEV, "Implicitly set pdsk from %s to %s\n",
792 drbd_disk_str(ns.pdsk), drbd_disk_str(pdsk_min));
793 ns.pdsk = pdsk_min;
794 }
795
796 if (fp == FP_STONITH &&
Philipp Reisner4308a0a2011-02-10 11:24:38 +0100797 (ns.role == R_PRIMARY && ns.conn < C_CONNECTED && ns.pdsk > D_OUTDATED))
Philipp Reisnerb8907332011-01-27 14:07:51 +0100798 ns.susp_fen = 1; /* Suspend IO while fence-peer handler runs (peer lost) */
799
Lars Ellenbergf3990022011-03-23 14:31:09 +0100800 if (mdev->tconn->res_opts.on_no_data == OND_SUSPEND_IO &&
Philipp Reisner4308a0a2011-02-10 11:24:38 +0100801 (ns.role == R_PRIMARY && ns.disk < D_UP_TO_DATE && ns.pdsk < D_UP_TO_DATE))
Philipp Reisnerb8907332011-01-27 14:07:51 +0100802 ns.susp_nod = 1; /* Suspend IO while no data available (no accessible data available) */
803
804 if (ns.aftr_isp || ns.peer_isp || ns.user_isp) {
805 if (ns.conn == C_SYNC_SOURCE)
806 ns.conn = C_PAUSED_SYNC_S;
807 if (ns.conn == C_SYNC_TARGET)
808 ns.conn = C_PAUSED_SYNC_T;
809 } else {
810 if (ns.conn == C_PAUSED_SYNC_S)
811 ns.conn = C_SYNC_SOURCE;
812 if (ns.conn == C_PAUSED_SYNC_T)
813 ns.conn = C_SYNC_TARGET;
814 }
815
816 return ns;
817}
818
819void drbd_resume_al(struct drbd_conf *mdev)
820{
821 if (test_and_clear_bit(AL_SUSPENDED, &mdev->flags))
822 dev_info(DEV, "Resumed AL updates\n");
823}
824
825/* helper for __drbd_set_state */
826static void set_ov_position(struct drbd_conf *mdev, enum drbd_conns cs)
827{
828 if (mdev->tconn->agreed_pro_version < 90)
829 mdev->ov_start_sector = 0;
830 mdev->rs_total = drbd_bm_bits(mdev);
831 mdev->ov_position = 0;
832 if (cs == C_VERIFY_T) {
833 /* starting online verify from an arbitrary position
834 * does not fit well into the existing protocol.
835 * on C_VERIFY_T, we initialize ov_left and friends
836 * implicitly in receive_DataRequest once the
837 * first P_OV_REQUEST is received */
838 mdev->ov_start_sector = ~(sector_t)0;
839 } else {
840 unsigned long bit = BM_SECT_TO_BIT(mdev->ov_start_sector);
841 if (bit >= mdev->rs_total) {
842 mdev->ov_start_sector =
843 BM_BIT_TO_SECT(mdev->rs_total - 1);
844 mdev->rs_total = 1;
845 } else
846 mdev->rs_total -= bit;
847 mdev->ov_position = mdev->ov_start_sector;
848 }
849 mdev->ov_left = mdev->rs_total;
850}
851
852/**
853 * __drbd_set_state() - Set a new DRBD state
854 * @mdev: DRBD device.
855 * @ns: new state.
856 * @flags: Flags
857 * @done: Optional completion, that will get completed after the after_state_ch() finished
858 *
859 * Caller needs to hold req_lock, and global_state_lock. Do not call directly.
860 */
861enum drbd_state_rv
862__drbd_set_state(struct drbd_conf *mdev, union drbd_state ns,
863 enum chg_state_flags flags, struct completion *done)
864{
865 union drbd_state os;
866 enum drbd_state_rv rv = SS_SUCCESS;
867 const char *warn_sync_abort = NULL;
868 struct after_state_chg_work *ascw;
869
Philipp Reisner78bae592011-03-28 15:40:12 +0200870 os = drbd_read_state(mdev);
Philipp Reisnerb8907332011-01-27 14:07:51 +0100871
Philipp Reisner4308a0a2011-02-10 11:24:38 +0100872 ns = sanitize_state(mdev, ns, &warn_sync_abort);
Philipp Reisnerb8907332011-01-27 14:07:51 +0100873 if (ns.i == os.i)
874 return SS_NOTHING_TO_DO;
875
Philipp Reisner35095022011-02-09 16:29:33 +0100876 rv = is_valid_transition(os, ns);
877 if (rv < SS_SUCCESS)
878 return rv;
879
Philipp Reisnerb8907332011-01-27 14:07:51 +0100880 if (!(flags & CS_HARD)) {
881 /* pre-state-change checks ; only look at ns */
882 /* See drbd_state_sw_errors in drbd_strings.c */
883
884 rv = is_valid_state(mdev, ns);
885 if (rv < SS_SUCCESS) {
886 /* If the old state was illegal as well, then let
887 this happen...*/
888
889 if (is_valid_state(mdev, os) == rv)
Philipp Reisnera75f34a2011-02-09 15:10:33 +0100890 rv = is_valid_soft_transition(os, ns);
Philipp Reisnerb8907332011-01-27 14:07:51 +0100891 } else
Philipp Reisnera75f34a2011-02-09 15:10:33 +0100892 rv = is_valid_soft_transition(os, ns);
Philipp Reisnerb8907332011-01-27 14:07:51 +0100893 }
894
895 if (rv < SS_SUCCESS) {
896 if (flags & CS_VERBOSE)
897 print_st_err(mdev, os, ns, rv);
898 return rv;
899 }
900
901 if (warn_sync_abort)
902 dev_warn(DEV, "%s aborted.\n", warn_sync_abort);
903
Philipp Reisner435693e2011-03-25 15:11:30 +0100904 drbd_pr_state_change(mdev, os, ns, flags);
Philipp Reisnerb8907332011-01-27 14:07:51 +0100905
Philipp Reisner706cb242011-03-29 15:20:27 +0200906 /* Display changes to the susp* flags that where caused by the call to
907 sanitize_state(). Only display it here if we where not called from
908 _conn_request_state() */
909 if (!(flags & CS_DC_SUSP))
910 conn_pr_state_change(mdev->tconn, os, ns, (flags & ~CS_DC_MASK) | CS_DC_SUSP);
911
Philipp Reisnerb8907332011-01-27 14:07:51 +0100912 /* if we are going -> D_FAILED or D_DISKLESS, grab one extra reference
913 * on the ldev here, to be sure the transition -> D_DISKLESS resp.
914 * drbd_ldev_destroy() won't happen before our corresponding
915 * after_state_ch works run, where we put_ldev again. */
916 if ((os.disk != D_FAILED && ns.disk == D_FAILED) ||
917 (os.disk != D_DISKLESS && ns.disk == D_DISKLESS))
918 atomic_inc(&mdev->local_cnt);
919
Philipp Reisnerda9fbc22011-03-29 10:52:01 +0200920 mdev->state.i = ns.i;
Philipp Reisner8e0af252011-03-28 16:18:39 +0200921 mdev->tconn->susp = ns.susp;
922 mdev->tconn->susp_nod = ns.susp_nod;
923 mdev->tconn->susp_fen = ns.susp_fen;
Philipp Reisnerb8907332011-01-27 14:07:51 +0100924
Philipp Reisner0e29d162011-02-18 14:23:11 +0100925 /* solve the race between becoming unconfigured,
926 * worker doing the cleanup, and
927 * admin reconfiguring us:
928 * on (re)configure, first set CONFIG_PENDING,
929 * then wait for a potentially exiting worker,
930 * start the worker, and schedule one no_op.
931 * then proceed with configuration.
932 */
933 if(conn_all_vols_unconf(mdev->tconn) &&
934 !test_and_set_bit(CONFIG_PENDING, &mdev->tconn->flags))
935 set_bit(OBJECT_DYING, &mdev->tconn->flags);
936
Philipp Reisnerb8907332011-01-27 14:07:51 +0100937 if (os.disk == D_ATTACHING && ns.disk >= D_NEGOTIATING)
938 drbd_print_uuids(mdev, "attached to UUIDs");
939
940 wake_up(&mdev->misc_wait);
941 wake_up(&mdev->state_wait);
Philipp Reisner2a67d8b2011-02-09 14:10:32 +0100942 wake_up(&mdev->tconn->ping_wait);
Philipp Reisnerb8907332011-01-27 14:07:51 +0100943
944 /* aborted verify run. log the last position */
945 if ((os.conn == C_VERIFY_S || os.conn == C_VERIFY_T) &&
946 ns.conn < C_CONNECTED) {
947 mdev->ov_start_sector =
948 BM_BIT_TO_SECT(drbd_bm_bits(mdev) - mdev->ov_left);
949 dev_info(DEV, "Online Verify reached sector %llu\n",
950 (unsigned long long)mdev->ov_start_sector);
951 }
952
953 if ((os.conn == C_PAUSED_SYNC_T || os.conn == C_PAUSED_SYNC_S) &&
954 (ns.conn == C_SYNC_TARGET || ns.conn == C_SYNC_SOURCE)) {
955 dev_info(DEV, "Syncer continues.\n");
956 mdev->rs_paused += (long)jiffies
957 -(long)mdev->rs_mark_time[mdev->rs_last_mark];
958 if (ns.conn == C_SYNC_TARGET)
959 mod_timer(&mdev->resync_timer, jiffies);
960 }
961
962 if ((os.conn == C_SYNC_TARGET || os.conn == C_SYNC_SOURCE) &&
963 (ns.conn == C_PAUSED_SYNC_T || ns.conn == C_PAUSED_SYNC_S)) {
964 dev_info(DEV, "Resync suspended\n");
965 mdev->rs_mark_time[mdev->rs_last_mark] = jiffies;
966 }
967
968 if (os.conn == C_CONNECTED &&
969 (ns.conn == C_VERIFY_S || ns.conn == C_VERIFY_T)) {
970 unsigned long now = jiffies;
971 int i;
972
973 set_ov_position(mdev, ns.conn);
974 mdev->rs_start = now;
975 mdev->rs_last_events = 0;
976 mdev->rs_last_sect_ev = 0;
977 mdev->ov_last_oos_size = 0;
978 mdev->ov_last_oos_start = 0;
979
980 for (i = 0; i < DRBD_SYNC_MARKS; i++) {
981 mdev->rs_mark_left[i] = mdev->ov_left;
982 mdev->rs_mark_time[i] = now;
983 }
984
985 drbd_rs_controller_reset(mdev);
986
987 if (ns.conn == C_VERIFY_S) {
988 dev_info(DEV, "Starting Online Verify from sector %llu\n",
989 (unsigned long long)mdev->ov_position);
990 mod_timer(&mdev->resync_timer, jiffies);
991 }
992 }
993
994 if (get_ldev(mdev)) {
995 u32 mdf = mdev->ldev->md.flags & ~(MDF_CONSISTENT|MDF_PRIMARY_IND|
996 MDF_CONNECTED_IND|MDF_WAS_UP_TO_DATE|
997 MDF_PEER_OUT_DATED|MDF_CRASHED_PRIMARY);
998
999 if (test_bit(CRASHED_PRIMARY, &mdev->flags))
1000 mdf |= MDF_CRASHED_PRIMARY;
1001 if (mdev->state.role == R_PRIMARY ||
1002 (mdev->state.pdsk < D_INCONSISTENT && mdev->state.peer == R_PRIMARY))
1003 mdf |= MDF_PRIMARY_IND;
1004 if (mdev->state.conn > C_WF_REPORT_PARAMS)
1005 mdf |= MDF_CONNECTED_IND;
1006 if (mdev->state.disk > D_INCONSISTENT)
1007 mdf |= MDF_CONSISTENT;
1008 if (mdev->state.disk > D_OUTDATED)
1009 mdf |= MDF_WAS_UP_TO_DATE;
1010 if (mdev->state.pdsk <= D_OUTDATED && mdev->state.pdsk >= D_INCONSISTENT)
1011 mdf |= MDF_PEER_OUT_DATED;
1012 if (mdf != mdev->ldev->md.flags) {
1013 mdev->ldev->md.flags = mdf;
1014 drbd_md_mark_dirty(mdev);
1015 }
1016 if (os.disk < D_CONSISTENT && ns.disk >= D_CONSISTENT)
1017 drbd_set_ed_uuid(mdev, mdev->ldev->md.uuid[UI_CURRENT]);
1018 put_ldev(mdev);
1019 }
1020
1021 /* Peer was forced D_UP_TO_DATE & R_PRIMARY, consider to resync */
1022 if (os.disk == D_INCONSISTENT && os.pdsk == D_INCONSISTENT &&
1023 os.peer == R_SECONDARY && ns.peer == R_PRIMARY)
1024 set_bit(CONSIDER_RESYNC, &mdev->flags);
1025
1026 /* Receiver should clean up itself */
1027 if (os.conn != C_DISCONNECTING && ns.conn == C_DISCONNECTING)
1028 drbd_thread_stop_nowait(&mdev->tconn->receiver);
1029
1030 /* Now the receiver finished cleaning up itself, it should die */
1031 if (os.conn != C_STANDALONE && ns.conn == C_STANDALONE)
1032 drbd_thread_stop_nowait(&mdev->tconn->receiver);
1033
1034 /* Upon network failure, we need to restart the receiver. */
1035 if (os.conn > C_TEAR_DOWN &&
1036 ns.conn <= C_TEAR_DOWN && ns.conn >= C_TIMEOUT)
1037 drbd_thread_restart_nowait(&mdev->tconn->receiver);
1038
1039 /* Resume AL writing if we get a connection */
1040 if (os.conn < C_CONNECTED && ns.conn >= C_CONNECTED)
1041 drbd_resume_al(mdev);
1042
1043 ascw = kmalloc(sizeof(*ascw), GFP_ATOMIC);
1044 if (ascw) {
1045 ascw->os = os;
1046 ascw->ns = ns;
1047 ascw->flags = flags;
1048 ascw->w.cb = w_after_state_ch;
Philipp Reisnera21e9292011-02-08 15:08:49 +01001049 ascw->w.mdev = mdev;
Philipp Reisnerb8907332011-01-27 14:07:51 +01001050 ascw->done = done;
1051 drbd_queue_work(&mdev->tconn->data.work, &ascw->w);
1052 } else {
Philipp Reisnerbbeb6412011-02-10 13:45:46 +01001053 dev_err(DEV, "Could not kmalloc an ascw\n");
Philipp Reisnerb8907332011-01-27 14:07:51 +01001054 }
1055
1056 return rv;
1057}
1058
Andreas Gruenbacher99920dc2011-03-16 15:31:39 +01001059static int w_after_state_ch(struct drbd_work *w, int unused)
Philipp Reisnerb8907332011-01-27 14:07:51 +01001060{
1061 struct after_state_chg_work *ascw =
1062 container_of(w, struct after_state_chg_work, w);
Philipp Reisner00d56942011-02-09 18:09:48 +01001063 struct drbd_conf *mdev = w->mdev;
Philipp Reisnerb8907332011-01-27 14:07:51 +01001064
1065 after_state_ch(mdev, ascw->os, ascw->ns, ascw->flags);
1066 if (ascw->flags & CS_WAIT_COMPLETE) {
1067 D_ASSERT(ascw->done != NULL);
1068 complete(ascw->done);
1069 }
1070 kfree(ascw);
1071
Andreas Gruenbacher99920dc2011-03-16 15:31:39 +01001072 return 0;
Philipp Reisnerb8907332011-01-27 14:07:51 +01001073}
1074
1075static void abw_start_sync(struct drbd_conf *mdev, int rv)
1076{
1077 if (rv) {
1078 dev_err(DEV, "Writing the bitmap failed not starting resync.\n");
1079 _drbd_request_state(mdev, NS(conn, C_CONNECTED), CS_VERBOSE);
1080 return;
1081 }
1082
1083 switch (mdev->state.conn) {
1084 case C_STARTING_SYNC_T:
1085 _drbd_request_state(mdev, NS(conn, C_WF_SYNC_UUID), CS_VERBOSE);
1086 break;
1087 case C_STARTING_SYNC_S:
1088 drbd_start_resync(mdev, C_SYNC_SOURCE);
1089 break;
1090 }
1091}
1092
1093int drbd_bitmap_io_from_worker(struct drbd_conf *mdev,
1094 int (*io_fn)(struct drbd_conf *),
1095 char *why, enum bm_flag flags)
1096{
1097 int rv;
1098
1099 D_ASSERT(current == mdev->tconn->worker.task);
1100
1101 /* open coded non-blocking drbd_suspend_io(mdev); */
1102 set_bit(SUSPEND_IO, &mdev->flags);
1103
1104 drbd_bm_lock(mdev, why, flags);
1105 rv = io_fn(mdev);
1106 drbd_bm_unlock(mdev);
1107
1108 drbd_resume_io(mdev);
1109
1110 return rv;
1111}
1112
1113/**
1114 * after_state_ch() - Perform after state change actions that may sleep
1115 * @mdev: DRBD device.
1116 * @os: old state.
1117 * @ns: new state.
1118 * @flags: Flags
1119 */
1120static void after_state_ch(struct drbd_conf *mdev, union drbd_state os,
1121 union drbd_state ns, enum chg_state_flags flags)
1122{
1123 enum drbd_fencing_p fp;
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01001124 struct sib_info sib;
1125
1126 sib.sib_reason = SIB_STATE_CHANGE;
1127 sib.os = os;
1128 sib.ns = ns;
Philipp Reisnerb8907332011-01-27 14:07:51 +01001129
1130 if (os.conn != C_CONNECTED && ns.conn == C_CONNECTED) {
1131 clear_bit(CRASHED_PRIMARY, &mdev->flags);
1132 if (mdev->p_uuid)
1133 mdev->p_uuid[UI_FLAGS] &= ~((u64)2);
1134 }
1135
1136 fp = FP_DONT_CARE;
1137 if (get_ldev(mdev)) {
1138 fp = mdev->ldev->dc.fencing;
1139 put_ldev(mdev);
1140 }
1141
1142 /* Inform userspace about the change... */
Lars Ellenberg3b98c0c2011-03-07 12:49:34 +01001143 drbd_bcast_event(mdev, &sib);
Philipp Reisnerb8907332011-01-27 14:07:51 +01001144
1145 if (!(os.role == R_PRIMARY && os.disk < D_UP_TO_DATE && os.pdsk < D_UP_TO_DATE) &&
1146 (ns.role == R_PRIMARY && ns.disk < D_UP_TO_DATE && ns.pdsk < D_UP_TO_DATE))
1147 drbd_khelper(mdev, "pri-on-incon-degr");
1148
1149 /* Here we have the actions that are performed after a
1150 state change. This function might sleep */
1151
Philipp Reisnerb8907332011-01-27 14:07:51 +01001152 if (ns.susp_nod) {
Philipp Reisnera6d00c82011-03-29 18:16:11 +02001153 enum drbd_req_event what = NOTHING;
1154
1155 if (os.conn < C_CONNECTED && conn_lowest_conn(mdev->tconn) >= C_CONNECTED)
Philipp Reisnerb8907332011-01-27 14:07:51 +01001156 what = RESEND;
1157
Philipp Reisnera6d00c82011-03-29 18:16:11 +02001158 if (os.disk == D_ATTACHING && conn_lowest_disk(mdev->tconn) > D_ATTACHING)
Philipp Reisnerb8907332011-01-27 14:07:51 +01001159 what = RESTART_FROZEN_DISK_IO;
1160
Philipp Reisnera6d00c82011-03-29 18:16:11 +02001161 if (what != NOTHING) {
Philipp Reisnerb8907332011-01-27 14:07:51 +01001162 spin_lock_irq(&mdev->tconn->req_lock);
Philipp Reisnera6d00c82011-03-29 18:16:11 +02001163 _tl_restart(mdev->tconn, what);
1164 _drbd_set_state(_NS(mdev, susp_nod, 0), CS_VERBOSE, NULL);
Philipp Reisnerb8907332011-01-27 14:07:51 +01001165 spin_unlock_irq(&mdev->tconn->req_lock);
1166 }
Philipp Reisnerb8907332011-01-27 14:07:51 +01001167 }
1168
1169 /* Became sync source. With protocol >= 96, we still need to send out
1170 * the sync uuid now. Need to do that before any drbd_send_state, or
1171 * the other side may go "paused sync" before receiving the sync uuids,
1172 * which is unexpected. */
1173 if ((os.conn != C_SYNC_SOURCE && os.conn != C_PAUSED_SYNC_S) &&
1174 (ns.conn == C_SYNC_SOURCE || ns.conn == C_PAUSED_SYNC_S) &&
1175 mdev->tconn->agreed_pro_version >= 96 && get_ldev(mdev)) {
1176 drbd_gen_and_send_sync_uuid(mdev);
1177 put_ldev(mdev);
1178 }
1179
1180 /* Do not change the order of the if above and the two below... */
1181 if (os.pdsk == D_DISKLESS && ns.pdsk > D_DISKLESS) { /* attach on the peer */
1182 drbd_send_uuids(mdev);
1183 drbd_send_state(mdev);
1184 }
1185 /* No point in queuing send_bitmap if we don't have a connection
1186 * anymore, so check also the _current_ state, not only the new state
1187 * at the time this work was queued. */
1188 if (os.conn != C_WF_BITMAP_S && ns.conn == C_WF_BITMAP_S &&
1189 mdev->state.conn == C_WF_BITMAP_S)
1190 drbd_queue_bitmap_io(mdev, &drbd_send_bitmap, NULL,
1191 "send_bitmap (WFBitMapS)",
1192 BM_LOCKED_TEST_ALLOWED);
1193
1194 /* Lost contact to peer's copy of the data */
1195 if ((os.pdsk >= D_INCONSISTENT &&
1196 os.pdsk != D_UNKNOWN &&
1197 os.pdsk != D_OUTDATED)
1198 && (ns.pdsk < D_INCONSISTENT ||
1199 ns.pdsk == D_UNKNOWN ||
1200 ns.pdsk == D_OUTDATED)) {
1201 if (get_ldev(mdev)) {
1202 if ((ns.role == R_PRIMARY || ns.peer == R_PRIMARY) &&
1203 mdev->ldev->md.uuid[UI_BITMAP] == 0 && ns.disk >= D_UP_TO_DATE) {
Philipp Reisner2aebfab2011-03-28 16:48:11 +02001204 if (drbd_suspended(mdev)) {
Philipp Reisnerb8907332011-01-27 14:07:51 +01001205 set_bit(NEW_CUR_UUID, &mdev->flags);
1206 } else {
1207 drbd_uuid_new_current(mdev);
1208 drbd_send_uuids(mdev);
1209 }
1210 }
1211 put_ldev(mdev);
1212 }
1213 }
1214
1215 if (ns.pdsk < D_INCONSISTENT && get_ldev(mdev)) {
1216 if (ns.peer == R_PRIMARY && mdev->ldev->md.uuid[UI_BITMAP] == 0) {
1217 drbd_uuid_new_current(mdev);
1218 drbd_send_uuids(mdev);
1219 }
1220
1221 /* D_DISKLESS Peer becomes secondary */
1222 if (os.peer == R_PRIMARY && ns.peer == R_SECONDARY)
1223 /* We may still be Primary ourselves.
1224 * No harm done if the bitmap still changes,
1225 * redirtied pages will follow later. */
1226 drbd_bitmap_io_from_worker(mdev, &drbd_bm_write,
1227 "demote diskless peer", BM_LOCKED_SET_ALLOWED);
1228 put_ldev(mdev);
1229 }
1230
1231 /* Write out all changed bits on demote.
1232 * Though, no need to da that just yet
1233 * if there is a resync going on still */
1234 if (os.role == R_PRIMARY && ns.role == R_SECONDARY &&
1235 mdev->state.conn <= C_CONNECTED && get_ldev(mdev)) {
1236 /* No changes to the bitmap expected this time, so assert that,
1237 * even though no harm was done if it did change. */
1238 drbd_bitmap_io_from_worker(mdev, &drbd_bm_write,
1239 "demote", BM_LOCKED_TEST_ALLOWED);
1240 put_ldev(mdev);
1241 }
1242
1243 /* Last part of the attaching process ... */
1244 if (ns.conn >= C_CONNECTED &&
1245 os.disk == D_ATTACHING && ns.disk == D_NEGOTIATING) {
1246 drbd_send_sizes(mdev, 0, 0); /* to start sync... */
1247 drbd_send_uuids(mdev);
1248 drbd_send_state(mdev);
1249 }
1250
1251 /* We want to pause/continue resync, tell peer. */
1252 if (ns.conn >= C_CONNECTED &&
1253 ((os.aftr_isp != ns.aftr_isp) ||
1254 (os.user_isp != ns.user_isp)))
1255 drbd_send_state(mdev);
1256
1257 /* In case one of the isp bits got set, suspend other devices. */
1258 if ((!os.aftr_isp && !os.peer_isp && !os.user_isp) &&
1259 (ns.aftr_isp || ns.peer_isp || ns.user_isp))
1260 suspend_other_sg(mdev);
1261
1262 /* Make sure the peer gets informed about eventual state
1263 changes (ISP bits) while we were in WFReportParams. */
1264 if (os.conn == C_WF_REPORT_PARAMS && ns.conn >= C_CONNECTED)
1265 drbd_send_state(mdev);
1266
1267 if (os.conn != C_AHEAD && ns.conn == C_AHEAD)
1268 drbd_send_state(mdev);
1269
1270 /* We are in the progress to start a full sync... */
1271 if ((os.conn != C_STARTING_SYNC_T && ns.conn == C_STARTING_SYNC_T) ||
1272 (os.conn != C_STARTING_SYNC_S && ns.conn == C_STARTING_SYNC_S))
1273 /* no other bitmap changes expected during this phase */
1274 drbd_queue_bitmap_io(mdev,
1275 &drbd_bmio_set_n_write, &abw_start_sync,
1276 "set_n_write from StartingSync", BM_LOCKED_TEST_ALLOWED);
1277
1278 /* We are invalidating our self... */
1279 if (os.conn < C_CONNECTED && ns.conn < C_CONNECTED &&
1280 os.disk > D_INCONSISTENT && ns.disk == D_INCONSISTENT)
1281 /* other bitmap operation expected during this phase */
1282 drbd_queue_bitmap_io(mdev, &drbd_bmio_set_n_write, NULL,
1283 "set_n_write from invalidate", BM_LOCKED_MASK);
1284
1285 /* first half of local IO error, failure to attach,
1286 * or administrative detach */
1287 if (os.disk != D_FAILED && ns.disk == D_FAILED) {
1288 enum drbd_io_error_p eh;
1289 int was_io_error;
1290 /* corresponding get_ldev was in __drbd_set_state, to serialize
1291 * our cleanup here with the transition to D_DISKLESS,
1292 * so it is safe to dreference ldev here. */
1293 eh = mdev->ldev->dc.on_io_error;
1294 was_io_error = test_and_clear_bit(WAS_IO_ERROR, &mdev->flags);
1295
1296 /* current state still has to be D_FAILED,
1297 * there is only one way out: to D_DISKLESS,
1298 * and that may only happen after our put_ldev below. */
1299 if (mdev->state.disk != D_FAILED)
1300 dev_err(DEV,
1301 "ASSERT FAILED: disk is %s during detach\n",
1302 drbd_disk_str(mdev->state.disk));
1303
Andreas Gruenbacher927036f2011-03-16 00:50:00 +01001304 if (!drbd_send_state(mdev))
Philipp Reisnerb8907332011-01-27 14:07:51 +01001305 dev_warn(DEV, "Notified peer that I am detaching my disk\n");
1306 else
1307 dev_err(DEV, "Sending state for detaching disk failed\n");
1308
1309 drbd_rs_cancel_all(mdev);
1310
1311 /* In case we want to get something to stable storage still,
1312 * this may be the last chance.
1313 * Following put_ldev may transition to D_DISKLESS. */
1314 drbd_md_sync(mdev);
1315 put_ldev(mdev);
1316
1317 if (was_io_error && eh == EP_CALL_HELPER)
1318 drbd_khelper(mdev, "local-io-error");
1319 }
1320
1321 /* second half of local IO error, failure to attach,
1322 * or administrative detach,
1323 * after local_cnt references have reached zero again */
1324 if (os.disk != D_DISKLESS && ns.disk == D_DISKLESS) {
1325 /* We must still be diskless,
1326 * re-attach has to be serialized with this! */
1327 if (mdev->state.disk != D_DISKLESS)
1328 dev_err(DEV,
1329 "ASSERT FAILED: disk is %s while going diskless\n",
1330 drbd_disk_str(mdev->state.disk));
1331
1332 mdev->rs_total = 0;
1333 mdev->rs_failed = 0;
1334 atomic_set(&mdev->rs_pending_cnt, 0);
1335
Andreas Gruenbacher927036f2011-03-16 00:50:00 +01001336 if (!drbd_send_state(mdev))
Philipp Reisnerb8907332011-01-27 14:07:51 +01001337 dev_warn(DEV, "Notified peer that I'm now diskless.\n");
1338 /* corresponding get_ldev in __drbd_set_state
1339 * this may finally trigger drbd_ldev_destroy. */
1340 put_ldev(mdev);
1341 }
1342
1343 /* Notify peer that I had a local IO error, and did not detached.. */
1344 if (os.disk == D_UP_TO_DATE && ns.disk == D_INCONSISTENT)
1345 drbd_send_state(mdev);
1346
1347 /* Disks got bigger while they were detached */
1348 if (ns.disk > D_NEGOTIATING && ns.pdsk > D_NEGOTIATING &&
1349 test_and_clear_bit(RESYNC_AFTER_NEG, &mdev->flags)) {
1350 if (ns.conn == C_CONNECTED)
1351 resync_after_online_grow(mdev);
1352 }
1353
1354 /* A resync finished or aborted, wake paused devices... */
1355 if ((os.conn > C_CONNECTED && ns.conn <= C_CONNECTED) ||
1356 (os.peer_isp && !ns.peer_isp) ||
1357 (os.user_isp && !ns.user_isp))
1358 resume_next_sg(mdev);
1359
1360 /* sync target done with resync. Explicitly notify peer, even though
1361 * it should (at least for non-empty resyncs) already know itself. */
1362 if (os.disk < D_UP_TO_DATE && os.conn >= C_SYNC_SOURCE && ns.conn == C_CONNECTED)
1363 drbd_send_state(mdev);
1364
1365 /* This triggers bitmap writeout of potentially still unwritten pages
1366 * if the resync finished cleanly, or aborted because of peer disk
1367 * failure, or because of connection loss.
1368 * For resync aborted because of local disk failure, we cannot do
1369 * any bitmap writeout anymore.
1370 * No harm done if some bits change during this phase.
1371 */
1372 if (os.conn > C_CONNECTED && ns.conn <= C_CONNECTED && get_ldev(mdev)) {
1373 drbd_queue_bitmap_io(mdev, &drbd_bm_write, NULL,
1374 "write from resync_finished", BM_LOCKED_SET_ALLOWED);
1375 put_ldev(mdev);
1376 }
1377
1378 if (ns.disk == D_DISKLESS &&
1379 ns.conn == C_STANDALONE &&
1380 ns.role == R_SECONDARY) {
1381 if (os.aftr_isp != ns.aftr_isp)
1382 resume_next_sg(mdev);
1383 }
1384
Philipp Reisner0e29d162011-02-18 14:23:11 +01001385 after_all_state_ch(mdev->tconn);
Philipp Reisnerbbeb6412011-02-10 13:45:46 +01001386
Philipp Reisnerb8907332011-01-27 14:07:51 +01001387 drbd_md_sync(mdev);
1388}
1389
Philipp Reisnerbbeb6412011-02-10 13:45:46 +01001390struct after_conn_state_chg_work {
1391 struct drbd_work w;
1392 enum drbd_conns oc;
Philipp Reisner8c7e16c2011-03-29 14:01:02 +02001393 union drbd_state ns_min;
Philipp Reisner5f082f92011-03-29 13:20:58 +02001394 union drbd_state ns_max; /* new, max state, over all mdevs */
Philipp Reisnerbbeb6412011-02-10 13:45:46 +01001395 enum chg_state_flags flags;
1396};
Philipp Reisnerb8907332011-01-27 14:07:51 +01001397
Philipp Reisner0e29d162011-02-18 14:23:11 +01001398static void after_all_state_ch(struct drbd_tconn *tconn)
Philipp Reisnerbbeb6412011-02-10 13:45:46 +01001399{
Philipp Reisner0e29d162011-02-18 14:23:11 +01001400 if (conn_all_vols_unconf(tconn) &&
1401 test_bit(OBJECT_DYING, &tconn->flags)) {
Philipp Reisnerb8907332011-01-27 14:07:51 +01001402 drbd_thread_stop_nowait(&tconn->worker);
1403 }
1404}
Philipp Reisnerbbeb6412011-02-10 13:45:46 +01001405
Andreas Gruenbacher99920dc2011-03-16 15:31:39 +01001406static int w_after_conn_state_ch(struct drbd_work *w, int unused)
Philipp Reisnerbbeb6412011-02-10 13:45:46 +01001407{
1408 struct after_conn_state_chg_work *acscw =
1409 container_of(w, struct after_conn_state_chg_work, w);
1410 struct drbd_tconn *tconn = w->tconn;
1411 enum drbd_conns oc = acscw->oc;
Philipp Reisner5f082f92011-03-29 13:20:58 +02001412 union drbd_state ns_max = acscw->ns_max;
Philipp Reisnera6d00c82011-03-29 18:16:11 +02001413 union drbd_state ns_min = acscw->ns_min;
1414 struct drbd_conf *mdev;
1415 int vnr;
Philipp Reisnerbbeb6412011-02-10 13:45:46 +01001416
1417 kfree(acscw);
1418
1419 /* Upon network configuration, we need to start the receiver */
Philipp Reisner5f082f92011-03-29 13:20:58 +02001420 if (oc == C_STANDALONE && ns_max.conn == C_UNCONNECTED)
Philipp Reisnerbbeb6412011-02-10 13:45:46 +01001421 drbd_thread_start(&tconn->receiver);
1422
Philipp Reisnera6d00c82011-03-29 18:16:11 +02001423 if (ns_max.susp_fen) {
1424 /* case1: The outdate peer handler is successful: */
1425 if (ns_max.pdsk <= D_OUTDATED) {
1426 tl_clear(tconn);
Philipp Reisner695d08f2011-04-11 22:53:32 -07001427 rcu_read_lock();
Philipp Reisnera6d00c82011-03-29 18:16:11 +02001428 idr_for_each_entry(&tconn->volumes, mdev, vnr) {
1429 if (test_bit(NEW_CUR_UUID, &mdev->flags)) {
1430 drbd_uuid_new_current(mdev);
1431 clear_bit(NEW_CUR_UUID, &mdev->flags);
1432 }
1433 }
Philipp Reisner695d08f2011-04-11 22:53:32 -07001434 rcu_read_unlock();
Philipp Reisnera6d00c82011-03-29 18:16:11 +02001435 conn_request_state(tconn,
1436 (union drbd_state) { { .susp_fen = 1 } },
1437 (union drbd_state) { { .susp_fen = 0 } },
1438 CS_VERBOSE);
1439 }
1440 /* case2: The connection was established again: */
1441 if (ns_min.conn >= C_CONNECTED) {
Philipp Reisner695d08f2011-04-11 22:53:32 -07001442 rcu_read_lock();
Philipp Reisnera6d00c82011-03-29 18:16:11 +02001443 idr_for_each_entry(&tconn->volumes, mdev, vnr)
1444 clear_bit(NEW_CUR_UUID, &mdev->flags);
Philipp Reisner695d08f2011-04-11 22:53:32 -07001445 rcu_read_unlock();
Philipp Reisnera6d00c82011-03-29 18:16:11 +02001446 spin_lock_irq(&tconn->req_lock);
1447 _tl_restart(tconn, RESEND);
1448 _conn_request_state(tconn,
1449 (union drbd_state) { { .susp_fen = 1 } },
1450 (union drbd_state) { { .susp_fen = 0 } },
1451 CS_VERBOSE);
1452 spin_unlock_irq(&tconn->req_lock);
1453 }
1454 }
1455
1456
Philipp Reisnerbbeb6412011-02-10 13:45:46 +01001457 //conn_err(tconn, STATE_FMT, STATE_ARGS("nms", nms));
Philipp Reisner0e29d162011-02-18 14:23:11 +01001458 after_all_state_ch(tconn);
Philipp Reisnerbbeb6412011-02-10 13:45:46 +01001459
Andreas Gruenbacher99920dc2011-03-16 15:31:39 +01001460 return 0;
Philipp Reisnerbbeb6412011-02-10 13:45:46 +01001461}
1462
Philipp Reisner435693e2011-03-25 15:11:30 +01001463void conn_old_common_state(struct drbd_tconn *tconn, union drbd_state *pcs, enum chg_state_flags *pf)
Philipp Reisnerbbeb6412011-02-10 13:45:46 +01001464{
Philipp Reisner435693e2011-03-25 15:11:30 +01001465 enum chg_state_flags flags = ~0;
Philipp Reisnerda9fbc22011-03-29 10:52:01 +02001466 union drbd_dev_state os, cs = {}; /* old_state, common_state */
Philipp Reisner88ef5942011-03-25 14:31:11 +01001467 struct drbd_conf *mdev;
Philipp Reisner435693e2011-03-25 15:11:30 +01001468 int vnr, first_vol = 1;
Philipp Reisner88ef5942011-03-25 14:31:11 +01001469
Philipp Reisner695d08f2011-04-11 22:53:32 -07001470 rcu_read_lock();
Philipp Reisner88ef5942011-03-25 14:31:11 +01001471 idr_for_each_entry(&tconn->volumes, mdev, vnr) {
1472 os = mdev->state;
1473
Philipp Reisner435693e2011-03-25 15:11:30 +01001474 if (first_vol) {
1475 cs = os;
1476 first_vol = 0;
1477 continue;
1478 }
Philipp Reisner88ef5942011-03-25 14:31:11 +01001479
Philipp Reisner435693e2011-03-25 15:11:30 +01001480 if (cs.role != os.role)
1481 flags &= ~CS_DC_ROLE;
Philipp Reisner88ef5942011-03-25 14:31:11 +01001482
Philipp Reisner435693e2011-03-25 15:11:30 +01001483 if (cs.peer != os.peer)
1484 flags &= ~CS_DC_PEER;
Philipp Reisner88ef5942011-03-25 14:31:11 +01001485
Philipp Reisner435693e2011-03-25 15:11:30 +01001486 if (cs.conn != os.conn)
1487 flags &= ~CS_DC_CONN;
Philipp Reisner88ef5942011-03-25 14:31:11 +01001488
Philipp Reisner435693e2011-03-25 15:11:30 +01001489 if (cs.disk != os.disk)
1490 flags &= ~CS_DC_DISK;
1491
1492 if (cs.pdsk != os.pdsk)
1493 flags &= ~CS_DC_PDSK;
Philipp Reisner88ef5942011-03-25 14:31:11 +01001494 }
Philipp Reisner695d08f2011-04-11 22:53:32 -07001495 rcu_read_unlock();
Philipp Reisner88ef5942011-03-25 14:31:11 +01001496
Philipp Reisner435693e2011-03-25 15:11:30 +01001497 *pf |= CS_DC_MASK;
1498 *pf &= flags;
Philipp Reisnerda9fbc22011-03-29 10:52:01 +02001499 (*pcs).i = cs.i;
Philipp Reisner88ef5942011-03-25 14:31:11 +01001500}
Philipp Reisnerbbeb6412011-02-10 13:45:46 +01001501
Philipp Reisnerbd0c8242011-03-25 12:02:20 +01001502static enum drbd_state_rv
1503conn_is_valid_transition(struct drbd_tconn *tconn, union drbd_state mask, union drbd_state val,
Philipp Reisner88ef5942011-03-25 14:31:11 +01001504 enum chg_state_flags flags)
Philipp Reisnerbbeb6412011-02-10 13:45:46 +01001505{
Philipp Reisnerbd0c8242011-03-25 12:02:20 +01001506 enum drbd_state_rv rv = SS_SUCCESS;
Philipp Reisnerbbeb6412011-02-10 13:45:46 +01001507 union drbd_state ns, os;
Philipp Reisnerbd0c8242011-03-25 12:02:20 +01001508 struct drbd_conf *mdev;
1509 int vnr;
Philipp Reisnerbbeb6412011-02-10 13:45:46 +01001510
Philipp Reisner695d08f2011-04-11 22:53:32 -07001511 rcu_read_lock();
Philipp Reisnerbd0c8242011-03-25 12:02:20 +01001512 idr_for_each_entry(&tconn->volumes, mdev, vnr) {
Philipp Reisner78bae592011-03-28 15:40:12 +02001513 os = drbd_read_state(mdev);
Philipp Reisnerbd0c8242011-03-25 12:02:20 +01001514 ns = sanitize_state(mdev, apply_mask_val(os, mask, val), NULL);
Philipp Reisnerbbeb6412011-02-10 13:45:46 +01001515
Philipp Reisner778bcf22011-03-28 12:55:03 +02001516 if (flags & CS_IGN_OUTD_FAIL && ns.disk == D_OUTDATED && os.disk < D_OUTDATED)
1517 ns.disk = os.disk;
1518
Philipp Reisnerbd0c8242011-03-25 12:02:20 +01001519 if (ns.i == os.i)
1520 continue;
Philipp Reisnerbbeb6412011-02-10 13:45:46 +01001521
Philipp Reisnerbd0c8242011-03-25 12:02:20 +01001522 rv = is_valid_transition(os, ns);
1523 if (rv < SS_SUCCESS)
1524 break;
1525
1526 if (!(flags & CS_HARD)) {
1527 rv = is_valid_state(mdev, ns);
1528 if (rv < SS_SUCCESS) {
1529 if (is_valid_state(mdev, os) == rv)
1530 rv = is_valid_soft_transition(os, ns);
1531 } else
1532 rv = is_valid_soft_transition(os, ns);
1533 }
1534 if (rv < SS_SUCCESS)
1535 break;
Philipp Reisnerbbeb6412011-02-10 13:45:46 +01001536 }
Philipp Reisner695d08f2011-04-11 22:53:32 -07001537 rcu_read_unlock();
Philipp Reisnerbbeb6412011-02-10 13:45:46 +01001538
Philipp Reisnerbd0c8242011-03-25 12:02:20 +01001539 if (rv < SS_SUCCESS && flags & CS_VERBOSE)
1540 print_st_err(mdev, os, ns, rv);
1541
1542 return rv;
Philipp Reisnerbbeb6412011-02-10 13:45:46 +01001543}
1544
Philipp Reisner8c7e16c2011-03-29 14:01:02 +02001545void
Philipp Reisnerbd0c8242011-03-25 12:02:20 +01001546conn_set_state(struct drbd_tconn *tconn, union drbd_state mask, union drbd_state val,
Philipp Reisner8c7e16c2011-03-29 14:01:02 +02001547 union drbd_state *pns_min, union drbd_state *pns_max, enum chg_state_flags flags)
Philipp Reisnerbbeb6412011-02-10 13:45:46 +01001548{
Philipp Reisner8c7e16c2011-03-29 14:01:02 +02001549 union drbd_state ns, os, ns_max = { };
1550 union drbd_state ns_min = {
1551 { .role = R_MASK,
1552 .peer = R_MASK,
1553 .disk = D_MASK,
1554 .pdsk = D_MASK
1555 } };
Philipp Reisnerbd0c8242011-03-25 12:02:20 +01001556 struct drbd_conf *mdev;
Philipp Reisnerbbeb6412011-02-10 13:45:46 +01001557 enum drbd_state_rv rv;
Philipp Reisnerbd0c8242011-03-25 12:02:20 +01001558 int vnr;
Philipp Reisnerbbeb6412011-02-10 13:45:46 +01001559
Philipp Reisnerbd0c8242011-03-25 12:02:20 +01001560 if (mask.conn == C_MASK)
1561 tconn->cstate = val.conn;
Philipp Reisnerbbeb6412011-02-10 13:45:46 +01001562
Philipp Reisner695d08f2011-04-11 22:53:32 -07001563 rcu_read_lock();
Philipp Reisnerbd0c8242011-03-25 12:02:20 +01001564 idr_for_each_entry(&tconn->volumes, mdev, vnr) {
Philipp Reisner78bae592011-03-28 15:40:12 +02001565 os = drbd_read_state(mdev);
Philipp Reisnerbd0c8242011-03-25 12:02:20 +01001566 ns = apply_mask_val(os, mask, val);
1567 ns = sanitize_state(mdev, ns, NULL);
Philipp Reisnerbbeb6412011-02-10 13:45:46 +01001568
Philipp Reisner778bcf22011-03-28 12:55:03 +02001569 if (flags & CS_IGN_OUTD_FAIL && ns.disk == D_OUTDATED && os.disk < D_OUTDATED)
1570 ns.disk = os.disk;
1571
Philipp Reisnerbd0c8242011-03-25 12:02:20 +01001572 rv = __drbd_set_state(mdev, ns, flags, NULL);
1573 if (rv < SS_SUCCESS)
1574 BUG();
Philipp Reisnerbbeb6412011-02-10 13:45:46 +01001575
Philipp Reisner8c7e16c2011-03-29 14:01:02 +02001576 ns.i = mdev->state.i;
1577 ns_max.role = max_role(ns.role, ns_max.role);
1578 ns_max.peer = max_role(ns.peer, ns_max.peer);
1579 ns_max.conn = max_t(enum drbd_conns, ns.conn, ns_max.conn);
1580 ns_max.disk = max_t(enum drbd_disk_state, ns.disk, ns_max.disk);
1581 ns_max.pdsk = max_t(enum drbd_disk_state, ns.pdsk, ns_max.pdsk);
1582
1583 ns_min.role = min_role(ns.role, ns_min.role);
1584 ns_min.peer = min_role(ns.peer, ns_min.peer);
1585 ns_min.conn = min_t(enum drbd_conns, ns.conn, ns_min.conn);
1586 ns_min.disk = min_t(enum drbd_disk_state, ns.disk, ns_min.disk);
1587 ns_min.pdsk = min_t(enum drbd_disk_state, ns.pdsk, ns_min.pdsk);
Philipp Reisnerbd0c8242011-03-25 12:02:20 +01001588 }
Philipp Reisner695d08f2011-04-11 22:53:32 -07001589 rcu_read_unlock();
Philipp Reisnerbd0c8242011-03-25 12:02:20 +01001590
Philipp Reisner8c7e16c2011-03-29 14:01:02 +02001591 ns_min.susp = ns_max.susp = tconn->susp;
1592 ns_min.susp_nod = ns_max.susp_nod = tconn->susp_nod;
1593 ns_min.susp_fen = ns_max.susp_fen = tconn->susp_fen;
1594
1595 *pns_min = ns_min;
1596 *pns_max = ns_max;
Philipp Reisnerbbeb6412011-02-10 13:45:46 +01001597}
1598
Philipp Reisnerdf24aa42011-02-15 11:14:44 +01001599static enum drbd_state_rv
1600_conn_rq_cond(struct drbd_tconn *tconn, union drbd_state mask, union drbd_state val)
1601{
Philipp Reisnerdf24aa42011-02-15 11:14:44 +01001602 enum drbd_state_rv rv;
1603
1604 if (test_and_clear_bit(CONN_WD_ST_CHG_OKAY, &tconn->flags))
1605 return SS_CW_SUCCESS;
1606
1607 if (test_and_clear_bit(CONN_WD_ST_CHG_FAIL, &tconn->flags))
1608 return SS_CW_FAILED_BY_PEER;
1609
Philipp Reisnerdf24aa42011-02-15 11:14:44 +01001610 spin_lock_irq(&tconn->req_lock);
1611 rv = tconn->cstate != C_WF_REPORT_PARAMS ? SS_CW_NO_NEED : SS_UNKNOWN_ERROR;
1612
1613 if (rv == SS_UNKNOWN_ERROR)
Philipp Reisner435693e2011-03-25 15:11:30 +01001614 rv = conn_is_valid_transition(tconn, mask, val, 0);
Philipp Reisnerdf24aa42011-02-15 11:14:44 +01001615
Philipp Reisnerbd0c8242011-03-25 12:02:20 +01001616 if (rv == SS_SUCCESS)
1617 rv = SS_UNKNOWN_ERROR; /* cont waiting, otherwise fail. */
Philipp Reisnerdf24aa42011-02-15 11:14:44 +01001618
1619 spin_unlock_irq(&tconn->req_lock);
1620
1621 return rv;
1622}
1623
1624static enum drbd_state_rv
1625conn_cl_wide(struct drbd_tconn *tconn, union drbd_state mask, union drbd_state val,
1626 enum chg_state_flags f)
1627{
1628 enum drbd_state_rv rv;
1629
1630 spin_unlock_irq(&tconn->req_lock);
1631 mutex_lock(&tconn->cstate_mutex);
1632
Andreas Gruenbachercaee1c32011-03-16 01:17:35 +01001633 if (conn_send_state_req(tconn, mask, val)) {
Philipp Reisnerdf24aa42011-02-15 11:14:44 +01001634 rv = SS_CW_FAILED_BY_PEER;
1635 /* if (f & CS_VERBOSE)
1636 print_st_err(mdev, os, ns, rv); */
1637 goto abort;
1638 }
1639
1640 wait_event(tconn->ping_wait, (rv = _conn_rq_cond(tconn, mask, val)));
1641
1642abort:
1643 mutex_unlock(&tconn->cstate_mutex);
1644 spin_lock_irq(&tconn->req_lock);
1645
1646 return rv;
1647}
1648
Philipp Reisnerbbeb6412011-02-10 13:45:46 +01001649enum drbd_state_rv
1650_conn_request_state(struct drbd_tconn *tconn, union drbd_state mask, union drbd_state val,
1651 enum chg_state_flags flags)
1652{
1653 enum drbd_state_rv rv = SS_SUCCESS;
Philipp Reisnerbbeb6412011-02-10 13:45:46 +01001654 struct after_conn_state_chg_work *acscw;
1655 enum drbd_conns oc = tconn->cstate;
Philipp Reisner8c7e16c2011-03-29 14:01:02 +02001656 union drbd_state ns_max, ns_min, os;
Philipp Reisnerbbeb6412011-02-10 13:45:46 +01001657
Philipp Reisnerbbeb6412011-02-10 13:45:46 +01001658 rv = is_valid_conn_transition(oc, val.conn);
1659 if (rv < SS_SUCCESS)
1660 goto abort;
1661
Philipp Reisner88ef5942011-03-25 14:31:11 +01001662 rv = conn_is_valid_transition(tconn, mask, val, flags);
Philipp Reisnerbbeb6412011-02-10 13:45:46 +01001663 if (rv < SS_SUCCESS)
1664 goto abort;
1665
Philipp Reisnerdf24aa42011-02-15 11:14:44 +01001666 if (oc == C_WF_REPORT_PARAMS && val.conn == C_DISCONNECTING &&
1667 !(flags & (CS_LOCAL_ONLY | CS_HARD))) {
1668 rv = conn_cl_wide(tconn, mask, val, flags);
1669 if (rv < SS_SUCCESS)
1670 goto abort;
1671 }
1672
Philipp Reisner435693e2011-03-25 15:11:30 +01001673 conn_old_common_state(tconn, &os, &flags);
Philipp Reisner706cb242011-03-29 15:20:27 +02001674 flags |= CS_DC_SUSP;
Philipp Reisner8c7e16c2011-03-29 14:01:02 +02001675 conn_set_state(tconn, mask, val, &ns_min, &ns_max, flags);
Philipp Reisner5f082f92011-03-29 13:20:58 +02001676 conn_pr_state_change(tconn, os, ns_max, flags);
Philipp Reisnerbbeb6412011-02-10 13:45:46 +01001677
1678 acscw = kmalloc(sizeof(*acscw), GFP_ATOMIC);
1679 if (acscw) {
Philipp Reisner435693e2011-03-25 15:11:30 +01001680 acscw->oc = os.conn;
Philipp Reisner8c7e16c2011-03-29 14:01:02 +02001681 acscw->ns_min = ns_min;
Philipp Reisner5f082f92011-03-29 13:20:58 +02001682 acscw->ns_max = ns_max;
Philipp Reisnerbbeb6412011-02-10 13:45:46 +01001683 acscw->flags = flags;
1684 acscw->w.cb = w_after_conn_state_ch;
1685 acscw->w.tconn = tconn;
1686 drbd_queue_work(&tconn->data.work, &acscw->w);
1687 } else {
1688 conn_err(tconn, "Could not kmalloc an acscw\n");
1689 }
1690
1691abort:
Philipp Reisnerbbeb6412011-02-10 13:45:46 +01001692 return rv;
1693}
1694
1695enum drbd_state_rv
1696conn_request_state(struct drbd_tconn *tconn, union drbd_state mask, union drbd_state val,
1697 enum chg_state_flags flags)
1698{
1699 enum drbd_state_rv rv;
1700
1701 spin_lock_irq(&tconn->req_lock);
1702 rv = _conn_request_state(tconn, mask, val, flags);
1703 spin_unlock_irq(&tconn->req_lock);
1704
1705 return rv;
1706}