diff --git a/drivers/md/dm-verity-target.c b/drivers/md/dm-verity-target.c
index 711f101..d143fdc 100644
--- a/drivers/md/dm-verity-target.c
+++ b/drivers/md/dm-verity-target.c
@@ -278,6 +278,7 @@ static int verity_verify_level(struct dm_verity *v, struct dm_verity_io *io,
 	int r;
 	sector_t hash_block;
 	unsigned offset;
+	unsigned c;
 
 	verity_hash_at_level(v, block, level, &hash_block, &offset);
 
@@ -293,11 +294,23 @@ static int verity_verify_level(struct dm_verity *v, struct dm_verity_io *io,
 			goto release_ret_r;
 		}
 
-		r = verity_hash(v, verity_io_hash_req(v, io),
-				data, 1 << v->hash_dev_block_bits,
-				verity_io_real_digest(v, io));
-		if (unlikely(r < 0))
-			goto release_ret_r;
+		for (c = 0; c < DM_VERITY_MAX_CORRUPTED_ERRS; c++) {
+			r = verity_hash(v, verity_io_hash_req(v, io),
+					data, 1 << v->hash_dev_block_bits,
+					verity_io_real_digest(v, io));
+
+			if (unlikely(r < 0))
+				goto release_ret_r;
+
+			if (likely(memcmp(verity_io_real_digest(v, io),
+					  want_digest,
+					  v->digest_size) == 0))
+				break;
+		}
+
+		if (c == DM_VERITY_MAX_CORRUPTED_ERRS)
+			DMINFO("redo meta hash failure over %d times",
+			       DM_VERITY_MAX_CORRUPTED_ERRS);
 
 		if (likely(memcmp(verity_io_real_digest(v, io), want_digest,
 				  v->digest_size) == 0))
@@ -399,6 +412,7 @@ static int verity_for_io_block(struct dm_verity *v, struct dm_verity_io *io,
 
 		bio_advance_iter(bio, iter, len);
 		todo -= len;
+
 	} while (todo);
 
 	return 0;
@@ -469,7 +483,9 @@ static int verity_verify_io(struct dm_verity_io *io)
 	bool is_zero;
 	struct dm_verity *v = io->v;
 	struct bvec_iter start;
+	struct bvec_iter keep;
 	unsigned b;
+	unsigned c;
 	struct crypto_wait wait;
 
 	for (b = 0; b < io->n_blocks; b++) {
@@ -502,19 +518,39 @@ static int verity_verify_io(struct dm_verity_io *io)
 			continue;
 		}
 
-		r = verity_hash_init(v, req, &wait);
-		if (unlikely(r < 0))
-			return r;
-
 		start = io->iter;
-		r = verity_for_io_block(v, io, &io->iter, &wait);
-		if (unlikely(r < 0))
-			return r;
 
-		r = verity_hash_final(v, req, verity_io_real_digest(v, io),
-					&wait);
-		if (unlikely(r < 0))
-			return r;
+		for (c = 0; c < DM_VERITY_MAX_CORRUPTED_ERRS; c++) {
+			keep = start;
+
+			r = verity_hash_init(v, req, &wait);
+			if (unlikely(r < 0))
+				return r;
+
+			if (c == 0)
+				r = verity_for_io_block(v, io, &io->iter,
+							&wait);
+			else
+				r = verity_for_io_block(v, io, &keep,
+							&wait);
+			if (unlikely(r < 0))
+				return r;
+
+			r = verity_hash_final(v, req,
+					      verity_io_real_digest(v, io),
+					      &wait);
+			if (unlikely(r < 0))
+				return r;
+
+			if (likely(memcmp(verity_io_real_digest(v, io),
+					  verity_io_want_digest(v, io),
+					  v->digest_size) == 0))
+				break;
+		}
+
+		if (c == DM_VERITY_MAX_CORRUPTED_ERRS)
+			DMINFO("redo data hash failure over %d times",
+			       DM_VERITY_MAX_CORRUPTED_ERRS);
 
 		if (likely(memcmp(verity_io_real_digest(v, io),
 				  verity_io_want_digest(v, io), v->digest_size) == 0)) {
