aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPhilipp Reisner <philipp.reisner@linbit.com>2011-02-10 07:45:46 -0500
committerPhilipp Reisner <philipp.reisner@linbit.com>2011-10-14 10:44:58 -0400
commitbbeb641c3e4982d6bba21188545a7fd44ab0a715 (patch)
treeeaceb0498387fcef6ad853a92b4db76d6c246e55
parent56707f9e873108c0173b4edf20ea452e1d2a89d2 (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.h4
-rw-r--r--drivers/block/drbd/drbd_main.c8
-rw-r--r--drivers/block/drbd/drbd_nl.c2
-rw-r--r--drivers/block/drbd/drbd_receiver.c39
-rw-r--r--drivers/block/drbd/drbd_state.c292
-rw-r--r--drivers/block/drbd/drbd_state.h10
-rw-r--r--drivers/block/drbd/drbd_worker.c7
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 {
918struct drbd_tconn { /* is a resource from the config file */ 918struct 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
3835static void drbd_disconnect(struct drbd_tconn *tconn) 3835static 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) {
4711reconnect: 4708reconnect:
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) {
4715disconnect: 4712disconnect:
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);
43static int w_after_state_ch(struct drbd_work *w, int unused); 43static int w_after_state_ch(struct drbd_work *w, int unused);
44static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, 44static 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);
46static void after_conn_state_ch(struct drbd_tconn *tconn, union drbd_state os, 46static void after_all_state_ch(struct drbd_tconn *tconn, union drbd_state ns);
47 union drbd_state ns, enum chg_state_flags flags);
48static enum drbd_state_rv is_valid_state(struct drbd_conf *, union drbd_state); 47static enum drbd_state_rv is_valid_state(struct drbd_conf *, union drbd_state);
49static enum drbd_state_rv is_valid_soft_transition(union drbd_state, union drbd_state); 48static enum drbd_state_rv is_valid_soft_transition(union drbd_state, union drbd_state);
50static enum drbd_state_rv is_valid_transition(union drbd_state os, union drbd_state ns); 49static 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
277static 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
1246static void after_conn_state_ch(struct drbd_tconn *tconn, union drbd_state os, 1250struct 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
1257static 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
1265static 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
1285static 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
1298struct _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
1310static 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
1352static 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
1375enum 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, &params);
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, &params);
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
1426abort:
1427 read_unlock(&global_state_lock);
1428
1429 return rv;
1430}
1431
1432enum drbd_state_rv
1433conn_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
4struct drbd_conf; 4struct drbd_conf;
5struct 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
66extern enum drbd_state_rv drbd_change_state(struct drbd_conf *mdev, 68extern 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,
79extern void print_st_err(struct drbd_conf *, union drbd_state, 81extern void print_st_err(struct drbd_conf *, union drbd_state,
80 union drbd_state, int); 82 union drbd_state, int);
81 83
84enum 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
88enum drbd_state_rv
89conn_request_state(struct drbd_tconn *tconn, union drbd_state mask, union drbd_state val,
90 enum chg_state_flags flags);
91
82extern void drbd_resume_al(struct drbd_conf *mdev); 92extern 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