drbd: add race-breaker to drbd_go_diskless
authorLars Ellenberg <lars.ellenberg@linbit.com>
Fri, 15 Oct 2010 07:52:46 +0000 (09:52 +0200)
committerPhilipp Reisner <philipp.reisner@linbit.com>
Fri, 15 Oct 2010 12:06:53 +0000 (14:06 +0200)
This adds a necessary race breaker to these commits:
    drbd: fix for possible deadlock on IO error during resync
    drbd: drop wrong debug asserts, fix recently introduced race

What we do is get a refcount, check the state, then depending on the
state and the requested minimum disk state, either hold it (success),
or give it back immediately (failed "try lock").

Some code paths (flushing of drbd metadata) may still grab and hold a
refcount even if we are D_FAILED (application IO won't).
So even if we hit local_cnt == 0 once after being D_FAILED,
we still need to wait for that again after we changed to D_DISKLESS.
Once local_cnt reaches 0 while we are D_DISKLESS, we can be sure that
no one will look at the protected members anymore, so only then is it
safe to free them.

We cannot easily convert to standard locking primitives here, as we want
to be able to use it in atomic context (we always do a "try lock"),
as well as hold references for a "long time" (from IO submission to
completion callback).

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

index bbe3bff2cad68ce0bbc3441a47099cba5462c469..8bfedc7164fa4c9164d4a0bd2ed7348b384fdd81 100644 (file)
@@ -3763,6 +3763,9 @@ static int w_go_diskless(struct drbd_conf *mdev, struct drbd_work *w, int unused
         * the protected members anymore, though, so in the after_state_ch work
         * it will be safe to free them. */
        drbd_force_state(mdev, NS(disk, D_DISKLESS));
+       /* We need to wait for return of references checked out while we still
+        * have been D_FAILED, though (drbd_md_sync, bitmap io). */
+       wait_event(mdev->misc_wait, !atomic_read(&mdev->local_cnt));
 
        clear_bit(GO_DISKLESS, &mdev->flags);
        return 1;
index da7d9bd4f3f0537e94418839c3e50243602c2a00..9b2a0158f399af00af84e4e65805df81f5b935c6 100644 (file)
@@ -53,7 +53,7 @@
 
 
 extern const char *drbd_buildtag(void);
-#define REL_VERSION "8.3.9rc1"
+#define REL_VERSION "8.3.9rc2"
 #define API_VERSION 88
 #define PRO_VERSION_MIN 86
 #define PRO_VERSION_MAX 95