drbd: fix a race between start_resync and send_and_submit
In the drbd make request function, specifically in drbd_send_and_submit(), we decide whether we want to send the actual write request, or only a "set this block out of sync" information. We do so based on the current connection state, while holding the req_lock. The connection state is not supposed to change while holding the req_lock. But in drbd_start_resync, we did change that state anyways, while only holding the global_state_lock, which is enough to change sync-after dependencies (paused vs active resync), but not good enough to change the connection state. Fix: in drbd_start_resync, first grab the req_lock to serialize with drbd_send_and_submit(), before grabbing the global_state_lock to be able to evaluate the sync-after dependencies. Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com> Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com> Signed-off-by: Jens Axboe <axboe@fb.com>
This commit is contained in:
Родитель
20c68fdea1
Коммит
074f4afeb2
|
@ -1686,11 +1686,15 @@ void drbd_start_resync(struct drbd_device *device, enum drbd_conns side)
|
||||||
}
|
}
|
||||||
clear_bit(B_RS_H_DONE, &device->flags);
|
clear_bit(B_RS_H_DONE, &device->flags);
|
||||||
|
|
||||||
write_lock_irq(&global_state_lock);
|
/* req_lock: serialize with drbd_send_and_submit() and others
|
||||||
|
* global_state_lock: for stable sync-after dependencies */
|
||||||
|
spin_lock_irq(&device->resource->req_lock);
|
||||||
|
write_lock(&global_state_lock);
|
||||||
/* Did some connection breakage or IO error race with us? */
|
/* Did some connection breakage or IO error race with us? */
|
||||||
if (device->state.conn < C_CONNECTED
|
if (device->state.conn < C_CONNECTED
|
||||||
|| !get_ldev_if_state(device, D_NEGOTIATING)) {
|
|| !get_ldev_if_state(device, D_NEGOTIATING)) {
|
||||||
write_unlock_irq(&global_state_lock);
|
write_unlock(&global_state_lock);
|
||||||
|
spin_unlock_irq(&device->resource->req_lock);
|
||||||
mutex_unlock(device->state_mutex);
|
mutex_unlock(device->state_mutex);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1730,7 +1734,8 @@ void drbd_start_resync(struct drbd_device *device, enum drbd_conns side)
|
||||||
}
|
}
|
||||||
_drbd_pause_after(device);
|
_drbd_pause_after(device);
|
||||||
}
|
}
|
||||||
write_unlock_irq(&global_state_lock);
|
write_unlock(&global_state_lock);
|
||||||
|
spin_unlock_irq(&device->resource->req_lock);
|
||||||
|
|
||||||
if (r == SS_SUCCESS) {
|
if (r == SS_SUCCESS) {
|
||||||
/* reset rs_last_bcast when a resync or verify is started,
|
/* reset rs_last_bcast when a resync or verify is started,
|
||||||
|
|
Загрузка…
Ссылка в новой задаче