drbd: Killed volume0; last step of multi-volume-enablement
authorPhilipp Reisner <philipp.reisner@linbit.com>
Thu, 10 Feb 2011 12:45:46 +0000 (13:45 +0100)
committerPhilipp Reisner <philipp.reisner@linbit.com>
Fri, 14 Oct 2011 14:44:58 +0000 (16:44 +0200)
Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com>
Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com>
drivers/block/drbd/drbd_int.h
drivers/block/drbd/drbd_main.c
drivers/block/drbd/drbd_nl.c
drivers/block/drbd/drbd_receiver.c
drivers/block/drbd/drbd_state.c
drivers/block/drbd/drbd_state.h
drivers/block/drbd/drbd_worker.c

index e2b59f58a0aa20289a4acdc6f426bfb54b6bad48..f718124c5c82460ef6b0483f9d084099748f7ede 100644 (file)
@@ -918,8 +918,8 @@ enum {
 struct drbd_tconn {                    /* is a resource from the config file */
        char *name;                     /* Resource name */
        struct list_head all_tconn;     /* List of all drbd_tconn, prot by global_state_lock */
-       struct drbd_conf *volume0;      /* TODO: Remove me again */
        struct idr volumes;             /* <tconn, vnr> to mdev mapping */
+       enum drbd_conns cstate;        /* Only C_STANDALONE to C_WF_REPORT_PARAMS */
 
        unsigned long flags;
        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)
        int have_net_conf;
 
        atomic_inc(&tconn->net_cnt);
-       have_net_conf = tconn->volume0->state.conn >= C_UNCONNECTED;
+       have_net_conf = tconn->cstate >= C_UNCONNECTED;
        if (!have_net_conf)
                put_net_conf(tconn);
        return have_net_conf;
index b43ad87a536a49266fc9d61d2867c00cb36dca19..b64b7388ee9d59f5d455f330053a5d5c743fd47b 100644 (file)
@@ -1344,7 +1344,7 @@ static int we_should_drop_the_connection(struct drbd_tconn *tconn, struct socket
        drop_it =   tconn->meta.socket == sock
                || !tconn->asender.task
                || get_t_state(&tconn->asender) != RUNNING
-               || tconn->volume0->state.conn < C_CONNECTED;
+               || tconn->cstate < C_WF_REPORT_PARAMS;
 
        if (drop_it)
                return true;
@@ -1705,9 +1705,9 @@ int drbd_send(struct drbd_tconn *tconn, struct socket *sock,
                        conn_err(tconn, "%s_sendmsg returned %d\n",
                                 sock == tconn->meta.socket ? "msock" : "sock",
                                 rv);
-                       drbd_force_state(tconn->volume0, NS(conn, C_BROKEN_PIPE));
+                       conn_request_state(tconn, NS(conn, C_BROKEN_PIPE), CS_HARD);
                } else
-                       drbd_force_state(tconn->volume0, NS(conn, C_TIMEOUT));
+                       conn_request_state(tconn, NS(conn, C_TIMEOUT), CS_HARD);
        }
 
        return sent;
@@ -2188,6 +2188,7 @@ struct drbd_tconn *drbd_new_tconn(char *name)
        if (!tconn->name)
                goto fail;
 
+       tconn->cstate = C_STANDALONE;
        spin_lock_init(&tconn->req_lock);
        atomic_set(&tconn->net_cnt, 0);
        init_waitqueue_head(&tconn->net_cnt_wait);
@@ -2258,7 +2259,6 @@ struct drbd_conf *drbd_new_device(unsigned int minor)
        if (!zalloc_cpumask_var(&mdev->tconn->cpu_mask, GFP_KERNEL))
                goto out_no_cpumask;
 
-       mdev->tconn->volume0 = mdev;
        mdev->minor = minor;
 
        drbd_init_set_defaults(mdev);
index 0debe589b674a3e23e20c9a5cf85d890d9a2fc90..eeb284aef3c89761e0125f7e8844cf059f6527cc 100644 (file)
@@ -1547,7 +1547,7 @@ static int drbd_nl_net_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp,
        mdev->tconn->int_dig_out=int_dig_out;
        mdev->tconn->int_dig_in=int_dig_in;
        mdev->tconn->int_dig_vv=int_dig_vv;
-       retcode = _drbd_set_state(_NS(mdev, conn, C_UNCONNECTED), CS_VERBOSE, NULL);
+       retcode = _conn_request_state(mdev->tconn, NS(conn, C_UNCONNECTED), CS_VERBOSE);
        spin_unlock_irq(&mdev->tconn->req_lock);
 
        kobject_uevent(&disk_to_dev(mdev->vdisk)->kobj, KOBJ_CHANGE);
index 2b69a15a55dd14c960106e6a20d8af9238065844..27e1eb7ce540bb6cc96e29614d87ed2c4ad3e75a 100644 (file)
@@ -551,7 +551,7 @@ static int drbd_recv(struct drbd_tconn *tconn, void *buf, size_t size)
        set_fs(oldfs);
 
        if (rv != size)
-               drbd_force_state(tconn->volume0, NS(conn, C_BROKEN_PIPE));
+               conn_request_state(tconn, NS(conn, C_BROKEN_PIPE), CS_HARD);
 
        return rv;
 }
