struct list_head recovered_regions;
struct list_head failed_recovered_regions;
+ /*
+ * If there was a barrier failure no regions can be marked clean.
+ */
+ int barrier_failure;
+
void *context;
sector_t target_begin;
INIT_LIST_HEAD(&rh->quiesced_regions);
INIT_LIST_HEAD(&rh->recovered_regions);
INIT_LIST_HEAD(&rh->failed_recovered_regions);
+ rh->barrier_failure = 0;
rh->region_pool = mempool_create_kmalloc_pool(MIN_REGIONS,
sizeof(struct dm_region));
/* dm_rh_mark_nosync
* @ms
* @bio
- * @done
- * @error
*
* The bio was written on some mirror(s) but failed on other mirror(s).
* We can successfully endio the bio but should avoid the region being
*
* This function is _not_ safe in interrupt context!
*/
-void dm_rh_mark_nosync(struct dm_region_hash *rh,
- struct bio *bio, unsigned done, int error)
+void dm_rh_mark_nosync(struct dm_region_hash *rh, struct bio *bio)
{
unsigned long flags;
struct dm_dirty_log *log = rh->log;
region_t region = dm_rh_bio_to_region(rh, bio);
int recovering = 0;
+ if (bio_empty_barrier(bio)) {
+ rh->barrier_failure = 1;
+ return;
+ }
+
/* We must inform the log that the sync count has changed. */
log->type->set_region_sync(log, region, 0);
BUG_ON(!list_empty(®->list));
spin_unlock_irqrestore(&rh->region_lock, flags);
- bio_endio(bio, error);
if (recovering)
complete_resync_work(reg, 0);
}
{
struct bio *bio;
- for (bio = bios->head; bio; bio = bio->bi_next)
+ for (bio = bios->head; bio; bio = bio->bi_next) {
+ if (bio_empty_barrier(bio))
+ continue;
rh_inc(rh, dm_rh_bio_to_region(rh, bio));
+ }
}
EXPORT_SYMBOL_GPL(dm_rh_inc_pending);
*/
/* do nothing for DM_RH_NOSYNC */
- if (reg->state == DM_RH_RECOVERING) {
+ if (unlikely(rh->barrier_failure)) {
+ /*
+ * If a write barrier failed some time ago, we
+ * don't know whether or not this write made it
+ * to the disk, so we must resync the device.
+ */
+ reg->state = DM_RH_NOSYNC;
+ } else if (reg->state == DM_RH_RECOVERING) {
list_add_tail(®->list, &rh->quiesced_regions);
} else if (reg->state == DM_RH_DIRTY) {
reg->state = DM_RH_CLEAN;