diff options
author | Philipp Reisner <philipp.reisner@linbit.com> | 2011-02-10 07:45:46 -0500 |
---|---|---|
committer | Philipp Reisner <philipp.reisner@linbit.com> | 2011-10-14 10:44:58 -0400 |
commit | bbeb641c3e4982d6bba21188545a7fd44ab0a715 (patch) | |
tree | eaceb0498387fcef6ad853a92b4db76d6c246e55 | |
parent | 56707f9e873108c0173b4edf20ea452e1d2a89d2 (diff) |
drbd: Killed volume0; last step of multi-volume-enablement
Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com>
Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com>
-rw-r--r-- | drivers/block/drbd/drbd_int.h | 4 | ||||
-rw-r--r-- | drivers/block/drbd/drbd_main.c | 8 | ||||
-rw-r--r-- | drivers/block/drbd/drbd_nl.c | 2 | ||||
-rw-r--r-- | drivers/block/drbd/drbd_receiver.c | 39 | ||||
-rw-r--r-- | drivers/block/drbd/drbd_state.c | 292 | ||||
-rw-r--r-- | drivers/block/drbd/drbd_state.h | 10 | ||||
-rw-r--r-- | drivers/block/drbd/drbd_worker.c | 7 |
7 files changed, 276 insertions, 86 deletions
diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index e2b59f58a0aa..f718124c5c82 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h | |||
@@ -918,8 +918,8 @@ enum { | |||
918 | struct drbd_tconn { /* is a resource from the config file */ | 918 | struct drbd_tconn { /* is a resource from the config file */ |
919 | char *name; /* Resource name */ | 919 | char *name; /* Resource name */ |
920 | struct list_head all_tconn; /* List of all drbd_tconn, prot by global_state_lock */ | 920 | struct list_head all_tconn; /* List of all drbd_tconn, prot by global_state_lock */ |
921 | struct drbd_conf *volume0; /* TODO: Remove me again */ | ||
922 | struct idr volumes; /* <tconn, vnr> to mdev mapping */ | 921 | struct idr volumes; /* <tconn, vnr> to mdev mapping */ |
922 | enum drbd_conns cstate; /* Only C_STANDALONE to C_WF_REPORT_PARAMS */ | ||
923 | 923 | ||
924 | unsigned long flags; | 924 | unsigned long flags; |
925 | struct net_conf *net_conf; /* protected by get_net_conf() and put_net_conf() */ | 925 | struct net_conf *net_conf; /* protected by get_net_conf() and put_net_conf() */ |
@@ -2024,7 +2024,7 @@ static inline int get_net_conf(struct drbd_tconn *tconn) | |||
2024 | int have_net_conf; | 2024 | int have_net_conf; |
2025 | 2025 | ||
2026 | atomic_inc(&tconn->net_cnt); | 2026 | atomic_inc(&tconn->net_cnt); |
2027 | have_net_conf = tconn->volume0->state.conn >= C_UNCONNECTED; | 2027 | have_net_conf = tconn->cstate >= C_UNCONNECTED; |
2028 | if (!have_net_conf) | 2028 | if (!have_net_conf) |
2029 | put_net_conf(tconn); | 2029 | put_net_conf(tconn); |
2030 | return have_net_conf; | 2030 | return have_net_conf; |
diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index b43ad87a536a..b64b7388ee9d 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c | |||
@@ -1344,7 +1344,7 @@ static int we_should_drop_the_connection(struct drbd_tconn *tconn, struct socket | |||
1344 | drop_it = tconn->meta.socket == sock | 1344 | drop_it = tconn->meta.socket == sock |
1345 | || !tconn->asender.task | 1345 | || !tconn->asender.task |
1346 | || get_t_state(&tconn->asender) != RUNNING | 1346 | || get_t_state(&tconn->asender) != RUNNING |
1347 | || tconn->volume0->state.conn < C_CONNECTED; | 1347 | || tconn->cstate < C_WF_REPORT_PARAMS; |
1348 | 1348 | ||
1349 | if (drop_it) | 1349 | if (drop_it) |
1350 | return true; | 1350 | return true; |
@@ -1705,9 +1705,9 @@ int drbd_send(struct drbd_tconn *tconn, struct socket *sock, | |||
1705 | conn_err(tconn, "%s_sendmsg returned %d\n", | 1705 | conn_err(tconn, "%s_sendmsg returned %d\n", |
1706 | sock == tconn->meta.socket ? "msock" : "sock", | 1706 | sock == tconn->meta.socket ? "msock" : "sock", |
1707 | rv); | 1707 | rv); |
1708 | drbd_force_state(tconn->volume0, NS(conn, C_BROKEN_PIPE)); | 1708 | conn_request_state(tconn, NS(conn, C_BROKEN_PIPE), CS_HARD); |
1709 | } else | 1709 | } else |
1710 | drbd_force_state(tconn->volume0, NS(conn, C_TIMEOUT)); | 1710 | conn_request_state(tconn, NS(conn, C_TIMEOUT), CS_HARD); |
1711 | } | 1711 | } |
1712 | 1712 | ||
1713 | return sent; | 1713 | return sent; |
@@ -2188,6 +2188,7 @@ struct drbd_tconn *drbd_new_tconn(char *name) | |||
2188 | if (!tconn->name) | 2188 | if (!tconn->name) |
2189 | goto fail; | 2189 | goto fail; |
2190 | 2190 | ||
2191 | tconn->cstate = C_STANDALONE; | ||
2191 | spin_lock_init(&tconn->req_lock); | 2192 | spin_lock_init(&tconn->req_lock); |
2192 | atomic_set(&tconn->net_cnt, 0); | 2193 | atomic_set(&tconn->net_cnt, 0); |
2193 | init_waitqueue_head(&tconn->net_cnt_wait); | 2194 | init_waitqueue_head(&tconn->net_cnt_wait); |
@@ -2258,7 +2259,6 @@ struct drbd_conf *drbd_new_device(unsigned int minor) | |||
2258 | if (!zalloc_cpumask_var(&mdev->tconn->cpu_mask, GFP_KERNEL)) | 2259 | if (!zalloc_cpumask_var(&mdev->tconn->cpu_mask, GFP_KERNEL)) |
2259 | goto out_no_cpumask; | 2260 | goto out_no_cpumask; |
2260 | 2261 | ||
2261 | mdev->tconn->volume0 = mdev; | ||
2262 | mdev->minor = minor; | 2262 | mdev->minor = minor; |
2263 | 2263 | ||
2264 | drbd_init_set_defaults(mdev); | 2264 | drbd_init_set_defaults(mdev); |
diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index 0debe589b674..eeb284aef3c8 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c | |||
@@ -1547,7 +1547,7 @@ static int drbd_nl_net_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, | |||
1547 | mdev->tconn->int_dig_out=int_dig_out; | 1547 | mdev->tconn->int_dig_out=int_dig_out; |
1548 | mdev->tconn->int_dig_in=int_dig_in; | 1548 | mdev->tconn->int_dig_in=int_dig_in; |
1549 | mdev->tconn->int_dig_vv=int_dig_vv; | 1549 | mdev->tconn->int_dig_vv=int_dig_vv; |
1550 | retcode = _drbd_set_state(_NS(mdev, conn, C_UNCONNECTED), CS_VERBOSE, NULL); | 1550 | retcode = _conn_request_state(mdev->tconn, NS(conn, C_UNCONNECTED), CS_VERBOSE); |
1551 | spin_unlock_irq(&mdev->tconn->req_lock); | 1551 | spin_unlock_irq(&mdev->tconn->req_lock); |
1552 | 1552 | ||
1553 | kobject_uevent(&disk_to_dev(mdev->vdisk)->kobj, KOBJ_CHANGE); | 1553 | kobject_uevent(&disk_to_dev(mdev->vdisk)->kobj, KOBJ_CHANGE); |
diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 2b69a15a55dd..27e1eb7ce540 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c | |||
@@ -551,7 +551,7 @@ static int drbd_recv(struct drbd_tconn *tconn, void *buf, size_t size) | |||
551 | set_fs(oldfs); | 551 | set_fs(oldfs); |
552 | 552 | ||
553 | if (rv != size) | 553 | if (rv != size) |
554 | drbd_force_state(tconn->volume0, NS(conn, C_BROKEN_PIPE)); | 554 | conn_request_state(tconn, NS(conn, C_BROKEN_PIPE), CS_HARD); |
555 | 555 | ||
556 | return rv; | 556 | return rv; |
557 | } | 557 | } |
@@ -647,7 +647,7 @@ out: | |||
647 | conn_err(tconn, "%s failed, err = %d\n", what, err); | 647 | conn_err(tconn, "%s failed, err = %d\n", what, err); |
648 | } | 648 | } |
649 | if (disconnect_on_error) | 649 | if (disconnect_on_error) |
650 | drbd_force_state(tconn->volume0, NS(conn, C_DISCONNECTING)); | 650 | conn_request_state(tconn, NS(conn, C_DISCONNECTING), CS_HARD); |
651 | } | 651 | } |
652 | put_net_conf(tconn); | 652 | put_net_conf(tconn); |
653 | return sock; | 653 | return sock; |
@@ -694,7 +694,7 @@ out: | |||
694 | if (err < 0) { | 694 | if (err < 0) { |
695 | if (err != -EAGAIN && err != -EINTR && err != -ERESTARTSYS) { | 695 | if (err != -EAGAIN && err != -EINTR && err != -ERESTARTSYS) { |
696 | conn_err(tconn, "%s failed, err = %d\n", what, err); | 696 | conn_err(tconn, "%s failed, err = %d\n", what, err); |
697 | drbd_force_state(tconn->volume0, NS(conn, C_DISCONNECTING)); | 697 | conn_request_state(tconn, NS(conn, C_DISCONNECTING), CS_HARD); |
698 | } | 698 | } |
699 | } | 699 | } |
700 | put_net_conf(tconn); | 700 | put_net_conf(tconn); |
@@ -776,7 +776,7 @@ static int drbd_connect(struct drbd_tconn *tconn) | |||
776 | struct socket *s, *sock, *msock; | 776 | struct socket *s, *sock, *msock; |
777 | int try, h, ok; | 777 | int try, h, ok; |
778 | 778 | ||
779 | if (drbd_request_state(tconn->volume0, NS(conn, C_WF_CONNECTION)) < SS_SUCCESS) | 779 | if (conn_request_state(tconn, NS(conn, C_WF_CONNECTION), CS_VERBOSE) < SS_SUCCESS) |
780 | return -2; | 780 | return -2; |
781 | 781 | ||
782 | clear_bit(DISCARD_CONCURRENT, &tconn->flags); | 782 | clear_bit(DISCARD_CONCURRENT, &tconn->flags); |
@@ -850,7 +850,7 @@ retry: | |||
850 | } | 850 | } |
851 | } | 851 | } |
852 | 852 | ||
853 | if (tconn->volume0->state.conn <= C_DISCONNECTING) | 853 | if (tconn->cstate <= C_DISCONNECTING) |
854 | goto out_release_sockets; | 854 | goto out_release_sockets; |
855 | if (signal_pending(current)) { | 855 | if (signal_pending(current)) { |
856 | flush_signals(current); | 856 | flush_signals(current); |
@@ -912,7 +912,7 @@ retry: | |||
912 | } | 912 | } |
913 | } | 913 | } |
914 | 914 | ||
915 | if (drbd_request_state(tconn->volume0, NS(conn, C_WF_REPORT_PARAMS)) < SS_SUCCESS) | 915 | if (conn_request_state(tconn, NS(conn, C_WF_REPORT_PARAMS), CS_VERBOSE) < SS_SUCCESS) |
916 | return 0; | 916 | return 0; |
917 | 917 | ||
918 | sock->sk->sk_sndtimeo = tconn->net_conf->timeout*HZ/10; | 918 | sock->sk->sk_sndtimeo = tconn->net_conf->timeout*HZ/10; |
@@ -3817,7 +3817,7 @@ static void drbdd(struct drbd_tconn *tconn) | |||
3817 | 3817 | ||
3818 | if (0) { | 3818 | if (0) { |
3819 | err_out: | 3819 | err_out: |
3820 | drbd_force_state(tconn->volume0, NS(conn, C_PROTOCOL_ERROR)); | 3820 | conn_request_state(tconn, NS(conn, C_PROTOCOL_ERROR), CS_HARD); |
3821 | } | 3821 | } |
3822 | } | 3822 | } |
3823 | 3823 | ||
@@ -3834,10 +3834,10 @@ void drbd_flush_workqueue(struct drbd_conf *mdev) | |||
3834 | 3834 | ||
3835 | static void drbd_disconnect(struct drbd_tconn *tconn) | 3835 | static void drbd_disconnect(struct drbd_tconn *tconn) |
3836 | { | 3836 | { |
3837 | union drbd_state os, ns; | 3837 | enum drbd_conns oc; |
3838 | int rv = SS_UNKNOWN_ERROR; | 3838 | int rv = SS_UNKNOWN_ERROR; |
3839 | 3839 | ||
3840 | if (tconn->volume0->state.conn == C_STANDALONE) | 3840 | if (tconn->cstate == C_STANDALONE) |
3841 | return; | 3841 | return; |
3842 | 3842 | ||
3843 | /* asender does not clean up anything. it must not interfere, either */ | 3843 | /* asender does not clean up anything. it must not interfere, either */ |
@@ -3849,16 +3849,13 @@ static void drbd_disconnect(struct drbd_tconn *tconn) | |||
3849 | conn_info(tconn, "Connection closed\n"); | 3849 | conn_info(tconn, "Connection closed\n"); |
3850 | 3850 | ||
3851 | spin_lock_irq(&tconn->req_lock); | 3851 | spin_lock_irq(&tconn->req_lock); |
3852 | os = tconn->volume0->state; | 3852 | oc = tconn->cstate; |
3853 | if (os.conn >= C_UNCONNECTED) { | 3853 | if (oc >= C_UNCONNECTED) |
3854 | /* Do not restart in case we are C_DISCONNECTING */ | 3854 | rv = _conn_request_state(tconn, NS(conn, C_UNCONNECTED), CS_VERBOSE); |
3855 | ns.i = os.i; | 3855 | |
3856 | ns.conn = C_UNCONNECTED; | ||
3857 | rv = _drbd_set_state(tconn->volume0, ns, CS_VERBOSE, NULL); | ||
3858 | } | ||
3859 | spin_unlock_irq(&tconn->req_lock); | 3856 | spin_unlock_irq(&tconn->req_lock); |
3860 | 3857 | ||
3861 | if (os.conn == C_DISCONNECTING) { | 3858 | if (oc == C_DISCONNECTING) { |
3862 | wait_event(tconn->net_cnt_wait, atomic_read(&tconn->net_cnt) == 0); | 3859 | wait_event(tconn->net_cnt_wait, atomic_read(&tconn->net_cnt) == 0); |
3863 | 3860 | ||
3864 | crypto_free_hash(tconn->cram_hmac_tfm); | 3861 | crypto_free_hash(tconn->cram_hmac_tfm); |
@@ -3866,7 +3863,7 @@ static void drbd_disconnect(struct drbd_tconn *tconn) | |||
3866 | 3863 | ||
3867 | kfree(tconn->net_conf); | 3864 | kfree(tconn->net_conf); |
3868 | tconn->net_conf = NULL; | 3865 | tconn->net_conf = NULL; |
3869 | drbd_request_state(tconn->volume0, NS(conn, C_STANDALONE)); | 3866 | conn_request_state(tconn, NS(conn, C_STANDALONE), CS_VERBOSE); |
3870 | } | 3867 | } |
3871 | } | 3868 | } |
3872 | 3869 | ||
@@ -4240,7 +4237,7 @@ int drbdd_init(struct drbd_thread *thi) | |||
4240 | } | 4237 | } |
4241 | if (h == -1) { | 4238 | if (h == -1) { |
4242 | conn_warn(tconn, "Discarding network configuration.\n"); | 4239 | conn_warn(tconn, "Discarding network configuration.\n"); |
4243 | drbd_force_state(tconn->volume0, NS(conn, C_DISCONNECTING)); | 4240 | conn_request_state(tconn, NS(conn, C_DISCONNECTING), CS_HARD); |
4244 | } | 4241 | } |
4245 | } while (h == 0); | 4242 | } while (h == 0); |
4246 | 4243 | ||
@@ -4709,11 +4706,11 @@ int drbd_asender(struct drbd_thread *thi) | |||
4709 | 4706 | ||
4710 | if (0) { | 4707 | if (0) { |
4711 | reconnect: | 4708 | reconnect: |
4712 | drbd_force_state(tconn->volume0, NS(conn, C_NETWORK_FAILURE)); | 4709 | conn_request_state(tconn, NS(conn, C_NETWORK_FAILURE), CS_HARD); |
4713 | } | 4710 | } |
4714 | if (0) { | 4711 | if (0) { |
4715 | disconnect: | 4712 | disconnect: |
4716 | drbd_force_state(tconn->volume0, NS(conn, C_DISCONNECTING)); | 4713 | conn_request_state(tconn, NS(conn, C_DISCONNECTING), CS_HARD); |
4717 | } | 4714 | } |
4718 | clear_bit(SIGNAL_ASENDER, &tconn->flags); | 4715 | clear_bit(SIGNAL_ASENDER, &tconn->flags); |
4719 | 4716 | ||
diff --git a/drivers/block/drbd/drbd_state.c b/drivers/block/drbd/drbd_state.c index 0100aab1288d..7376d9dc0bc7 100644 --- a/drivers/block/drbd/drbd_state.c +++ b/drivers/block/drbd/drbd_state.c | |||
@@ -43,8 +43,7 @@ int drbd_send_state_req(struct drbd_conf *, union drbd_state, union drbd_state); | |||
43 | static int w_after_state_ch(struct drbd_work *w, int unused); | 43 | static int w_after_state_ch(struct drbd_work *w, int unused); |
44 | static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, | 44 | static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, |
45 | union drbd_state ns, enum chg_state_flags flags); | 45 | union drbd_state ns, enum chg_state_flags flags); |
46 | static void after_conn_state_ch(struct drbd_tconn *tconn, union drbd_state os, | 46 | static void after_all_state_ch(struct drbd_tconn *tconn, union drbd_state ns); |
47 | union drbd_state ns, enum chg_state_flags flags); | ||
48 | static enum drbd_state_rv is_valid_state(struct drbd_conf *, union drbd_state); | 47 | static enum drbd_state_rv is_valid_state(struct drbd_conf *, union drbd_state); |
49 | static enum drbd_state_rv is_valid_soft_transition(union drbd_state, union drbd_state); | 48 | static enum drbd_state_rv is_valid_soft_transition(union drbd_state, union drbd_state); |
50 | static enum drbd_state_rv is_valid_transition(union drbd_state os, union drbd_state ns); | 49 | static enum drbd_state_rv is_valid_transition(union drbd_state os, union drbd_state ns); |
@@ -275,6 +274,51 @@ void print_st_err(struct drbd_conf *mdev, union drbd_state os, | |||
275 | print_st(mdev, "wanted", ns); | 274 | print_st(mdev, "wanted", ns); |
276 | } | 275 | } |
277 | 276 | ||
277 | static void print_state_change(struct drbd_conf *mdev, union drbd_state os, union drbd_state ns, | ||
278 | enum chg_state_flags flags) | ||
279 | { | ||
280 | char *pbp, pb[300]; | ||
281 | pbp = pb; | ||
282 | *pbp = 0; | ||
283 | if (ns.role != os.role) | ||
284 | pbp += sprintf(pbp, "role( %s -> %s ) ", | ||
285 | drbd_role_str(os.role), | ||
286 | drbd_role_str(ns.role)); | ||
287 | if (ns.peer != os.peer) | ||
288 | pbp += sprintf(pbp, "peer( %s -> %s ) ", | ||
289 | drbd_role_str(os.peer), | ||
290 | drbd_role_str(ns.peer)); | ||
291 | if (ns.conn != os.conn && !(flags & CS_NO_CSTATE_CHG)) | ||
292 | pbp += sprintf(pbp, "conn( %s -> %s ) ", | ||
293 | drbd_conn_str(os.conn), | ||
294 | drbd_conn_str(ns.conn)); | ||
295 | if (ns.disk != os.disk) | ||
296 | pbp += sprintf(pbp, "disk( %s -> %s ) ", | ||
297 | drbd_disk_str(os.disk), | ||
298 | drbd_disk_str(ns.disk)); | ||
299 | if (ns.pdsk != os.pdsk) | ||
300 | pbp += sprintf(pbp, "pdsk( %s -> %s ) ", | ||
301 | drbd_disk_str(os.pdsk), | ||
302 | drbd_disk_str(ns.pdsk)); | ||
303 | if (is_susp(ns) != is_susp(os)) | ||
304 | pbp += sprintf(pbp, "susp( %d -> %d ) ", | ||
305 | is_susp(os), | ||
306 | is_susp(ns)); | ||
307 | if (ns.aftr_isp != os.aftr_isp) | ||
308 | pbp += sprintf(pbp, "aftr_isp( %d -> %d ) ", | ||
309 | os.aftr_isp, | ||
310 | ns.aftr_isp); | ||
311 | if (ns.peer_isp != os.peer_isp) | ||
312 | pbp += sprintf(pbp, "peer_isp( %d -> %d ) ", | ||
313 | os.peer_isp, | ||
314 | ns.peer_isp); | ||
315 | if (ns.user_isp != os.user_isp) | ||
316 | pbp += sprintf(pbp, "user_isp( %d -> %d ) ", | ||
317 | os.user_isp, | ||
318 | ns.user_isp); | ||
319 | if (pbp != pb) | ||
320 | dev_info(DEV, "%s\n", pb); | ||
321 | } | ||
278 | 322 | ||
279 | /** | 323 | /** |
280 | * is_valid_state() - Returns an SS_ error code if ns is not valid | 324 | * is_valid_state() - Returns an SS_ error code if ns is not valid |
@@ -704,48 +748,7 @@ __drbd_set_state(struct drbd_conf *mdev, union drbd_state ns, | |||
704 | if (warn_sync_abort) | 748 | if (warn_sync_abort) |
705 | dev_warn(DEV, "%s aborted.\n", warn_sync_abort); | 749 | dev_warn(DEV, "%s aborted.\n", warn_sync_abort); |
706 | 750 | ||
707 | { | 751 | print_state_change(mdev, os, ns, flags); |
708 | char *pbp, pb[300]; | ||
709 | pbp = pb; | ||
710 | *pbp = 0; | ||
711 | if (ns.role != os.role) | ||
712 | pbp += sprintf(pbp, "role( %s -> %s ) ", | ||
713 | drbd_role_str(os.role), | ||
714 | drbd_role_str(ns.role)); | ||
715 | if (ns.peer != os.peer) | ||
716 | pbp += sprintf(pbp, "peer( %s -> %s ) ", | ||
717 | drbd_role_str(os.peer), | ||
718 | drbd_role_str(ns.peer)); | ||
719 | if (ns.conn != os.conn) | ||
720 | pbp += sprintf(pbp, "conn( %s -> %s ) ", | ||
721 | drbd_conn_str(os.conn), | ||
722 | drbd_conn_str(ns.conn)); | ||
723 | if (ns.disk != os.disk) | ||
724 | pbp += sprintf(pbp, "disk( %s -> %s ) ", | ||
725 | drbd_disk_str(os.disk), | ||
726 | drbd_disk_str(ns.disk)); | ||
727 | if (ns.pdsk != os.pdsk) | ||
728 | pbp += sprintf(pbp, "pdsk( %s -> %s ) ", | ||
729 | drbd_disk_str(os.pdsk), | ||
730 | drbd_disk_str(ns.pdsk)); | ||
731 | if (is_susp(ns) != is_susp(os)) | ||
732 | pbp += sprintf(pbp, "susp( %d -> %d ) ", | ||
733 | is_susp(os), | ||
734 | is_susp(ns)); | ||
735 | if (ns.aftr_isp != os.aftr_isp) | ||
736 | pbp += sprintf(pbp, "aftr_isp( %d -> %d ) ", | ||
737 | os.aftr_isp, | ||
738 | ns.aftr_isp); | ||
739 | if (ns.peer_isp != os.peer_isp) | ||
740 | pbp += sprintf(pbp, "peer_isp( %d -> %d ) ", | ||
741 | os.peer_isp, | ||
742 | ns.peer_isp); | ||
743 | if (ns.user_isp != os.user_isp) | ||
744 | pbp += sprintf(pbp, "user_isp( %d -> %d ) ", | ||
745 | os.user_isp, | ||
746 | ns.user_isp); | ||
747 | dev_info(DEV, "%s\n", pb); | ||
748 | } | ||
749 | 752 | ||
750 | /* solve the race between becoming unconfigured, | 753 | /* solve the race between becoming unconfigured, |
751 | * worker doing the cleanup, and | 754 | * worker doing the cleanup, and |
@@ -887,7 +890,7 @@ __drbd_set_state(struct drbd_conf *mdev, union drbd_state ns, | |||
887 | ascw->done = done; | 890 | ascw->done = done; |
888 | drbd_queue_work(&mdev->tconn->data.work, &ascw->w); | 891 | drbd_queue_work(&mdev->tconn->data.work, &ascw->w); |
889 | } else { | 892 | } else { |
890 | dev_warn(DEV, "Could not kmalloc an ascw\n"); | 893 | dev_err(DEV, "Could not kmalloc an ascw\n"); |
891 | } | 894 | } |
892 | 895 | ||
893 | return rv; | 896 | return rv; |
@@ -1239,21 +1242,202 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, | |||
1239 | resume_next_sg(mdev); | 1242 | resume_next_sg(mdev); |
1240 | } | 1243 | } |
1241 | 1244 | ||
1242 | after_conn_state_ch(mdev->tconn, os, ns, flags); | 1245 | after_all_state_ch(mdev->tconn, ns); |
1246 | |||
1243 | drbd_md_sync(mdev); | 1247 | drbd_md_sync(mdev); |
1244 | } | 1248 | } |
1245 | 1249 | ||
1246 | static void after_conn_state_ch(struct drbd_tconn *tconn, union drbd_state os, | 1250 | struct after_conn_state_chg_work { |
1247 | union drbd_state ns, enum chg_state_flags flags) | 1251 | struct drbd_work w; |
1252 | enum drbd_conns oc; | ||
1253 | union drbd_state nms; /* new, max state, over all mdevs */ | ||
1254 | enum chg_state_flags flags; | ||
1255 | }; | ||
1256 | |||
1257 | static void after_all_state_ch(struct drbd_tconn *tconn, union drbd_state ns) | ||
1248 | { | 1258 | { |
1259 | if (ns.disk == D_DISKLESS && ns.conn == C_STANDALONE && ns.role == R_SECONDARY) { | ||
1260 | /* if (test_bit(DEVICE_DYING, &mdev->flags)) TODO: DEVICE_DYING functionality */ | ||
1261 | drbd_thread_stop_nowait(&tconn->worker); | ||
1262 | } | ||
1263 | } | ||
1264 | |||
1265 | static int w_after_conn_state_ch(struct drbd_work *w, int unused) | ||
1266 | { | ||
1267 | struct after_conn_state_chg_work *acscw = | ||
1268 | container_of(w, struct after_conn_state_chg_work, w); | ||
1269 | struct drbd_tconn *tconn = w->tconn; | ||
1270 | enum drbd_conns oc = acscw->oc; | ||
1271 | union drbd_state nms = acscw->nms; | ||
1272 | |||
1273 | kfree(acscw); | ||
1274 | |||
1249 | /* Upon network configuration, we need to start the receiver */ | 1275 | /* Upon network configuration, we need to start the receiver */ |
1250 | if (os.conn == C_STANDALONE && ns.conn == C_UNCONNECTED) | 1276 | if (oc == C_STANDALONE && nms.conn == C_UNCONNECTED) |
1251 | drbd_thread_start(&tconn->receiver); | 1277 | drbd_thread_start(&tconn->receiver); |
1252 | 1278 | ||
1253 | if (ns.disk == D_DISKLESS && | 1279 | //conn_err(tconn, STATE_FMT, STATE_ARGS("nms", nms)); |
1254 | ns.conn == C_STANDALONE && | 1280 | after_all_state_ch(tconn, nms); |
1255 | ns.role == R_SECONDARY) { | 1281 | |
1256 | /* if (test_bit(DEVICE_DYING, &mdev->flags)) TODO: DEVICE_DYING functionality */ | 1282 | return 1; |
1257 | drbd_thread_stop_nowait(&tconn->worker); | 1283 | } |
1284 | |||
1285 | static void print_conn_state_change(struct drbd_tconn *tconn, enum drbd_conns oc, enum drbd_conns nc) | ||
1286 | { | ||
1287 | char *pbp, pb[300]; | ||
1288 | pbp = pb; | ||
1289 | *pbp = 0; | ||
1290 | if (nc != oc) | ||
1291 | pbp += sprintf(pbp, "conn( %s -> %s ) ", | ||
1292 | drbd_conn_str(oc), | ||
1293 | drbd_conn_str(nc)); | ||
1294 | |||
1295 | conn_info(tconn, "%s\n", pb); | ||
1296 | } | ||
1297 | |||
1298 | struct _is_valid_itr_params { | ||
1299 | enum chg_state_flags flags; | ||
1300 | union drbd_state mask, val; | ||
1301 | union drbd_state ms; /* maximal state, over all mdevs */ | ||
1302 | enum drbd_conns oc; | ||
1303 | enum { | ||
1304 | OC_UNINITIALIZED, | ||
1305 | OC_CONSISTENT, | ||
1306 | OC_INCONSISTENT, | ||
1307 | } oc_state; | ||
1308 | }; | ||
1309 | |||
1310 | static int _is_valid_itr_fn(int vnr, void *p, void *data) | ||
1311 | { | ||
1312 | struct drbd_conf *mdev = (struct drbd_conf *)p; | ||
1313 | struct _is_valid_itr_params *params = (struct _is_valid_itr_params *)data; | ||
1314 | enum chg_state_flags flags = params->flags; | ||
1315 | union drbd_state ns, os; | ||
1316 | enum drbd_state_rv rv; | ||
1317 | |||
1318 | os = mdev->state; | ||
1319 | ns = apply_mask_val(os, params->mask, params->val); | ||
1320 | ns = sanitize_state(mdev, ns, NULL); | ||
1321 | rv = is_valid_state(mdev, ns); | ||
1322 | |||
1323 | if (rv < SS_SUCCESS) { | ||
1324 | /* If the old state was illegal as well, then let this happen...*/ | ||
1325 | |||
1326 | if (is_valid_state(mdev, os) == rv) | ||
1327 | rv = is_valid_soft_transition(os, ns); | ||
1328 | } else | ||
1329 | rv = is_valid_soft_transition(os, ns); | ||
1330 | |||
1331 | switch (params->oc_state) { | ||
1332 | case OC_UNINITIALIZED: | ||
1333 | params->oc = os.conn; | ||
1334 | params->oc_state = OC_CONSISTENT; | ||
1335 | break; | ||
1336 | case OC_CONSISTENT: | ||
1337 | if (params->oc != os.conn) | ||
1338 | params->oc_state = OC_INCONSISTENT; | ||
1339 | break; | ||
1340 | case OC_INCONSISTENT: | ||
1341 | break; | ||
1342 | } | ||
1343 | |||
1344 | if (rv < SS_SUCCESS) { | ||
1345 | if (flags & CS_VERBOSE) | ||
1346 | print_st_err(mdev, os, ns, rv); | ||
1347 | return rv; | ||
1348 | } else | ||
1349 | return 0; | ||
1350 | } | ||
1351 | |||
1352 | static int _set_state_itr_fn(int vnr, void *p, void *data) | ||
1353 | { | ||
1354 | struct drbd_conf *mdev = (struct drbd_conf *)p; | ||
1355 | struct _is_valid_itr_params *params = (struct _is_valid_itr_params *)data; | ||
1356 | enum chg_state_flags flags = params->flags; | ||
1357 | union drbd_state os, ns, ms = params->ms; | ||
1358 | enum drbd_state_rv rv; | ||
1359 | |||
1360 | os = mdev->state; | ||
1361 | ns = apply_mask_val(os, params->mask, params->val); | ||
1362 | ns = sanitize_state(mdev, ns, NULL); | ||
1363 | |||
1364 | rv = __drbd_set_state(mdev, ns, flags, NULL); | ||
1365 | |||
1366 | ms.role = max_t(enum drbd_role, mdev->state.role, ms.role); | ||
1367 | ms.peer = max_t(enum drbd_role, mdev->state.peer, ms.peer); | ||
1368 | ms.disk = max_t(enum drbd_role, mdev->state.disk, ms.disk); | ||
1369 | ms.pdsk = max_t(enum drbd_role, mdev->state.pdsk, ms.pdsk); | ||
1370 | params->ms = ms; | ||
1371 | |||
1372 | return 0; | ||
1373 | } | ||
1374 | |||
1375 | enum drbd_state_rv | ||
1376 | _conn_request_state(struct drbd_tconn *tconn, union drbd_state mask, union drbd_state val, | ||
1377 | enum chg_state_flags flags) | ||
1378 | { | ||
1379 | enum drbd_state_rv rv = SS_SUCCESS; | ||
1380 | struct _is_valid_itr_params params; | ||
1381 | struct after_conn_state_chg_work *acscw; | ||
1382 | enum drbd_conns oc = tconn->cstate; | ||
1383 | |||
1384 | read_lock(&global_state_lock); | ||
1385 | |||
1386 | rv = is_valid_conn_transition(oc, val.conn); | ||
1387 | if (rv < SS_SUCCESS) | ||
1388 | goto abort; | ||
1389 | |||
1390 | params.flags = flags; | ||
1391 | params.mask = mask; | ||
1392 | params.val = val; | ||
1393 | params.oc_state = OC_UNINITIALIZED; | ||
1394 | |||
1395 | if (!(flags & CS_HARD)) | ||
1396 | rv = idr_for_each(&tconn->volumes, _is_valid_itr_fn, ¶ms); | ||
1397 | |||
1398 | if (rv == 0) /* idr_for_each semantics */ | ||
1399 | rv = SS_SUCCESS; | ||
1400 | |||
1401 | if (rv < SS_SUCCESS) | ||
1402 | goto abort; | ||
1403 | |||
1404 | if (params.oc_state == OC_CONSISTENT) { | ||
1405 | oc = params.oc; | ||
1406 | print_conn_state_change(tconn, oc, val.conn); | ||
1407 | params.flags |= CS_NO_CSTATE_CHG; | ||
1408 | } | ||
1409 | tconn->cstate = val.conn; | ||
1410 | params.ms.i = 0; | ||
1411 | params.ms.conn = val.conn; | ||
1412 | idr_for_each(&tconn->volumes, _set_state_itr_fn, ¶ms); | ||
1413 | |||
1414 | acscw = kmalloc(sizeof(*acscw), GFP_ATOMIC); | ||
1415 | if (acscw) { | ||
1416 | acscw->oc = oc; | ||
1417 | acscw->nms = params.ms; | ||
1418 | acscw->flags = flags; | ||
1419 | acscw->w.cb = w_after_conn_state_ch; | ||
1420 | acscw->w.tconn = tconn; | ||
1421 | drbd_queue_work(&tconn->data.work, &acscw->w); | ||
1422 | } else { | ||
1423 | conn_err(tconn, "Could not kmalloc an acscw\n"); | ||
1258 | } | 1424 | } |
1425 | |||
1426 | abort: | ||
1427 | read_unlock(&global_state_lock); | ||
1428 | |||
1429 | return rv; | ||
1430 | } | ||
1431 | |||
1432 | enum drbd_state_rv | ||
1433 | conn_request_state(struct drbd_tconn *tconn, union drbd_state mask, union drbd_state val, | ||
1434 | enum chg_state_flags flags) | ||
1435 | { | ||
1436 | enum drbd_state_rv rv; | ||
1437 | |||
1438 | spin_lock_irq(&tconn->req_lock); | ||
1439 | rv = _conn_request_state(tconn, mask, val, flags); | ||
1440 | spin_unlock_irq(&tconn->req_lock); | ||
1441 | |||
1442 | return rv; | ||
1259 | } | 1443 | } |
diff --git a/drivers/block/drbd/drbd_state.h b/drivers/block/drbd/drbd_state.h index 3ec26e2c4c40..d312d84b8410 100644 --- a/drivers/block/drbd/drbd_state.h +++ b/drivers/block/drbd/drbd_state.h | |||
@@ -2,6 +2,7 @@ | |||
2 | #define DRBD_STATE_H | 2 | #define DRBD_STATE_H |
3 | 3 | ||
4 | struct drbd_conf; | 4 | struct drbd_conf; |
5 | struct drbd_tconn; | ||
5 | 6 | ||
6 | /** | 7 | /** |
7 | * DOC: DRBD State macros | 8 | * DOC: DRBD State macros |
@@ -61,6 +62,7 @@ enum chg_state_flags { | |||
61 | CS_WAIT_COMPLETE = 4, | 62 | CS_WAIT_COMPLETE = 4, |
62 | CS_SERIALIZE = 8, | 63 | CS_SERIALIZE = 8, |
63 | CS_ORDERED = CS_WAIT_COMPLETE + CS_SERIALIZE, | 64 | CS_ORDERED = CS_WAIT_COMPLETE + CS_SERIALIZE, |
65 | CS_NO_CSTATE_CHG = 16, /* Do not display changes in cstate. Internal to drbd_state.c */ | ||
64 | }; | 66 | }; |
65 | 67 | ||
66 | extern enum drbd_state_rv drbd_change_state(struct drbd_conf *mdev, | 68 | extern enum drbd_state_rv drbd_change_state(struct drbd_conf *mdev, |
@@ -79,6 +81,14 @@ extern enum drbd_state_rv __drbd_set_state(struct drbd_conf *, union drbd_state, | |||
79 | extern void print_st_err(struct drbd_conf *, union drbd_state, | 81 | extern void print_st_err(struct drbd_conf *, union drbd_state, |
80 | union drbd_state, int); | 82 | union drbd_state, int); |
81 | 83 | ||
84 | enum drbd_state_rv | ||
85 | _conn_request_state(struct drbd_tconn *tconn, union drbd_state mask, union drbd_state val, | ||
86 | enum chg_state_flags flags); | ||
87 | |||
88 | enum drbd_state_rv | ||
89 | conn_request_state(struct drbd_tconn *tconn, union drbd_state mask, union drbd_state val, | ||
90 | enum chg_state_flags flags); | ||
91 | |||
82 | extern void drbd_resume_al(struct drbd_conf *mdev); | 92 | extern void drbd_resume_al(struct drbd_conf *mdev); |
83 | 93 | ||
84 | /** | 94 | /** |
diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index 8539df25bc22..eee017dd6d7d 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c | |||
@@ -1720,11 +1720,10 @@ int drbd_worker(struct drbd_thread *thi) | |||
1720 | list_del_init(&w->list); | 1720 | list_del_init(&w->list); |
1721 | spin_unlock_irq(&tconn->data.work.q_lock); | 1721 | spin_unlock_irq(&tconn->data.work.q_lock); |
1722 | 1722 | ||
1723 | if (!w->cb(w, tconn->volume0->state.conn < C_CONNECTED)) { | 1723 | if (!w->cb(w, tconn->cstate < C_WF_REPORT_PARAMS)) { |
1724 | /* dev_warn(DEV, "worker: a callback failed! \n"); */ | 1724 | /* dev_warn(DEV, "worker: a callback failed! \n"); */ |
1725 | if (tconn->volume0->state.conn >= C_CONNECTED) | 1725 | if (tconn->cstate >= C_WF_REPORT_PARAMS) |
1726 | drbd_force_state(tconn->volume0, | 1726 | conn_request_state(tconn, NS(conn, C_NETWORK_FAILURE), CS_HARD); |
1727 | NS(conn, C_NETWORK_FAILURE)); | ||
1728 | } | 1727 | } |
1729 | } | 1728 | } |
1730 | 1729 | ||