@@ -647,7 +647,7 @@ out:
                        conn_err(tconn, "%s failed, err = %d\n", what, err);
                }
                if (disconnect_on_error)
-                       drbd_force_state(tconn->volume0, NS(conn, C_DISCONNECTING));
+                       conn_request_state(tconn, NS(conn, C_DISCONNECTING), CS_HARD);
        }
        put_net_conf(tconn);
        return sock;
@@ -694,7 +694,7 @@ out:
        if (err < 0) {
                if (err != -EAGAIN && err != -EINTR && err != -ERESTARTSYS) {
                        conn_err(tconn, "%s failed, err = %d\n", what, err);
-                       drbd_force_state(tconn->volume0, NS(conn, C_DISCONNECTING));
+                       conn_request_state(tconn, NS(conn, C_DISCONNECTING), CS_HARD);
                }
        }
        put_net_conf(tconn);
@@ -776,7 +776,7 @@ static int drbd_connect(struct drbd_tconn *tconn)
        struct socket *s, *sock, *msock;
        int try, h, ok;
 
-       if (drbd_request_state(tconn->volume0, NS(conn, C_WF_CONNECTION)) < SS_SUCCESS)
+       if (conn_request_state(tconn, NS(conn, C_WF_CONNECTION), CS_VERBOSE) < SS_SUCCESS)
                return -2;
 
        clear_bit(DISCARD_CONCURRENT, &tconn->flags);
@@ -850,7 +850,7 @@ retry:
                        }
                }
 
-               if (tconn->volume0->state.conn <= C_DISCONNECTING)
+               if (tconn->cstate <= C_DISCONNECTING)
                        goto out_release_sockets;
                if (signal_pending(current)) {
                        flush_signals(current);
@@ -912,7 +912,7 @@ retry:
                }
        }
 
-       if (drbd_request_state(tconn->volume0, NS(conn, C_WF_REPORT_PARAMS)) < SS_SUCCESS)
+       if (conn_request_state(tconn, NS(conn, C_WF_REPORT_PARAMS), CS_VERBOSE) < SS_SUCCESS)
                return 0;
 
        sock->sk->sk_sndtimeo = tconn->net_conf->timeout*HZ/10;
@@ -3817,7 +3817,7 @@ static void drbdd(struct drbd_tconn *tconn)
 
        if (0) {
        err_out:
-               drbd_force_state(tconn->volume0, NS(conn, C_PROTOCOL_ERROR));
+               conn_request_state(tconn, NS(conn, C_PROTOCOL_ERROR), CS_HARD);
        }
 }
 
