Merge branch 'for-2.6.39/drivers' of git://git.kernel.dk/linux-2.6-block
[pandora-kernel.git] / drivers / block / drbd / drbd_worker.c
index 7bfeb79..f7e6c92 100644 (file)
@@ -44,15 +44,12 @@ static int w_make_resync_request(struct drbd_conf *mdev,
 
 
 
-/* defined here:
-   drbd_md_io_complete
-   drbd_endio_sec
-   drbd_endio_pri
-
- * more endio handlers:
-   atodb_endio in drbd_actlog.c
-   drbd_bm_async_io_complete in drbd_bitmap.c
-
+/* endio handlers:
+ *   drbd_md_io_complete (defined here)
+ *   drbd_endio_pri (defined here)
+ *   drbd_endio_sec (defined here)
+ *   bm_async_io_complete (defined in drbd_bitmap.c)
+ *
  * For all these callbacks, note the following:
  * The callbacks will be called in irq context by the IDE drivers,
  * and in Softirqs/Tasklets/BH context by the SCSI drivers.
@@ -253,13 +250,6 @@ int w_read_retry_remote(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
        return w_send_read_req(mdev, w, 0);
 }
 
-int w_resync_inactive(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
-{
-       ERR_IF(cancel) return 1;
-       dev_err(DEV, "resync inactive, but callback triggered??\n");
-       return 1; /* Simply ignore this! */
-}
-
 void drbd_csum_ee(struct drbd_conf *mdev, struct crypto_hash *tfm, struct drbd_epoch_entry *e, void *digest)
 {
        struct hash_desc desc;
@@ -376,9 +366,10 @@ static int read_for_csum(struct drbd_conf *mdev, sector_t sector, int size)
        if (drbd_submit_ee(mdev, e, READ, DRBD_FAULT_RS_RD) == 0)
                return 0;
 
-       /* drbd_submit_ee currently fails for one reason only:
-        * not being able to allocate enough bios.
-        * Is dropping the connection going to help? */
+       /* If it failed because of ENOMEM, retry should help.  If it failed
+        * because bio_add_page failed (probably broken lower level driver),
+        * retry may or may not help.
+        * If it does not, you may need to force disconnect. */
        spin_lock_irq(&mdev->req_lock);
        list_del(&e->w.list);
        spin_unlock_irq(&mdev->req_lock);
@@ -389,26 +380,25 @@ defer:
        return -EAGAIN;
 }
 
