summaryrefslogtreecommitdiff
path: root/drivers/md
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/md')
-rw-r--r--drivers/md/Kconfig6
-rw-r--r--drivers/md/dm-android-verity.c55
-rw-r--r--drivers/md/raid10.c22
3 files changed, 60 insertions, 23 deletions
diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig
index 36ca4e4cbfb7..6fd8483cc668 100644
--- a/drivers/md/Kconfig
+++ b/drivers/md/Kconfig
@@ -533,15 +533,15 @@ config DM_LOG_WRITES
If unsure, say N.
config DM_ANDROID_VERITY
- tristate "Android verity target support"
- depends on DM_VERITY
+ bool "Android verity target support"
+ depends on DM_VERITY=y
depends on X509_CERTIFICATE_PARSER
depends on SYSTEM_TRUSTED_KEYRING
depends on PUBLIC_KEY_ALGO_RSA
depends on KEYS
depends on ASYMMETRIC_KEY_TYPE
depends on ASYMMETRIC_PUBLIC_KEY_SUBTYPE
- depends on MD_LINEAR
+ depends on MD_LINEAR=y
select DM_VERITY_HASH_PREFETCH_MIN_SIZE_128
---help---
This device-mapper target is virtually a VERITY target. This
diff --git a/drivers/md/dm-android-verity.c b/drivers/md/dm-android-verity.c
index 13c60bee8af5..7cef735a01a7 100644
--- a/drivers/md/dm-android-verity.c
+++ b/drivers/md/dm-android-verity.c
@@ -115,6 +115,12 @@ static inline bool is_userdebug(void)
return !strncmp(buildvariant, typeuserdebug, sizeof(typeuserdebug));
}
+static inline bool is_unlocked(void)
+{
+ static const char unlocked[] = "orange";
+
+ return !strncmp(verifiedbootstate, unlocked, sizeof(unlocked));
+}
static int table_extract_mpi_array(struct public_key_signature *pks,
const void *data, size_t len)
@@ -585,6 +591,8 @@ static int verify_verity_signature(char *key_id,
if (IS_ERR(pks)) {
DMERR("hashing failed");
+ retval = PTR_ERR(pks);
+ pks = NULL;
goto error;
}
@@ -648,6 +656,28 @@ static int add_as_linear_device(struct dm_target *ti, char *dev)
return err;
}
+static int create_linear_device(struct dm_target *ti, dev_t dev,
+ char *target_device)
+{
+ u64 device_size = 0;
+ int err = find_size(dev, &device_size);
+
+ if (err) {
+ DMERR("error finding bdev size");
+ handle_error();
+ return err;
+ }
+
+ ti->len = device_size;
+ err = add_as_linear_device(ti, target_device);
+ if (err) {
+ handle_error();
+ return err;
+ }
+ verity_enabled = false;
+ return 0;
+}
+
/*
* Target parameters:
* <key id> Key id of the public key in the system keyring.
@@ -671,7 +701,6 @@ static int android_verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
struct fec_ecc_metadata uninitialized_var(ecc);
char buf[FEC_ARG_LENGTH], *buf_ptr;
unsigned long long tmpll;
- u64 uninitialized_var(device_size);
if (argc == 1) {
/* Use the default keyid */
@@ -699,23 +728,8 @@ static int android_verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
return -EINVAL;
}
- if (is_eng()) {
- err = find_size(dev, &device_size);
- if (err) {
- DMERR("error finding bdev size");
- handle_error();
- return err;
- }
-
- ti->len = device_size;
- err = add_as_linear_device(ti, target_device);
- if (err) {
- handle_error();
- return err;
- }
- verity_enabled = false;
- return 0;
- }
+ if (is_eng())
+ return create_linear_device(ti, dev, target_device);
strreplace(key_id, '#', ' ');
@@ -730,6 +744,11 @@ static int android_verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
err = extract_metadata(dev, &fec, &metadata, &verity_enabled);
if (err) {
+ /* Allow invalid metadata when the device is unlocked */
+ if (is_unlocked()) {
+ DMWARN("Allow invalid metadata when unlocked");
+ return create_linear_device(ti, dev, target_device);
+ }
DMERR("Error while extracting metadata");
handle_error();
goto free_metadata;
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index ebb0dd612ebd..a92979e704e3 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -1072,6 +1072,8 @@ static void __make_request(struct mddev *mddev, struct bio *bio)
int max_sectors;
int sectors;
+ md_write_start(mddev, bio);
+
/*
* Register the new request and wait if the reconstruction
* thread has put up a bar for new requests.
@@ -1455,8 +1457,6 @@ static void make_request(struct mddev *mddev, struct bio *bio)
return;
}
- md_write_start(mddev, bio);
-
do {
/*
@@ -1477,7 +1477,25 @@ static void make_request(struct mddev *mddev, struct bio *bio)
split = bio;
}
+ /*
+ * If a bio is splitted, the first part of bio will pass
+ * barrier but the bio is queued in current->bio_list (see
+ * generic_make_request). If there is a raise_barrier() called
+ * here, the second part of bio can't pass barrier. But since
+ * the first part bio isn't dispatched to underlaying disks
+ * yet, the barrier is never released, hence raise_barrier will
+ * alays wait. We have a deadlock.
+ * Note, this only happens in read path. For write path, the
+ * first part of bio is dispatched in a schedule() call
+ * (because of blk plug) or offloaded to raid10d.
+ * Quitting from the function immediately can change the bio
+ * order queued in bio_list and avoid the deadlock.
+ */
__make_request(mddev, split);
+ if (split != bio && bio_data_dir(bio) == READ) {
+ generic_make_request(bio);
+ break;
+ }
} while (split != bio);
/* In case raid10d snuck in to freeze_array */