@@ -3834,10 +3834,10 @@ void drbd_flush_workqueue(struct drbd_conf *mdev)
 
 static void drbd_disconnect(struct drbd_tconn *tconn)
 {
-       union drbd_state os, ns;
+       enum drbd_conns oc;
        int rv = SS_UNKNOWN_ERROR;
 
-       if (tconn->volume0->state.conn == C_STANDALONE)
+       if (tconn->cstate == C_STANDALONE)
                return;
 
        /* asender does not clean up anything. it must not interfere, either */
@@ -3849,16 +3849,13 @@ static void drbd_disconnect(struct drbd_tconn *tconn)
        conn_info(tconn, "Connection closed\n");
 
        spin_lock_irq(&tconn->req_lock);
-       os = tconn->volume0->state;
-       if (os.conn >= C_UNCONNECTED) {
-               /* Do not restart in case we are C_DISCONNECTING */
-               ns.i = os.i;
-               ns.conn = C_UNCONNECTED;
-               rv = _drbd_set_state(tconn->volume0, ns, CS_VERBOSE, NULL);
-       }
+       oc = tconn->cstate;
+       if (oc >= C_UNCONNECTED)
+               rv = _conn_request_state(tconn, NS(conn, C_UNCONNECTED), CS_VERBOSE);
+
        spin_unlock_irq(&tconn->req_lock);
 
-       if (os.conn == C_DISCONNECTING) {
+       if (oc == C_DISCONNECTING) {
                wait_event(tconn->net_cnt_wait, atomic_read(&tconn->net_cnt) == 0);
 
                crypto_free_hash(tconn->cram_hmac_tfm);
@@ -3866,7 +3863,7 @@ static void drbd_disconnect(struct drbd_tconn *tconn)
 
                kfree(tconn->net_conf);
                tconn->net_conf = NULL;
-               drbd_request_state(tconn->volume0, NS(conn, C_STANDALONE));
+               conn_request_state(tconn, NS(conn, C_STANDALONE), CS_VERBOSE);
        }
 }
 
@@ -4240,7 +4237,7 @@ int drbdd_init(struct drbd_thread *thi)
                }
                if (h == -1) {
                        conn_warn(tconn, "Discarding network configuration.\n");
-                       drbd_force_state(tconn->volume0, NS(conn, C_DISCONNECTING));
+                       conn_request_state(tconn, NS(conn, C_DISCONNECTING), CS_HARD);
                }
        } while (h == 0);
 
@@ -4709,11 +4706,11 @@ int drbd_asender(struct drbd_thread *thi)
 
        if (0) {
 reconnect:
-               drbd_force_state(tconn->volume0, NS(conn, C_NETWORK_FAILURE));
+               conn_request_state(tconn, NS(conn, C_NETWORK_FAILURE), CS_HARD);
        }
        if (0) {
 disconnect:
-               drbd_force_state(tconn->volume0, NS(conn, C_DISCONNECTING));
+               conn_request_state(tconn, NS(conn, C_DISCONNECTING), CS_HARD);
        }
        clear_bit(SIGNAL_ASENDER, &tconn->flags);
 
index 0100aab1288de6cc14822c1a4f9a229b1f290f17..7376d9dc0bc7915290ef9b1a0e45ac5bf3f91e09 100644 (file)
@@ -43,8 +43,7 @@ int drbd_send_state_req(struct drbd_conf *, union drbd_state, union drbd_state);
 static int w_after_state_ch(struct drbd_work *w, int unused);
 static void after_state_ch(struct drbd_conf *mdev, union drbd_state os,
                           union drbd_state ns, enum chg_state_flags flags);
