|
@@ -1624,35 +1624,53 @@ void drbd_start_resync(struct drbd_conf *mdev, enum drbd_conns side)
|
|
|
drbd_state_unlock(mdev);
|
|
|
}
|
|
|
|
|
|
+static int _worker_dying(int vnr, void *p, void *data)
|
|
|
+{
|
|
|
+ struct drbd_conf *mdev = (struct drbd_conf *)p;
|
|
|
+
|
|
|
+ D_ASSERT(mdev->state.disk == D_DISKLESS && mdev->state.conn == C_STANDALONE);
|
|
|
+ /* _drbd_set_state only uses stop_nowait.
|
|
|
+ * wait here for the exiting receiver. */
|
|
|
+ drbd_thread_stop(&mdev->tconn->receiver);
|
|
|
+ drbd_mdev_cleanup(mdev);
|
|
|
+
|
|
|
+ clear_bit(DEVICE_DYING, &mdev->flags);
|
|
|
+ clear_bit(CONFIG_PENDING, &mdev->flags);
|
|
|
+ wake_up(&mdev->state_wait);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
int drbd_worker(struct drbd_thread *thi)
|
|
|
{
|
|
|
- struct drbd_conf *mdev = thi->mdev;
|
|
|
+ struct drbd_tconn *tconn = thi->mdev->tconn;
|
|
|
struct drbd_work *w = NULL;
|
|
|
LIST_HEAD(work_list);
|
|
|
- int intr = 0, i;
|
|
|
+ int intr = 0;
|
|
|
|
|
|
while (get_t_state(thi) == RUNNING) {
|
|
|
drbd_thread_current_set_cpu(thi);
|
|
|
|
|
|
- if (down_trylock(&mdev->tconn->data.work.s)) {
|
|
|
- mutex_lock(&mdev->tconn->data.mutex);
|
|
|
- if (mdev->tconn->data.socket && !mdev->tconn->net_conf->no_cork)
|
|
|
- drbd_tcp_uncork(mdev->tconn->data.socket);
|
|
|
- mutex_unlock(&mdev->tconn->data.mutex);
|
|
|
+ if (down_trylock(&tconn->data.work.s)) {
|
|
|
+ mutex_lock(&tconn->data.mutex);
|
|
|
+ if (tconn->data.socket && !tconn->net_conf->no_cork)
|
|
|
+ drbd_tcp_uncork(tconn->data.socket);
|
|
|
+ mutex_unlock(&tconn->data.mutex);
|
|
|
|
|
|
- intr = down_interruptible(&mdev->tconn->data.work.s);
|
|
|
+ intr = down_interruptible(&tconn->data.work.s);
|
|
|
|
|
|
- mutex_lock(&mdev->tconn->data.mutex);
|
|
|
- if (mdev->tconn->data.socket && !mdev->tconn->net_conf->no_cork)
|
|
|
- drbd_tcp_cork(mdev->tconn->data.socket);
|
|
|
- mutex_unlock(&mdev->tconn->data.mutex);
|
|
|
+ mutex_lock(&tconn->data.mutex);
|
|
|
+ if (tconn->data.socket && !tconn->net_conf->no_cork)
|
|
|
+ drbd_tcp_cork(tconn->data.socket);
|
|
|
+ mutex_unlock(&tconn->data.mutex);
|
|
|
}
|
|
|
|
|
|
if (intr) {
|
|
|
- D_ASSERT(intr == -EINTR);
|
|
|
flush_signals(current);
|
|
|
- if (!expect(get_t_state(thi) != RUNNING))
|
|
|
+ if (get_t_state(thi) == RUNNING) {
|
|
|
+ conn_warn(tconn, "Worker got an unexpected signal\n");
|
|
|
continue;
|
|
|
+ }
|
|
|
break;
|
|
|
}
|
|
|
|
|
@@ -1663,8 +1681,8 @@ int drbd_worker(struct drbd_thread *thi)
|
|
|
this... */
|
|
|
|
|
|
w = NULL;
|
|
|
- spin_lock_irq(&mdev->tconn->data.work.q_lock);
|
|
|
- if (!expect(!list_empty(&mdev->tconn->data.work.q))) {
|
|
|
+ spin_lock_irq(&tconn->data.work.q_lock);
|
|
|
+ if (list_empty(&tconn->data.work.q)) {
|
|
|
/* something terribly wrong in our logic.
|
|
|
* we were able to down() the semaphore,
|
|
|
* but the list is empty... doh.
|
|
@@ -1676,57 +1694,44 @@ int drbd_worker(struct drbd_thread *thi)
|
|
|
*
|
|
|
* I'll try to get away just starting over this loop.
|
|
|
*/
|
|
|
- spin_unlock_irq(&mdev->tconn->data.work.q_lock);
|
|
|
+ conn_warn(tconn, "Work list unexpectedly empty\n");
|
|
|
+ spin_unlock_irq(&tconn->data.work.q_lock);
|
|
|
continue;
|
|
|
}
|
|
|
- w = list_entry(mdev->tconn->data.work.q.next, struct drbd_work, list);
|
|
|
+ w = list_entry(tconn->data.work.q.next, struct drbd_work, list);
|
|
|
list_del_init(&w->list);
|
|
|
- spin_unlock_irq(&mdev->tconn->data.work.q_lock);
|
|
|
+ spin_unlock_irq(&tconn->data.work.q_lock);
|
|
|
|
|
|
- if (!w->cb(mdev, w, mdev->state.conn < C_CONNECTED)) {
|
|
|
+ if (!w->cb(w->mdev, w, tconn->volume0->state.conn < C_CONNECTED)) {
|
|
|
/* dev_warn(DEV, "worker: a callback failed! \n"); */
|
|
|
- if (mdev->state.conn >= C_CONNECTED)
|
|
|
- drbd_force_state(mdev,
|
|
|
- NS(conn, C_NETWORK_FAILURE));
|
|
|
+ if (tconn->volume0->state.conn >= C_CONNECTED)
|
|
|
+ drbd_force_state(tconn->volume0,
|
|
|
+ NS(conn, C_NETWORK_FAILURE));
|
|
|
}
|
|
|
}
|
|
|
- D_ASSERT(test_bit(DEVICE_DYING, &mdev->flags));
|
|
|
- D_ASSERT(test_bit(CONFIG_PENDING, &mdev->flags));
|
|
|
|
|
|
- spin_lock_irq(&mdev->tconn->data.work.q_lock);
|
|
|
- i = 0;
|
|
|
- while (!list_empty(&mdev->tconn->data.work.q)) {
|
|
|
- list_splice_init(&mdev->tconn->data.work.q, &work_list);
|
|
|
- spin_unlock_irq(&mdev->tconn->data.work.q_lock);
|
|
|
+ spin_lock_irq(&tconn->data.work.q_lock);
|
|
|
+ while (!list_empty(&tconn->data.work.q)) {
|
|
|
+ list_splice_init(&tconn->data.work.q, &work_list);
|
|
|
+ spin_unlock_irq(&tconn->data.work.q_lock);
|
|
|
|
|
|
while (!list_empty(&work_list)) {
|
|
|
w = list_entry(work_list.next, struct drbd_work, list);
|
|
|
list_del_init(&w->list);
|
|
|
- w->cb(mdev, w, 1);
|
|
|
- i++; /* dead debugging code */
|
|
|
+ w->cb(w->mdev, w, 1);
|
|
|
}
|
|
|
|
|
|
- spin_lock_irq(&mdev->tconn->data.work.q_lock);
|
|
|
+ spin_lock_irq(&tconn->data.work.q_lock);
|
|
|
}
|
|
|
- sema_init(&mdev->tconn->data.work.s, 0);
|
|
|
+ sema_init(&tconn->data.work.s, 0);
|
|
|
/* DANGEROUS race: if someone did queue his work within the spinlock,
|
|
|
* but up() ed outside the spinlock, we could get an up() on the
|
|
|
* semaphore without corresponding list entry.
|
|
|
* So don't do that.
|
|
|
*/
|
|
|
- spin_unlock_irq(&mdev->tconn->data.work.q_lock);
|
|
|
+ spin_unlock_irq(&tconn->data.work.q_lock);
|
|
|
|
|
|
- D_ASSERT(mdev->state.disk == D_DISKLESS && mdev->state.conn == C_STANDALONE);
|
|
|
- /* _drbd_set_state only uses stop_nowait.
|
|
|
- * wait here for the exiting receiver. */
|
|
|
- drbd_thread_stop(&mdev->tconn->receiver);
|
|
|
- drbd_mdev_cleanup(mdev);
|
|
|
-
|
|
|
- dev_info(DEV, "worker terminated\n");
|
|
|
-
|
|
|
- clear_bit(DEVICE_DYING, &mdev->flags);
|
|
|
- clear_bit(CONFIG_PENDING, &mdev->flags);
|
|
|
- wake_up(&mdev->state_wait);
|
|
|
+ idr_for_each(&tconn->volumes, _worker_dying, NULL);
|
|
|
|
|
|
return 0;
|
|
|
}
|