drbd: describe bitmap locking for bulk operation in finer detail
authorLars Ellenberg <lars.ellenberg@linbit.com>
Fri, 21 Jan 2011 09:56:44 +0000 (10:56 +0100)
committerPhilipp Reisner <philipp.reisner@linbit.com>
Thu, 10 Mar 2011 10:48:02 +0000 (11:48 +0100)
Now that we do no longer in-place endian-swap the bitmap, we allow
selected bitmap operations (testing bits, sometimes even settting bits)
during some bulk operations.

This caused us to hit a lot of FIXME asserts similar to
FIXME asender in drbd_bm_count_bits,
bitmap locked for 'write from resync_finished' by worker
Which now is nonsense: looking at the bitmap is perfectly legal
as long as it is not being resized.

This cosmetic patch defines some flags to describe expectations in finer
detail, so the asserts in e.g. bm_change_bits_to() can be skipped if
appropriate.

Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com>
Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com>
drivers/block/drbd/drbd_bitmap.c
drivers/block/drbd/drbd_int.h
drivers/block/drbd/drbd_main.c
drivers/block/drbd/drbd_nl.c
drivers/block/drbd/drbd_receiver.c

index 25428bc..b62dd5f 100644 (file)
@@ -104,26 +104,16 @@ struct drbd_bitmap {
 
        wait_queue_head_t bm_io_wait; /* used to serialize IO of single pages */
 
-       unsigned long  bm_flags;
+       enum bm_flag bm_flags;
 
        /* debugging aid, in case we are still racy somewhere */
        char          *bm_why;
        struct task_struct *bm_task;
 };
 
-/* definition of bits in bm_flags */
-#define BM_LOCKED       0
-// #define BM_MD_IO_ERROR  1 unused now.
-#define BM_P_VMALLOCED  2
-
 static int __bm_change_bits_to(struct drbd_conf *mdev, const unsigned long s,
                               unsigned long e, int val, const enum km_type km);
 
-static int bm_is_locked(struct drbd_bitmap *b)
-{
-       return test_bit(BM_LOCKED, &b->bm_flags);
-}
-
 #define bm_print_lock_info(m) __bm_print_lock_info(m, __func__)
 static void __bm_print_lock_info(struct drbd_conf *mdev, const char *func)
 {
@@ -140,7 +130,7 @@ static void __bm_print_lock_info(struct drbd_conf *mdev, const char *func)
            b->bm_task == mdev->worker.task   ? "worker"   : "?");
 }
 
-void drbd_bm_lock(struct drbd_conf *mdev, char *why)
+void drbd_bm_lock(struct drbd_conf *mdev, char *why, enum bm_flag flags)
 {
        struct drbd_bitmap *b = mdev->bitmap;
        int trylock_failed;
@@ -163,8 +153,9 @@ void drbd_bm_lock(struct drbd_conf *mdev, char *why)
                    b->bm_task == mdev->worker.task   ? "worker"   : "?");
                mutex_lock(&b->bm_change);
        }
-       if (__test_and_set_bit(BM_LOCKED, &b->bm_flags))
+       if (BM_LOCKED_MASK & b->bm_flags)
                dev_err(DEV, "FIXME bitmap already locked in bm_lock\n");
+       b->bm_flags |= flags & BM_LOCKED_MASK;
 
        b->bm_why  = why;
        b->bm_task = current;
@@ -178,9 +169,10 @@ void drbd_bm_unlock(struct drbd_conf *mdev)
                return;
        }
 
-       if (!__test_and_clear_bit(BM_LOCKED, &mdev->bitmap->bm_flags))
+       if (!(BM_LOCKED_MASK & mdev->bitmap->bm_flags))
                dev_err(DEV, "FIXME bitmap not locked in bm_unlock\n");
 
+       b->bm_flags &= ~BM_LOCKED_MASK;
        b->bm_why  = NULL;
        b->bm_task = NULL;
        mutex_unlock(&b->bm_change);
@@ -421,9 +413,9 @@ static struct page **bm_realloc_pages(struct drbd_bitmap *b, unsigned long want)
        }
 
        if (vmalloced)
-               set_bit(BM_P_VMALLOCED, &b->bm_flags);
+               b->bm_flags |= BM_P_VMALLOCED;
        else
