aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/block/drbd/drbd_int.h9
-rw-r--r--drivers/block/drbd/drbd_state.c11
2 files changed, 14 insertions, 6 deletions
diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h
index a16f9ae3c98a..a0ffc19ccf0e 100644
--- a/drivers/block/drbd/drbd_int.h
+++ b/drivers/block/drbd/drbd_int.h
@@ -1946,6 +1946,11 @@ static inline bool is_sync_state(enum drbd_conns connection_state)
1946 1946
1947static inline void put_ldev(struct drbd_device *device) 1947static inline void put_ldev(struct drbd_device *device)
1948{ 1948{
1949 enum drbd_disk_state ds = device->state.disk;
1950 /* We must check the state *before* the atomic_dec becomes visible,
1951 * or we have a theoretical race where someone hitting zero,
1952 * while state still D_FAILED, will then see D_DISKLESS in the
1953 * condition below and calling into destroy, where he must not, yet. */
1949 int i = atomic_dec_return(&device->local_cnt); 1954 int i = atomic_dec_return(&device->local_cnt);
1950 1955
1951 /* This may be called from some endio handler, 1956 /* This may be called from some endio handler,
@@ -1954,10 +1959,10 @@ static inline void put_ldev(struct drbd_device *device)
1954 __release(local); 1959 __release(local);
1955 D_ASSERT(device, i >= 0); 1960 D_ASSERT(device, i >= 0);
1956 if (i == 0) { 1961 if (i == 0) {
1957 if (device->state.disk == D_DISKLESS) 1962 if (ds == D_DISKLESS)
1958 /* even internal references gone, safe to destroy */ 1963 /* even internal references gone, safe to destroy */
1959 drbd_ldev_destroy(device); 1964 drbd_ldev_destroy(device);
1960 if (device->state.disk == D_FAILED) { 1965 if (ds == D_FAILED) {
1961 /* all application IO references gone. */ 1966 /* all application IO references gone. */
1962 if (!test_and_set_bit(GO_DISKLESS, &device->flags)) 1967 if (!test_and_set_bit(GO_DISKLESS, &device->flags))
1963 drbd_queue_work(&first_peer_device(device)->connection->sender_work, 1968 drbd_queue_work(&first_peer_device(device)->connection->sender_work,
diff --git a/drivers/block/drbd/drbd_state.c b/drivers/block/drbd/drbd_state.c
index 1bddd6cf8ac7..6629f4668102 100644
--- a/drivers/block/drbd/drbd_state.c
+++ b/drivers/block/drbd/drbd_state.c
@@ -958,7 +958,6 @@ __drbd_set_state(struct drbd_device *device, union drbd_state ns,
958 enum drbd_state_rv rv = SS_SUCCESS; 958 enum drbd_state_rv rv = SS_SUCCESS;
959 enum sanitize_state_warnings ssw; 959 enum sanitize_state_warnings ssw;
960 struct after_state_chg_work *ascw; 960 struct after_state_chg_work *ascw;
961 bool did_remote, should_do_remote;
962 961
963 os = drbd_read_state(device); 962 os = drbd_read_state(device);
964 963
@@ -1010,18 +1009,22 @@ __drbd_set_state(struct drbd_device *device, union drbd_state ns,
1010 (os.disk != D_DISKLESS && ns.disk == D_DISKLESS)) 1009 (os.disk != D_DISKLESS && ns.disk == D_DISKLESS))
1011 atomic_inc(&device->local_cnt); 1010 atomic_inc(&device->local_cnt);
1012 1011
1013 did_remote = drbd_should_do_remote(device->state);
1014 if (!is_sync_state(os.conn) && is_sync_state(ns.conn)) 1012 if (!is_sync_state(os.conn) && is_sync_state(ns.conn))
1015 clear_bit(RS_DONE, &device->flags); 1013 clear_bit(RS_DONE, &device->flags);
1016 1014
1015 /* changes to local_cnt and device flags should be visible before
1016 * changes to state, which again should be visible before anything else
1017 * depending on that change happens. */
1018 smp_wmb();
1017 device->state.i = ns.i; 1019 device->state.i = ns.i;
1018 should_do_remote = drbd_should_do_remote(device->state);
1019 device->resource->susp = ns.susp; 1020 device->resource->susp = ns.susp;
1020 device->resource->susp_nod = ns.susp_nod; 1021 device->resource->susp_nod = ns.susp_nod;
1021 device->resource->susp_fen = ns.susp_fen; 1022 device->resource->susp_fen = ns.susp_fen;
1023 smp_wmb();
1022 1024
1023 /* put replicated vs not-replicated requests in seperate epochs */ 1025 /* put replicated vs not-replicated requests in seperate epochs */
1024 if (did_remote != should_do_remote) 1026 if (drbd_should_do_remote((union drbd_dev_state)os.i) !=
1027 drbd_should_do_remote((union drbd_dev_state)ns.i))
1025 start_new_tl_epoch(connection); 1028 start_new_tl_epoch(connection);
1026 1029
1027 if (os.disk == D_ATTACHING && ns.disk >= D_NEGOTIATING) 1030 if (os.disk == D_ATTACHING && ns.disk >= D_NEGOTIATING)