-static void after_conn_state_ch(struct drbd_tconn *tconn, union drbd_state os,
-                               union drbd_state ns, enum chg_state_flags flags);
+static void after_all_state_ch(struct drbd_tconn *tconn, union drbd_state ns);
 static enum drbd_state_rv is_valid_state(struct drbd_conf *, union drbd_state);
 static enum drbd_state_rv is_valid_soft_transition(union drbd_state, union drbd_state);
 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,
        print_st(mdev, "wanted", ns);
 }
 
+static void print_state_change(struct drbd_conf *mdev, union drbd_state os, union drbd_state ns,
+                              enum chg_state_flags flags)
+{
+       char *pbp, pb[300];
+       pbp = pb;
+       *pbp = 0;
+       if (ns.role != os.role)
+               pbp += sprintf(pbp, "role( %s -> %s ) ",
+                              drbd_role_str(os.role),
+                              drbd_role_str(ns.role));
+       if (ns.peer != os.peer)
+               pbp += sprintf(pbp, "peer( %s -> %s ) ",
+                              drbd_role_str(os.peer),
+                              drbd_role_str(ns.peer));
+       if (ns.conn != os.conn && !(flags & CS_NO_CSTATE_CHG))
+               pbp += sprintf(pbp, "conn( %s -> %s ) ",
+                              drbd_conn_str(os.conn),
+                              drbd_conn_str(ns.conn));
+       if (ns.disk != os.disk)
+               pbp += sprintf(pbp, "disk( %s -> %s ) ",
+                              drbd_disk_str(os.disk),
+                              drbd_disk_str(ns.disk));
+       if (ns.pdsk != os.pdsk)
+               pbp += sprintf(pbp, "pdsk( %s -> %s ) ",
+                              drbd_disk_str(os.pdsk),
+                              drbd_disk_str(ns.pdsk));
+       if (is_susp(ns) != is_susp(os))
+               pbp += sprintf(pbp, "susp( %d -> %d ) ",
+                              is_susp(os),
+                              is_susp(ns));
+       if (ns.aftr_isp != os.aftr_isp)
+               pbp += sprintf(pbp, "aftr_isp( %d -> %d ) ",
+                              os.aftr_isp,
+                              ns.aftr_isp);
+       if (ns.peer_isp != os.peer_isp)
+               pbp += sprintf(pbp, "peer_isp( %d -> %d ) ",
+                              os.peer_isp,
+                              ns.peer_isp);
+       if (ns.user_isp != os.user_isp)
+               pbp += sprintf(pbp, "user_isp( %d -> %d ) ",
+                              os.user_isp,
+                              ns.user_isp);
+       if (pbp != pb)
+               dev_info(DEV, "%s\n", pb);
+}
 
 /**
  * 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,
        if (warn_sync_abort)
                dev_warn(DEV, "%s aborted.\n", warn_sync_abort);
 
-       {
-       char *pbp, pb[300];
-       pbp = pb;
-       *pbp = 0;
-       if (ns.role != os.role)
-               pbp += sprintf(pbp, "role( %s -> %s ) ",
-                              drbd_role_str(os.role),
-                              drbd_role_str(ns.role));
-       if (ns.peer != os.peer)
-               pbp += sprintf(pbp, "peer( %s -> %s ) ",
-                              drbd_role_str(os.peer),
-                              drbd_role_str(ns.peer));
-       if (ns.conn != os.conn)
-               pbp += sprintf(pbp, "conn( %s -> %s ) ",
-                              drbd_conn_str(os.conn),
-                              drbd_conn_str(ns.conn));
-       if (ns.disk != os.disk)
-               pbp += sprintf(pbp, "disk( %s -> %s ) ",
-                              drbd_disk_str(os.disk),
-                              drbd_disk_str(ns.disk));
-       if (ns.pdsk != os.pdsk)
-               pbp += sprintf(pbp, "pdsk( %s -> %s ) ",
-                              drbd_disk_str(os.pdsk),
-                              drbd_disk_str(ns.pdsk));
-       if (is_susp(ns) != is_susp(os))
-               pbp += sprintf(pbp, "susp( %d -> %d ) ",
-                              is_susp(os),
-                              is_susp(ns));
-       if (ns.aftr_isp != os.aftr_isp)
-               pbp += sprintf(pbp, "aftr_isp( %d -> %d ) ",
-                              os.aftr_isp,
-                              ns.aftr_isp);
-       if (ns.peer_isp != os.peer_isp)
-               pbp += sprintf(pbp, "peer_isp( %d -> %d ) ",
-                              os.peer_isp,
-                              ns.peer_isp);
-       if (ns.user_isp != os.user_isp)
-               pbp += sprintf(pbp, "user_isp( %d -> %d ) ",
-                              os.user_isp,
-                              ns.user_isp);
-       dev_info(DEV, "%s\n", pb);
-       }
+       print_state_change(mdev, os, ns, flags);
 
        /* solve the race between becoming unconfigured,
         * worker doing the cleanup, and
@@ -887,7 +890,7 @@ __drbd_set_state(struct drbd_conf *mdev, union drbd_state ns,
                ascw->done = done;
                drbd_queue_work(&mdev->tconn->data.work, &ascw->w);
        } else {
-               dev_warn(DEV, "Could not kmalloc an ascw\n");
+               dev_err(DEV, "Could not kmalloc an ascw\n");
        }
 
        return rv;
@@ -1239,21 +1242,202 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os,
                        resume_next_sg(mdev);
        }
 
-       after_conn_state_ch(mdev->tconn, os, ns, flags);
+       after_all_state_ch(mdev->tconn, ns);
+
        drbd_md_sync(mdev);
 }
 
-static void after_conn_state_ch(struct drbd_tconn *tconn, union drbd_state os,
-                               union drbd_state ns, enum chg_state_flags flags)
+struct after_conn_state_chg_work {
+       struct drbd_work w;
+       enum drbd_conns oc;
+       union drbd_state nms; /* new, max state, over all mdevs */
+       enum chg_state_flags flags;
+};
+
+static void after_all_state_ch(struct drbd_tconn *tconn, union drbd_state ns)
 {
+       if (ns.disk == D_DISKLESS && ns.conn == C_STANDALONE && ns.role == R_SECONDARY) {
+               /* if (test_bit(DEVICE_DYING, &mdev->flags)) TODO: DEVICE_DYING functionality */
+               drbd_thread_stop_nowait(&tconn->worker);
+       }
+}
+
+static int w_after_conn_state_ch(struct drbd_work *w, int unused)
+{
+       struct after_conn_state_chg_work *acscw =
+               container_of(w, struct after_conn_state_chg_work, w);
+       struct drbd_tconn *tconn = w->tconn;
+       enum drbd_conns oc = acscw->oc;
+       union drbd_state nms = acscw->nms;
+
+       kfree(acscw);
+
        /* Upon network configuration, we need to start the receiver */
-       if (os.conn == C_STANDALONE && ns.conn == C_UNCONNECTED)
+       if (oc == C_STANDALONE && nms.conn == C_UNCONNECTED)
                drbd_thread_start(&tconn->receiver);
 
-       if (ns.disk == D_DISKLESS &&
-           ns.conn == C_STANDALONE &&
-           ns.role == R_SECONDARY) {
-               /* if (test_bit(DEVICE_DYING, &mdev->flags)) TODO: DEVICE_DYING functionality */
-               drbd_thread_stop_nowait(&tconn->worker);
+       //conn_err(tconn, STATE_FMT, STATE_ARGS("nms", nms));
+       after_all_state_ch(tconn, nms);
+
+       return 1;
+}
+
+static void print_conn_state_change(struct drbd_tconn *tconn, enum drbd_conns oc, enum drbd_conns nc)
+{
+       char *pbp, pb[300];
+       pbp = pb;
+       *pbp = 0;
+       if (nc != oc)
+               pbp += sprintf(pbp, "conn( %s -> %s ) ",
+                              drbd_conn_str(oc),
+                              drbd_conn_str(nc));
+
+       conn_info(tconn, "%s\n", pb);
+}
+
+struct _is_valid_itr_params {
+       enum chg_state_flags flags;
+       union drbd_state mask, val;
+       union drbd_state ms; /* maximal state, over all mdevs */
+       enum drbd_conns oc;
+       enum {
+               OC_UNINITIALIZED,
+               OC_CONSISTENT,
+               OC_INCONSISTENT,
+       } oc_state;
+};
+
+static int _is_valid_itr_fn(int vnr, void *p, void *data)
+{
+       struct drbd_conf *mdev = (struct drbd_conf *)p;
+       struct _is_valid_itr_params *params = (struct _is_valid_itr_params *)data;
+       enum chg_state_flags flags = params->flags;
+       union drbd_state ns, os;
+       enum drbd_state_rv rv;
+
+       os = mdev->state;
+       ns = apply_mask_val(os, params->mask, params->val);
+       ns = sanitize_state(mdev, ns, NULL);
+       rv = is_valid_state(mdev, ns);
+
+       if (rv < SS_SUCCESS) {
+               /* If the old state was illegal as well, then let this happen...*/
+
+               if (is_valid_state(mdev, os) == rv)
+                       rv = is_valid_soft_transition(os, ns);
+       } else
+               rv = is_valid_soft_transition(os, ns);
+
+       switch (params->oc_state) {
+       case OC_UNINITIALIZED:
+               params->oc = os.conn;
+               params->oc_state = OC_CONSISTENT;
+               break;
+       case OC_CONSISTENT:
+               if (params->oc != os.conn)
+                       params->oc_state = OC_INCONSISTENT;
+               break;
+       case OC_INCONSISTENT:
+               break;
+       }
+
+       if (rv < SS_SUCCESS) {
+               if (flags & CS_VERBOSE)
+                       print_st_err(mdev, os, ns, rv);
+               return rv;
+       } else
+               return 0;
+}
+
+static int _set_state_itr_fn(int vnr, void *p, void *data)
+{
+       struct drbd_conf *mdev = (struct drbd_conf *)p;
+       struct _is_valid_itr_params *params = (struct _is_valid_itr_params *)data;
+       enum chg_state_flags flags = params->flags;
+       union drbd_state os, ns, ms = params->ms;
+       enum drbd_state_rv rv;
+
+       os = mdev->state;
+       ns = apply_mask_val(os, params->mask, params->val);
+       ns = sanitize_state(mdev, ns, NULL);
+
+       rv = __drbd_set_state(mdev, ns, flags, NULL);
+
+       ms.role = max_t(enum drbd_role, mdev->state.role, ms.role);
+       ms.peer = max_t(enum drbd_role, mdev->state.peer, ms.peer);
+       ms.disk = max_t(enum drbd_role, mdev->state.disk, ms.disk);
+       ms.pdsk = max_t(enum drbd_role, mdev->state.pdsk, ms.pdsk);
+       params->ms = ms;
+
+       return 0;
+}
+
+enum drbd_state_rv
+_conn_request_state(struct drbd_tconn *tconn, union drbd_state mask, union drbd_state val,
+                   enum chg_state_flags flags)
+{
+       enum drbd_state_rv rv = SS_SUCCESS;
+       struct _is_valid_itr_params params;
+       struct after_conn_state_chg_work *acscw;
+       enum drbd_conns oc = tconn->cstate;
+
+       read_lock(&global_state_lock);
+
+       rv = is_valid_conn_transition(oc, val.conn);
+       if (rv < SS_SUCCESS)
+               goto abort;
+
+       params.flags = flags;
+       params.mask = mask;
+       params.val = val;
+       params.oc_state = OC_UNINITIALIZED;
+
+       if (!(flags & CS_HARD))
+               rv = idr_for_each(&tconn->volumes, _is_valid_itr_fn, &params);
+
+       if (rv == 0)  /* idr_for_each semantics */
+               rv = SS_SUCCESS;
+
+       if (rv < SS_SUCCESS)
+               goto abort;
+
+       if (params.oc_state == OC_CONSISTENT) {
+               oc = params.oc;
+               print_conn_state_change(tconn, oc, val.conn);
+               params.flags |= CS_NO_CSTATE_CHG;
+       }
+       tconn->cstate = val.conn;
+       params.ms.i = 0;
+       params.ms.conn = val.conn;
+       idr_for_each(&tconn->volumes, _set_state_itr_fn, &params);
+
+       acscw = kmalloc(sizeof(*acscw), GFP_ATOMIC);
+       if (acscw) {
+               acscw->oc = oc;
+               acscw->nms = params.ms;
+               acscw->flags = flags;
+               acscw->w.cb = w_after_conn_state_ch;
+               acscw->w.tconn = tconn;
+               drbd_queue_work(&tconn->data.work, &acscw->w);
+       } else {
+               conn_err(tconn, "Could not kmalloc an acscw\n");
        }
+
+abort:
+       read_unlock(&global_state_lock);
+
+       return rv;
+}
+
+enum drbd_state_rv
+conn_request_state(struct drbd_tconn *tconn, union drbd_state mask, union drbd_state val,
+                  enum chg_state_flags flags)
+{
+       enum drbd_state_rv rv;
+
+       spin_lock_irq(&tconn->req_lock);
+       rv = _conn_request_state(tconn, mask, val, flags);
+       spin_unlock_irq(&tconn->req_lock);
+
+       return rv;
 }
index 3ec26e2c4c40b9ad0de53a8daa9c6c9268d1110a..d312d84b8410708f8ee027839c74c739afee5397 100644 (file)
@@ -2,6 +2,7 @@
 #define DRBD_STATE_H
 
 struct drbd_conf;
+struct drbd_tconn;
 
 /**
  * DOC: DRBD State macros
@@ -61,6 +62,7 @@ enum chg_state_flags {
        CS_WAIT_COMPLETE = 4,
        CS_SERIALIZE    = 8,
        CS_ORDERED      = CS_WAIT_COMPLETE + CS_SERIALIZE,
+       CS_NO_CSTATE_CHG = 16, /* Do not display changes in cstate. Internal to drbd_state.c */
 };
 
 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,
 extern void print_st_err(struct drbd_conf *, union drbd_state,
                        union drbd_state, int);
 