-               clear_bit(BM_P_VMALLOCED, &b->bm_flags);
+               b->bm_flags &= ~BM_P_VMALLOCED;
 
        return new_pages;
 }
@@ -460,7 +452,7 @@ void drbd_bm_cleanup(struct drbd_conf *mdev)
 {
        ERR_IF (!mdev->bitmap) return;
        bm_free_pages(mdev->bitmap->bm_pages, mdev->bitmap->bm_number_of_pages);
-       bm_vk_free(mdev->bitmap->bm_pages, test_bit(BM_P_VMALLOCED, &mdev->bitmap->bm_flags));
+       bm_vk_free(mdev->bitmap->bm_pages, (BM_P_VMALLOCED & mdev->bitmap->bm_flags));
        kfree(mdev->bitmap);
        mdev->bitmap = NULL;
 }
@@ -623,7 +615,7 @@ int drbd_bm_resize(struct drbd_conf *mdev, sector_t capacity, int set_new_bits)
 
        ERR_IF(!b) return -ENOMEM;
 
-       drbd_bm_lock(mdev, "resize");
+       drbd_bm_lock(mdev, "resize", BM_LOCKED_MASK);
 
        dev_info(DEV, "drbd_bm_resize called with capacity == %llu\n",
                        (unsigned long long)capacity);
@@ -631,7 +623,7 @@ int drbd_bm_resize(struct drbd_conf *mdev, sector_t capacity, int set_new_bits)
        if (capacity == b->bm_dev_capacity)
                goto out;
 