-void resync_timer_fn(unsigned long data)
+int w_resync_timer(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
 {
-       struct drbd_conf *mdev = (struct drbd_conf *) data;
-       int queue;
-
-       queue = 1;
        switch (mdev->state.conn) {
        case C_VERIFY_S:
-               mdev->resync_work.cb = w_make_ov_request;
+               w_make_ov_request(mdev, w, cancel);
                break;
        case C_SYNC_TARGET:
-               mdev->resync_work.cb = w_make_resync_request;
+               w_make_resync_request(mdev, w, cancel);
                break;
-       default:
-               queue = 0;
-               mdev->resync_work.cb = w_resync_inactive;
        }
 
-       /* harmless race: list_empty outside data.work.q_lock */
-       if (list_empty(&mdev->resync_work.list) && queue)
+       return 1;
+}
+
+void resync_timer_fn(unsigned long data)
+{
+       struct drbd_conf *mdev = (struct drbd_conf *) data;
+
+       if (list_empty(&mdev->resync_work.list))
                drbd_queue_work(&mdev->data.work, &mdev->resync_work);
 }
 
@@ -525,15 +515,6 @@ static int w_make_resync_request(struct drbd_conf *mdev,
        if (unlikely(cancel))
                return 1;
 
-       if (unlikely(mdev->state.conn < C_CONNECTED)) {
-               dev_err(DEV, "Confused in w_make_resync_request()! cstate < Connected");
-               return 0;
-       }
-
-       if (mdev->state.conn != C_SYNC_TARGET)
-               dev_err(DEV, "%s in w_make_resync_request\n",
-                       drbd_conn_str(mdev->state.conn));
-
        if (mdev->rs_total == 0) {
                /* empty resync? */
                drbd_resync_finished(mdev);
@@ -546,7 +527,6 @@ static int w_make_resync_request(struct drbd_conf *mdev,
                   to continue resync with a broken disk makes no sense at
                   all */
                dev_err(DEV, "Disk broke down during resync!\n");
-               mdev->resync_work.cb = w_resync_inactive;
                return 1;
        }
 
@@ -580,7 +560,6 @@ next_sector:
 
                if (bit == DRBD_END_OF_BITMAP) {
                        mdev->bm_resync_fo = drbd_bm_bits(mdev);
-                       mdev->resync_work.cb = w_resync_inactive;
                        put_ldev(mdev);
                        return 1;
                }
@@ -676,7 +655,6 @@ next_sector:
                 * resync data block, and the last bit is cleared.
                 * until then resync "work" is "inactive" ...
                 */
-               mdev->resync_work.cb = w_resync_inactive;
                put_ldev(mdev);
                return 1;
        }
@@ -697,17 +675,11 @@ static int w_make_ov_request(struct drbd_conf *mdev, struct drbd_work *w, int ca
        if (unlikely(cancel))
                return 1;
 
-       if (unlikely(mdev->state.conn < C_CONNECTED)) {
-               dev_err(DEV, "Confused in w_make_ov_request()! cstate < Connected");
-               return 0;
-       }
-
        number = drbd_rs_number_requests(mdev);
 
        sector = mdev->ov_position;
        for (i = 0; i < number; i++) {
                if (sector >= capacity) {
-                       mdev->resync_work.cb = w_resync_inactive;
                        return 1;
                }
 
@@ -738,10 +710,24 @@ static int w_make_ov_request(struct drbd_conf *mdev, struct drbd_work *w, int ca
 }
 
 
+void start_resync_timer_fn(unsigned long data)
+{
+       struct drbd_conf *mdev = (struct drbd_conf *) data;
+
+       drbd_queue_work(&mdev->data.work, &mdev->start_resync_work);
+}
+
 int w_start_resync(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
 {
-       drbd_start_resync(mdev, C_SYNC_SOURCE);
+       if (atomic_read(&mdev->unacked_cnt) || atomic_read(&mdev->rs_pending_cnt)) {
+               dev_warn(DEV, "w_start_resync later...\n");
+               mdev->start_resync_timer.expires = jiffies + HZ/10;
+               add_timer(&mdev->start_resync_timer);
+               return 1;
+       }
 
+       drbd_start_resync(mdev, C_SYNC_SOURCE);
+       clear_bit(AHEAD_TO_SYNC_SOURCE, &mdev->current_epoch->flags);
        return 1;
 }
 
@@ -789,8 +775,7 @@ int drbd_resync_finished(struct drbd_conf *mdev)
                 * queue (or even the read operations for those packets
                 * is not finished by now).   Retry in 100ms. */
 
-               __set_current_state(TASK_INTERRUPTIBLE);
-               schedule_timeout(HZ / 10);
+               schedule_timeout_interruptible(HZ / 10);
                w = kmalloc(sizeof(struct drbd_work), GFP_ATOMIC);
                if (w) {
                        w->cb = w_resync_finished;
@@ -884,14 +869,18 @@ int drbd_resync_finished(struct drbd_conf *mdev)
                        }
                }
 
-               drbd_uuid_set_bm(mdev, 0UL);
-
-               if (mdev->p_uuid) {
-                       /* Now the two UUID sets are equal, update what we
-                        * know of the peer. */
-                       int i;
-                       for (i = UI_CURRENT ; i <= UI_HISTORY_END ; i++)
-                               mdev->p_uuid[i] = mdev->ldev->md.uuid[i];
+               if (!(os.conn == C_VERIFY_S || os.conn == C_VERIFY_T)) {
+                       /* for verify runs, we don't update uuids here,
+                        * so there would be nothing to report. */
+                       drbd_uuid_set_bm(mdev, 0UL);
+                       drbd_print_uuids(mdev, "updated UUIDs");
+                       if (mdev->p_uuid) {
+                               /* Now the two UUID sets are equal, update what we
+                                * know of the peer. */
+                               int i;
+                               for (i = UI_CURRENT ; i <= UI_HISTORY_END ; i++)
+                                       mdev->p_uuid[i] = mdev->ldev->md.uuid[i];
+                       }
                }
        }
 
@@ -988,7 +977,9 @@ int w_e_end_rsdata_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
                put_ldev(mdev);
        }
 
-       if (likely((e->flags & EE_WAS_ERROR) == 0)) {
+       if (mdev->state.conn == C_AHEAD) {
+               ok = drbd_send_ack(mdev, P_RS_CANCEL, e);
+       } else if (likely((e->flags & EE_WAS_ERROR) == 0)) {
                if (likely(mdev->state.pdsk >= D_INCONSISTENT)) {
                        inc_rs_pending(mdev);
                        ok = drbd_send_block(mdev, P_RS_DATA_REPLY, e);
@@ -1090,25 +1081,27 @@ int w_e_end_ov_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
        if (unlikely(cancel))
                goto out;
 
-       if (unlikely((e->flags & EE_WAS_ERROR) != 0))
-               goto out;
-
        digest_size = crypto_hash_digestsize(mdev->verify_tfm);
-       /* FIXME if this allocation fails, online verify will not terminate! */
        digest = kmalloc(digest_size, GFP_NOIO);
-       if (digest) {
-               drbd_csum_ee(mdev, mdev->verify_tfm, e, digest);
-               inc_rs_pending(mdev);
-               ok = drbd_send_drequest_csum(mdev, e->sector, e->size,
-                                            digest, digest_size, P_OV_REPLY);
-               if (!ok)
-                       dec_rs_pending(mdev);
-               kfree(digest);
+       if (!digest) {
+               ok = 0; /* terminate the connection in case the allocation failed */
+               goto out;
        }
 
+       if (likely(!(e->flags & EE_WAS_ERROR)))
+               drbd_csum_ee(mdev, mdev->verify_tfm, e, digest);
+       else
+               memset(digest, 0, digest_size);
+
+       inc_rs_pending(mdev);
+       ok = drbd_send_drequest_csum(mdev, e->sector, e->size,
+                                    digest, digest_size, P_OV_REPLY);
+       if (!ok)
+               dec_rs_pending(mdev);
+       kfree(digest);
+
 out:
        drbd_free_ee(mdev, e);
-
        dec_unacked(mdev);
 
        return ok;
@@ -1158,10 +1151,6 @@ int w_e_end_ov_reply(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
                        eq = !memcmp(digest, di->digest, digest_size);
                        kfree(digest);
                }
-       } else {
-               ok = drbd_send_ack(mdev, P_NEG_RS_DREPLY, e);
-               if (__ratelimit(&drbd_ratelimit_state))
-                       dev_err(DEV, "Sending NegDReply. I guess it gets messy.\n");
        }
 
        dec_unacked(mdev);
@@ -1555,24 +1544,23 @@ void drbd_start_resync(struct drbd_conf *mdev, enum drbd_conns side)
        }
        write_unlock_irq(&global_state_lock);
 
-       if (side == C_SYNC_TARGET)
-               mdev->bm_resync_fo = 0;
-
-       /* Since protocol 96, we must serialize drbd_gen_and_send_sync_uuid
-        * with w_send_oos, or the sync target will get confused as to
-        * how much bits to resync.  We cannot do that always, because for an
-        * empty resync and protocol < 95, we need to do it here, as we call
-        * drbd_resync_finished from here in that case.
-        * We drbd_gen_and_send_sync_uuid here for protocol < 96,
-        * and from after_state_ch otherwise. */
-       if (side == C_SYNC_SOURCE && mdev->agreed_pro_version < 96)
-               drbd_gen_and_send_sync_uuid(mdev);
-
        if (r == SS_SUCCESS) {
                dev_info(DEV, "Began resync as %s (will sync %lu KB [%lu bits set]).\n",
                     drbd_conn_str(ns.conn),
                     (unsigned long) mdev->rs_total << (BM_BLOCK_SHIFT-10),
                     (unsigned long) mdev->rs_total);
+               if (side == C_SYNC_TARGET)
+                       mdev->bm_resync_fo = 0;
+
+               /* Since protocol 96, we must serialize drbd_gen_and_send_sync_uuid
+                * with w_send_oos, or the sync target will get confused as to
+                * how much bits to resync.  We cannot do that always, because for an
+                * empty resync and protocol < 95, we need to do it here, as we call
+                * drbd_resync_finished from here in that case.
+                * We drbd_gen_and_send_sync_uuid here for protocol < 96,
+                * and from after_state_ch otherwise. */
+               if (side == C_SYNC_SOURCE && mdev->agreed_pro_version < 96)
+                       drbd_gen_and_send_sync_uuid(mdev);
 
                if (mdev->agreed_pro_version < 95 && mdev->rs_total == 0) {
                        /* This still has a race (about when exactly the peers