Merge branch 'imx-for-2.6.38' of git://git.pengutronix.de/git/ukl/linux-2.6 into...
[pandora-kernel.git] / drivers / block / drbd / drbd_actlog.c
index 9400845..ba95cba 100644 (file)
@@ -78,11 +78,10 @@ static int _drbd_md_sync_page_io(struct drbd_conf *mdev,
        init_completion(&md_io.event);
        md_io.error = 0;
 
-       if ((rw & WRITE) && !test_bit(MD_NO_BARRIER, &mdev->flags))
-               rw |= REQ_HARDBARRIER;
+       if ((rw & WRITE) && !test_bit(MD_NO_FUA, &mdev->flags))
+               rw |= REQ_FUA;
        rw |= REQ_UNPLUG | REQ_SYNC;
 
- retry:
        bio = bio_alloc(GFP_NOIO, 1);
        bio->bi_bdev = bdev->md_bdev;
        bio->bi_sector = sector;
@@ -100,17 +99,6 @@ static int _drbd_md_sync_page_io(struct drbd_conf *mdev,
        wait_for_completion(&md_io.event);
        ok = bio_flagged(bio, BIO_UPTODATE) && md_io.error == 0;
 
-       /* check for unsupported barrier op.
-        * would rather check on EOPNOTSUPP, but that is not reliable.
-        * don't try again for ANY return value != 0 */
-       if (unlikely((bio->bi_rw & REQ_HARDBARRIER) && !ok)) {
-               /* Try again with no barrier */
-               dev_warn(DEV, "Barriers not supported on meta data device - disabling\n");
-               set_bit(MD_NO_BARRIER, &mdev->flags);
-               rw &= ~REQ_HARDBARRIER;
-               bio_put(bio);
-               goto retry;
-       }
  out:
        bio_put(bio);
        return ok;
@@ -284,18 +272,32 @@ w_al_write_transaction(struct drbd_conf *mdev, struct drbd_work *w, int unused)
        u32 xor_sum = 0;
 
        if (!get_ldev(mdev)) {
-               dev_err(DEV, "get_ldev() failed in w_al_write_transaction\n");
+               dev_err(DEV,
+                       "disk is %s, cannot start al transaction (-%d +%d)\n",
+                       drbd_disk_str(mdev->state.disk), evicted, new_enr);
                complete(&((struct update_al_work *)w)->event);
                return 1;
        }
        /* do we have to do a bitmap write, first?
         * TODO reduce maximum latency:
         * submit both bios, then wait for both,
-        * instead of doing two synchronous sector writes. */
+        * instead of doing two synchronous sector writes.
+        * For now, we must not write the transaction,
+        * if we cannot write out the bitmap of the evicted extent. */
        if (mdev->state.conn < C_CONNECTED && evicted != LC_FREE)
                drbd_bm_write_sect(mdev, evicted/AL_EXT_PER_BM_SECT);
 
-       mutex_lock(&mdev->md_io_mutex); /* protects md_io_page, al_tr_cycle, ... */
+       /* The bitmap write may have failed, causing a state change. */
+       if (mdev->state.disk < D_INCONSISTENT) {
+               dev_err(DEV,
+                       "disk is %s, cannot write al transaction (-%d +%d)\n",
+                       drbd_disk_str(mdev->state.disk), evicted, new_enr);
+               complete(&((struct update_al_work *)w)->event);
+               put_ldev(mdev);
+               return 1;
+       }
+
+       mutex_lock(&mdev->md_io_mutex); /* protects md_io_buffer, al_tr_cycle, ... */
        buffer = (struct al_transaction *)page_address(mdev->md_io_page);
 
        buffer->magic = __constant_cpu_to_be32(DRBD_MAGIC);
@@ -739,7 +741,7 @@ void drbd_al_apply_to_bm(struct drbd_conf *mdev)
        unsigned int enr;
        unsigned long add = 0;
        char ppb[10];
-       int i;
+       int i, tmp;
 
        wait_event(mdev->al_wait, lc_try_lock(mdev->act_log));
 
@@ -747,7 +749,9 @@ void drbd_al_apply_to_bm(struct drbd_conf *mdev)
                enr = lc_element_by_index(mdev->act_log, i)->lc_number;
                if (enr == LC_FREE)
                        continue;
-               add += drbd_bm_ALe_set_all(mdev, enr);
+               tmp = drbd_bm_ALe_set_all(mdev, enr);
+               dynamic_dev_dbg(DEV, "AL: set %d bits in extent %u\n", tmp, enr);
+               add += tmp;
        }
 
        lc_unlock(mdev->act_log);
@@ -965,29 +969,30 @@ void __drbd_set_in_sync(struct drbd_conf *mdev, sector_t sector, int size,
         * ok, (capacity & 7) != 0 sometimes, but who cares...
         * we count rs_{total,left} in bits, not sectors.
         */
-       spin_lock_irqsave(&mdev->al_lock, flags);
        count = drbd_bm_clear_bits(mdev, sbnr, ebnr);
-       if (count) {
-               /* we need the lock for drbd_try_clear_on_disk_bm */
-               if (jiffies - mdev->rs_mark_time > HZ*10) {
-                       /* should be rolling marks,
-                        * but we estimate only anyways. */
-                       if (mdev->rs_mark_left != drbd_bm_total_weight(mdev) &&
+       if (count && get_ldev(mdev)) {
+               unsigned long now = jiffies;
+               unsigned long last = mdev->rs_mark_time[mdev->rs_last_mark];
+               int next = (mdev->rs_last_mark + 1) % DRBD_SYNC_MARKS;
+               if (time_after_eq(now, last + DRBD_SYNC_MARK_STEP)) {
+                       unsigned long tw = drbd_bm_total_weight(mdev);
+                       if (mdev->rs_mark_left[mdev->rs_last_mark] != tw &&
                            mdev->state.conn != C_PAUSED_SYNC_T &&
                            mdev->state.conn != C_PAUSED_SYNC_S) {
-                               mdev->rs_mark_time = jiffies;
-                               mdev->rs_mark_left = drbd_bm_total_weight(mdev);
+                               mdev->rs_mark_time[next] = now;
+                               mdev->rs_mark_left[next] = tw;
+                               mdev->rs_last_mark = next;
                        }
                }
-               if (get_ldev(mdev)) {
-                       drbd_try_clear_on_disk_bm(mdev, sector, count, TRUE);
-                       put_ldev(mdev);
-               }
+               spin_lock_irqsave(&mdev->al_lock, flags);
+               drbd_try_clear_on_disk_bm(mdev, sector, count, TRUE);
+               spin_unlock_irqrestore(&mdev->al_lock, flags);
+
                /* just wake_up unconditional now, various lc_chaged(),
                 * lc_put() in drbd_try_clear_on_disk_bm(). */
                wake_up = 1;
+               put_ldev(mdev);
        }
-       spin_unlock_irqrestore(&mdev->al_lock, flags);
        if (wake_up)
                wake_up(&mdev->al_wait);
 }
@@ -1118,7 +1123,7 @@ static int _is_in_al(struct drbd_conf *mdev, unsigned int enr)
  * @mdev:      DRBD device.
  * @sector:    The sector number.
  *
- * This functions sleeps on al_wait. Returns 1 on success, 0 if interrupted.
+ * This functions sleeps on al_wait. Returns 0 on success, -EINTR if interrupted.
  */
 int drbd_rs_begin_io(struct drbd_conf *mdev, sector_t sector)
 {
@@ -1129,10 +1134,10 @@ int drbd_rs_begin_io(struct drbd_conf *mdev, sector_t sector)
        sig = wait_event_interruptible(mdev->al_wait,
                        (bm_ext = _bme_get(mdev, enr)));
        if (sig)
-               return 0;
+               return -EINTR;
 
        if (test_bit(BME_LOCKED, &bm_ext->flags))
-               return 1;
+               return 0;
 
        for (i = 0; i < AL_EXT_PER_BM_SECT; i++) {
                sig = wait_event_interruptible(mdev->al_wait,
@@ -1145,13 +1150,11 @@ int drbd_rs_begin_io(struct drbd_conf *mdev, sector_t sector)
                                wake_up(&mdev->al_wait);
                        }
                        spin_unlock_irq(&mdev->al_lock);
-                       return 0;
+                       return -EINTR;
                }
        }
-
        set_bit(BME_LOCKED, &bm_ext->flags);
-
-       return 1;
+       return 0;
 }
 
 /**