+enum drbd_state_rv
+_conn_request_state(struct drbd_tconn *tconn, union drbd_state mask, union drbd_state val,
+                   enum chg_state_flags flags);
+
+enum drbd_state_rv
+conn_request_state(struct drbd_tconn *tconn, union drbd_state mask, union drbd_state val,
+                  enum chg_state_flags flags);
+
 extern void drbd_resume_al(struct drbd_conf *mdev);
 
 /**
index 8539df25bc22851dc03994e5a03a6f33d48082f9..eee017dd6d7d24a14444a0dce2acfae1bbdcef1a 100644 (file)
@@ -1720,11 +1720,10 @@ int drbd_worker(struct drbd_thread *thi)
                list_del_init(&w->list);
                spin_unlock_irq(&tconn->data.work.q_lock);
 
-               if (!w->cb(w, tconn->volume0->state.conn < C_CONNECTED)) {
+               if (!w->cb(w, tconn->cstate < C_WF_REPORT_PARAMS)) {
                        /* dev_warn(DEV, "worker: a callback failed! \n"); */
-                       if (tconn->volume0->state.conn >= C_CONNECTED)
-                               drbd_force_state(tconn->volume0,
-                                                NS(conn, C_NETWORK_FAILURE));
+                       if (tconn->cstate >= C_WF_REPORT_PARAMS)
+                               conn_request_state(tconn, NS(conn, C_NETWORK_FAILURE), CS_HARD);
                }
        }