-       opages_vmalloced = test_bit(BM_P_VMALLOCED, &b->bm_flags);
+       opages_vmalloced = (BM_P_VMALLOCED & b->bm_flags);
 
        if (capacity == 0) {
                spin_lock_irq(&b->bm_lock);
@@ -1030,7 +1022,7 @@ static int bm_rw(struct drbd_conf *mdev, int rw, unsigned lazy_writeout_upper_id
         * as we submit copies of pages anyways.
         */
        if (!ctx.flags)
-               WARN_ON(!bm_is_locked(b));
+               WARN_ON(!(BM_LOCKED_MASK & b->bm_flags));
 
        num_pages = b->bm_number_of_pages;
 
@@ -1220,7 +1212,7 @@ static unsigned long bm_find_next(struct drbd_conf *mdev,
        ERR_IF(!b->bm_pages) return i;
 
        spin_lock_irq(&b->bm_lock);
-       if (bm_is_locked(b))
+       if (BM_DONT_TEST & b->bm_flags)
                bm_print_lock_info(mdev);
 
        i = __bm_find_next(mdev, bm_fo, find_zero_bit, KM_IRQ1);
@@ -1246,13 +1238,13 @@ unsigned long drbd_bm_find_next_zero(struct drbd_conf *mdev, unsigned long bm_fo
  * you must take drbd_bm_lock() first */
 unsigned long _drbd_bm_find_next(struct drbd_conf *mdev, unsigned long bm_fo)
 {
-       /* WARN_ON(!bm_is_locked(mdev)); */
+       /* WARN_ON(!(BM_DONT_SET & mdev->b->bm_flags)); */
        return __bm_find_next(mdev, bm_fo, 0, KM_USER1);
 }
 
 unsigned long _drbd_bm_find_next_zero(struct drbd_conf *mdev, unsigned long bm_fo)
 {
-       /* WARN_ON(!bm_is_locked(mdev)); */
+       /* WARN_ON(!(BM_DONT_SET & mdev->b->bm_flags)); */
        return __bm_find_next(mdev, bm_fo, 1, KM_USER1);
 }
 
@@ -1322,7 +1314,7 @@ static int bm_change_bits_to(struct drbd_conf *mdev, const unsigned long s,
        ERR_IF(!b->bm_pages) return 0;
 
        spin_lock_irqsave(&b->bm_lock, flags);
-       if (bm_is_locked(b))
+       if ((val ? BM_DONT_SET : BM_DONT_CLEAR) & b->bm_flags)
                bm_print_lock_info(mdev);
 
        c = __bm_change_bits_to(mdev, s, e, val, KM_IRQ1);
@@ -1439,7 +1431,7 @@ int drbd_bm_test_bit(struct drbd_conf *mdev, const unsigned long bitnr)
        ERR_IF(!b->bm_pages) return 0;
 
        spin_lock_irqsave(&b->bm_lock, flags);
-       if (bm_is_locked(b))
+       if (BM_DONT_TEST & b->bm_flags)
                bm_print_lock_info(mdev);
        if (bitnr < b->bm_bits) {
                p_addr = bm_map_pidx(b, bm_bit_to_page_idx(b, bitnr));
@@ -1474,7 +1466,7 @@ int drbd_bm_count_bits(struct drbd_conf *mdev, const unsigned long s, const unsi
        ERR_IF(!b->bm_pages) return 1;
 
        spin_lock_irqsave(&b->bm_lock, flags);
-       if (bm_is_locked(b))
+       if (BM_DONT_TEST & b->bm_flags)
                bm_print_lock_info(mdev);
        for (bitnr = s; bitnr <= e; bitnr++) {
                unsigned int idx = bm_bit_to_page_idx(b, bitnr);
@@ -1522,7 +1514,7 @@ int drbd_bm_e_weight(struct drbd_conf *mdev, unsigned long enr)
        ERR_IF(!b->bm_pages) return 0;
 
        spin_lock_irqsave(&b->bm_lock, flags);
-       if (bm_is_locked(b))
+       if (BM_DONT_TEST & b->bm_flags)
                bm_print_lock_info(mdev);
 
        s = S2W(enr);
@@ -1555,7 +1547,7 @@ unsigned long drbd_bm_ALe_set_all(struct drbd_conf *mdev, unsigned long al_enr)
        ERR_IF(!b->bm_pages) return 0;
 
        spin_lock_irq(&b->bm_lock);
-       if (bm_is_locked(b))
+       if (BM_DONT_SET & b->bm_flags)
                bm_print_lock_info(mdev);
        weight = b->bm_set;
 
index 0a9059e..267d989 100644 (file)
@@ -855,6 +855,32 @@ enum {
 
 struct drbd_bitmap; /* opaque for drbd_conf */
 
+/* definition of bits in bm_flags to be used in drbd_bm_lock
+ * and drbd_bitmap_io and friends. */
+enum bm_flag {
+       /* do we need to kfree, or vfree bm_pages? */
+       BM_P_VMALLOCED = 0x10000, /* internal use only, will be masked out */
+
+       /* currently locked for bulk operation */
+       BM_LOCKED_MASK = 0x7,
+
+       /* in detail, that is: */
+       BM_DONT_CLEAR = 0x1,
+       BM_DONT_SET   = 0x2,
+       BM_DONT_TEST  = 0x4,
+
+       /* (test bit, count bit) allowed (common case) */
+       BM_LOCKED_TEST_ALLOWED = 0x3,
+
+       /* testing bits, as well as setting new bits allowed, but clearing bits
+        * would be unexpected.  Used during bitmap receive.  Setting new bits
+        * requires sending of "out-of-sync" information, though. */
+       BM_LOCKED_SET_ALLOWED = 0x1,
+
+       /* clear is not expected while bitmap is locked for bulk operation */
+};
+
+
 /* TODO sort members for performance
  * MAYBE group them further */
 
@@ -920,6 +946,7 @@ struct drbd_md_io {
 struct bm_io_work {
        struct drbd_work w;
        char *why;
+       enum bm_flag flags;
        int (*io_fn)(struct drbd_conf *mdev);
        void (*done)(struct drbd_conf *mdev, int rv);
 };
@@ -1242,7 +1269,6 @@ extern void drbd_free_bc(struct drbd_backing_dev *ldev);
 extern void drbd_mdev_cleanup(struct drbd_conf *mdev);
 void drbd_print_uuids(struct drbd_conf *mdev, const char *text);
 
-/* drbd_meta-data.c (still in drbd_main.c) */
 extern void drbd_md_sync(struct drbd_conf *mdev);
 extern int  drbd_md_read(struct drbd_conf *mdev, struct drbd_backing_dev *bdev);
 extern void drbd_uuid_set(struct drbd_conf *mdev, int idx, u64 val) __must_hold(local);
@@ -1263,10 +1289,12 @@ extern void drbd_md_mark_dirty_(struct drbd_conf *mdev,
 extern void drbd_queue_bitmap_io(struct drbd_conf *mdev,
                                 int (*io_fn)(struct drbd_conf *),
                                 void (*done)(struct drbd_conf *, int),
-                                char *why);
+                                char *why, enum bm_flag flags);
+extern int drbd_bitmap_io(struct drbd_conf *mdev,
+               int (*io_fn)(struct drbd_conf *),
+               char *why, enum bm_flag flags);
 extern int drbd_bmio_set_n_write(struct drbd_conf *mdev);
 extern int drbd_bmio_clear_n_write(struct drbd_conf *mdev);
-extern int drbd_bitmap_io(struct drbd_conf *mdev, int (*io_fn)(struct drbd_conf *), char *why);
 extern void drbd_go_diskless(struct drbd_conf *mdev);
 extern void drbd_ldev_destroy(struct drbd_conf *mdev);
 
@@ -1452,7 +1480,7 @@ extern void drbd_bm_merge_lel(struct drbd_conf *mdev, size_t offset,
 extern void drbd_bm_get_lel(struct drbd_conf *mdev, size_t offset,
                size_t number, unsigned long *buffer);
 
-extern void drbd_bm_lock(struct drbd_conf *mdev, char *why);
+extern void drbd_bm_lock(struct drbd_conf *mdev, char *why, enum bm_flag flags);
 extern void drbd_bm_unlock(struct drbd_conf *mdev);
 /* drbd_main.c */
 
index b68332a..a9e9b49 100644 (file)
@@ -1320,7 +1320,9 @@ static void abw_start_sync(struct drbd_conf *mdev, int rv)
        }
 }
 
-int drbd_bitmap_io_from_worker(struct drbd_conf *mdev, int (*io_fn)(struct drbd_conf *), char *why)
+int drbd_bitmap_io_from_worker(struct drbd_conf *mdev,
+               int (*io_fn)(struct drbd_conf *),
+               char *why, enum bm_flag flags)
 {
        int rv;
 
@@ -1328,10 +1330,8 @@ int drbd_bitmap_io_from_worker(struct drbd_conf *mdev, int (*io_fn)(struct drbd_
 
        /* open coded non-blocking drbd_suspend_io(mdev); */
        set_bit(SUSPEND_IO, &mdev->flags);
-       if (!is_susp(mdev->state))
-               D_ASSERT(atomic_read(&mdev->ap_bio_cnt) == 0);
 
-       drbd_bm_lock(mdev, why);
+       drbd_bm_lock(mdev, why, flags);
        rv = io_fn(mdev);
        drbd_bm_unlock(mdev);
 
@@ -1438,7 +1438,8 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os,
        if (os.conn != C_WF_BITMAP_S && ns.conn == C_WF_BITMAP_S &&
            mdev->state.conn == C_WF_BITMAP_S)
                drbd_queue_bitmap_io(mdev, &drbd_send_bitmap, NULL,
-                               "send_bitmap (WFBitMapS)");
+                               "send_bitmap (WFBitMapS)",
+                               BM_LOCKED_TEST_ALLOWED);
 
        /* Lost contact to peer's copy of the data */
        if ((os.pdsk >= D_INCONSISTENT &&
@@ -1469,7 +1470,11 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os,
 
                /* D_DISKLESS Peer becomes secondary */
                if (os.peer == R_PRIMARY && ns.peer == R_SECONDARY)
-                       drbd_bitmap_io_from_worker(mdev, &drbd_bm_write, "demote diskless peer");
+                       /* We may still be Primary ourselves.
+                        * No harm done if the bitmap still changes,
+                        * redirtied pages will follow later. */
+                       drbd_bitmap_io_from_worker(mdev, &drbd_bm_write,
+                               "demote diskless peer", BM_LOCKED_SET_ALLOWED);
                put_ldev(mdev);
        }
 
@@ -1478,7 +1483,10 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os,
         * if there is a resync going on still */
        if (os.role == R_PRIMARY && ns.role == R_SECONDARY &&
                mdev->state.conn <= C_CONNECTED && get_ldev(mdev)) {
-               drbd_bitmap_io_from_worker(mdev, &drbd_bm_write, "demote");
+               /* No changes to the bitmap expected this time, so assert that,
+                * even though no harm was done if it did change. */
+               drbd_bitmap_io_from_worker(mdev, &drbd_bm_write,
+                               "demote", BM_LOCKED_TEST_ALLOWED);
                put_ldev(mdev);
        }
 
@@ -1512,12 +1520,17 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os,
        /* We are in the progress to start a full sync... */
        if ((os.conn != C_STARTING_SYNC_T && ns.conn == C_STARTING_SYNC_T) ||
            (os.conn != C_STARTING_SYNC_S && ns.conn == C_STARTING_SYNC_S))
-               drbd_queue_bitmap_io(mdev, &drbd_bmio_set_n_write, &abw_start_sync, "set_n_write from StartingSync");
+               /* no other bitmap changes expected during this phase */
+               drbd_queue_bitmap_io(mdev,
+                       &drbd_bmio_set_n_write, &abw_start_sync,
+                       "set_n_write from StartingSync", BM_LOCKED_TEST_ALLOWED);
 
        /* We are invalidating our self... */
        if (os.conn < C_CONNECTED && ns.conn < C_CONNECTED &&
            os.disk > D_INCONSISTENT && ns.disk == D_INCONSISTENT)
-               drbd_queue_bitmap_io(mdev, &drbd_bmio_set_n_write, NULL, "set_n_write from invalidate");
+               /* other bitmap operation expected during this phase */
+               drbd_queue_bitmap_io(mdev, &drbd_bmio_set_n_write, NULL,
+                       "set_n_write from invalidate", BM_LOCKED_MASK);
 
        /* first half of local IO error, failure to attach,
         * or administrative detach */
@@ -1599,14 +1612,14 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os,
 
        /* This triggers bitmap writeout of potentially still unwritten pages
         * if the resync finished cleanly, or aborted because of peer disk
-        * failure.  Resync aborted because of connection failure does bitmap
-        * writeout from drbd_disconnect.
+        * failure, or because of connection loss.
         * For resync aborted because of local disk failure, we cannot do
         * any bitmap writeout anymore.
+        * No harm done if some bits change during this phase.
         */
-       if (os.conn > C_CONNECTED && ns.conn == C_CONNECTED &&
-           mdev->state.conn == C_CONNECTED && get_ldev(mdev)) {
-               drbd_queue_bitmap_io(mdev, &drbd_bm_write, NULL, "write from resync_finished");
+       if (os.conn > C_CONNECTED && ns.conn <= C_CONNECTED && get_ldev(mdev)) {
+               drbd_queue_bitmap_io(mdev, &drbd_bm_write, NULL,
+                       "write from resync_finished", BM_LOCKED_SET_ALLOWED);
                put_ldev(mdev);
        }
 
@@ -3929,7 +3942,7 @@ static int w_bitmap_io(struct drbd_conf *mdev, struct drbd_work *w, int unused)
        D_ASSERT(atomic_read(&mdev->ap_bio_cnt) == 0);
 
        if (get_ldev(mdev)) {
-               drbd_bm_lock(mdev, work->why);
+               drbd_bm_lock(mdev, work->why, work->flags);
                rv = work->io_fn(mdev);
                drbd_bm_unlock(mdev);
                put_ldev(mdev);
@@ -3944,6 +3957,7 @@ static int w_bitmap_io(struct drbd_conf *mdev, struct drbd_work *w, int unused)
 
        clear_bit(BITMAP_IO_QUEUED, &mdev->flags);
        work->why = NULL;
+       work->flags = 0;
 
        return 1;
 }
@@ -3998,7 +4012,7 @@ void drbd_go_diskless(struct drbd_conf *mdev)
 void drbd_queue_bitmap_io(struct drbd_conf *mdev,
                          int (*io_fn)(struct drbd_conf *),
                          void (*done)(struct drbd_conf *, int),
-                         char *why)
+                         char *why, enum bm_flag flags)
 {
        D_ASSERT(current == mdev->worker.task);
 
@@ -4012,6 +4026,7 @@ void drbd_queue_bitmap_io(struct drbd_conf *mdev,
        mdev->bm_io_work.io_fn = io_fn;
        mdev->bm_io_work.done = done;
        mdev->bm_io_work.why = why;
+       mdev->bm_io_work.flags = flags;
 
        spin_lock_irq(&mdev->req_lock);
        set_bit(BITMAP_IO, &mdev->flags);
@@ -4031,19 +4046,22 @@ void drbd_queue_bitmap_io(struct drbd_conf *mdev,
  * freezes application IO while that the actual IO operations runs. This
  * functions MAY NOT be called from worker context.
  */
-int drbd_bitmap_io(struct drbd_conf *mdev, int (*io_fn)(struct drbd_conf *), char *why)
+int drbd_bitmap_io(struct drbd_conf *mdev, int (*io_fn)(struct drbd_conf *),
+               char *why, enum bm_flag flags)
 {
        int rv;
 
        D_ASSERT(current != mdev->worker.task);
 
-       drbd_suspend_io(mdev);
+       if ((flags & BM_LOCKED_SET_ALLOWED) == 0)
+               drbd_suspend_io(mdev);
 
-       drbd_bm_lock(mdev, why);
+       drbd_bm_lock(mdev, why, flags);
        rv = io_fn(mdev);
        drbd_bm_unlock(mdev);
 
-       drbd_resume_io(mdev);
+       if ((flags & BM_LOCKED_SET_ALLOWED) == 0)
+               drbd_resume_io(mdev);
 
        return rv;
 }
index ce6f2fe..bc0bcb9 100644 (file)
@@ -648,7 +648,9 @@ enum determine_dev_size drbd_determin_dev_size(struct drbd_conf *mdev, enum dds_
                dev_info(DEV, "Writing the whole bitmap, %s\n",
                         la_size_changed && md_moved ? "size changed and md moved" :
                         la_size_changed ? "size changed" : "md moved");
-               err = drbd_bitmap_io(mdev, &drbd_bm_write, "size changed"); /* does drbd_resume_io() ! */
+               /* next line implicitly does drbd_suspend_io()+drbd_resume_io() */
+               err = drbd_bitmap_io(mdev, &drbd_bm_write,
+                               "size changed", BM_LOCKED_MASK);
                if (err) {
                        rv = dev_size_error;
                        goto out;
@@ -1160,12 +1162,14 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp
        if (drbd_md_test_flag(mdev->ldev, MDF_FULL_SYNC)) {
                dev_info(DEV, "Assuming that all blocks are out of sync "
                     "(aka FullSync)\n");
-               if (drbd_bitmap_io(mdev, &drbd_bmio_set_n_write, "set_n_write from attaching")) {
+               if (drbd_bitmap_io(mdev, &drbd_bmio_set_n_write,
+                       "set_n_write from attaching", BM_LOCKED_MASK)) {
                        retcode = ERR_IO_MD_DISK;
                        goto force_diskless_dec;
                }
        } else {
-               if (drbd_bitmap_io(mdev, &drbd_bm_read, "read from attaching") < 0) {
+               if (drbd_bitmap_io(mdev, &drbd_bm_read,
+                       "read from attaching", BM_LOCKED_MASK) < 0) {
                        retcode = ERR_IO_MD_DISK;
                        goto force_diskless_dec;
                }
@@ -1173,7 +1177,8 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp
 
        if (cp_discovered) {
                drbd_al_apply_to_bm(mdev);
-               if (drbd_bitmap_io(mdev, &drbd_bm_write, "crashed primary apply AL")) {
+               if (drbd_bitmap_io(mdev, &drbd_bm_write,
+                       "crashed primary apply AL", BM_LOCKED_MASK)) {
                        retcode = ERR_IO_MD_DISK;
                        goto force_diskless_dec;
                }
@@ -1925,7 +1930,8 @@ static int drbd_nl_invalidate_peer(struct drbd_conf *mdev, struct drbd_nl_cfg_re
                        retcode = drbd_request_state(mdev, NS(pdsk, D_INCONSISTENT));
                        if (retcode >= SS_SUCCESS) {
                                if (drbd_bitmap_io(mdev, &drbd_bmio_set_susp_al,
-                                                  "set_n_write from invalidate_peer"))
+                                       "set_n_write from invalidate_peer",
+                                       BM_LOCKED_SET_ALLOWED))
                                        retcode = ERR_IO_MD_DISK;
                        }
                } else
@@ -2143,7 +2149,8 @@ static int drbd_nl_new_c_uuid(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nl
        drbd_uuid_new_current(mdev); /* New current, previous to UI_BITMAP */
 
        if (args.clear_bm) {
-               err = drbd_bitmap_io(mdev, &drbd_bmio_clear_n_write, "clear_n_write from new_c_uuid");
+               err = drbd_bitmap_io(mdev, &drbd_bmio_clear_n_write,
+                       "clear_n_write from new_c_uuid", BM_LOCKED_MASK);
                if (err) {
                        dev_err(DEV, "Writing bitmap failed with %d\n",err);
                        retcode = ERR_IO_MD_DISK;
index e5686a8..e13134f 100644 (file)
@@ -2599,7 +2599,8 @@ static enum drbd_conns drbd_sync_handshake(struct drbd_conf *mdev, enum drbd_rol
 
        if (abs(hg) >= 2) {
                dev_info(DEV, "Writing the whole bitmap, full sync required after drbd_sync_handshake.\n");
-               if (drbd_bitmap_io(mdev, &drbd_bmio_set_n_write, "set_n_write from sync_handshake"))
+               if (drbd_bitmap_io(mdev, &drbd_bmio_set_n_write, "set_n_write from sync_handshake",
+                                       BM_LOCKED_SET_ALLOWED))
                        return C_MASK;
        }
 
@@ -3053,7 +3054,8 @@ static int receive_uuids(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned
                if (skip_initial_sync) {
                        dev_info(DEV, "Accepted new current UUID, preparing to skip initial sync\n");
                        drbd_bitmap_io(mdev, &drbd_bmio_clear_n_write,
-                                       "clear_n_write from receive_uuids");
+                                       "clear_n_write from receive_uuids",
+                                       BM_LOCKED_TEST_ALLOWED);
                        _drbd_uuid_set(mdev, UI_CURRENT, p_uuid[UI_CURRENT]);
                        _drbd_uuid_set(mdev, UI_BITMAP, 0);
                        _drbd_set_state(_NS2(mdev, disk, D_UP_TO_DATE, pdsk, D_UP_TO_DATE),
@@ -3494,7 +3496,9 @@ static int receive_bitmap(struct drbd_conf *mdev, enum drbd_packets cmd, unsigne
        int ok = false;
        struct p_header80 *h = &mdev->data.rbuf.header.h80;
 
-       /* drbd_bm_lock(mdev, "receive bitmap"); By intention no bm_lock */
+       drbd_bm_lock(mdev, "receive bitmap", BM_LOCKED_SET_ALLOWED);
+       /* you are supposed to send additional out-of-sync information
+        * if you actually set bits during this phase */
 
        /* maybe we should use some per thread scratch page,
         * and allocate that during initial device creation? */
@@ -3568,7 +3572,7 @@ static int receive_bitmap(struct drbd_conf *mdev, enum drbd_packets cmd, unsigne
 
        ok = true;
  out:
-       /* drbd_bm_unlock(mdev); by intention no lock */
+       drbd_bm_unlock(mdev);
        if (ok && mdev->state.conn == C_WF_BITMAP_S)
                drbd_start_resync(mdev, C_SYNC_SOURCE);
        free_page((unsigned long) buffer);
@@ -3817,7 +3821,6 @@ static void drbd_disconnect(struct drbd_conf *mdev)
 
        fp = FP_DONT_CARE;
        if (get_ldev(mdev)) {
-               drbd_bitmap_io(mdev, &drbd_bm_write, "write from disconnect");
                fp = mdev->ldev->dc.fencing;
                put_ldev(mdev);
        }
@@ -3846,6 +3849,10 @@ static void drbd_disconnect(struct drbd_conf *mdev)
                drbd_request_state(mdev, NS(conn, C_STANDALONE));
        }
 
+       /* serialize with bitmap writeout triggered by the state change,
+        * if any. */
+       wait_event(mdev->misc_wait, !test_bit(BITMAP_IO, &mdev->flags));
+
        /* tcp_close and release of sendpage pages can be deferred.  I don't
         * want to use SO_LINGER, because apparently it can be deferred for
         * more than 20 seconds (longest time I checked).