Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit af00c100 authored by Sami Tolvanen's avatar Sami Tolvanen
Browse files

ANDROID: dm verity: port upstream changes to 3.18



Upstream dm-verity has different optional parameters. Port back the
relevant changes.

Bug: 21893453
Change-Id: I0ddadfcc4104b9d38554003203f6e65191ffe995
Signed-off-by: default avatarSami Tolvanen <samitolvanen@google.com>
parent 552b578f
Loading
Loading
Loading
Loading
+68 −40
Original line number Diff line number Diff line
@@ -24,23 +24,24 @@
#define DM_MSG_PREFIX			"verity"

#define DM_VERITY_ENV_LENGTH		42
#define DM_VERITY_ENV_VAR_NAME		"VERITY_ERR_BLOCK_NR"
#define DM_VERITY_ENV_VAR_NAME		"DM_VERITY_ERR_BLOCK_NR"

#define DM_VERITY_IO_VEC_INLINE		16
#define DM_VERITY_MEMPOOL_SIZE		4
#define DM_VERITY_DEFAULT_PREFETCH_SIZE	262144

#define DM_VERITY_MAX_LEVELS		63
#define DM_VERITY_MAX_CORRUPTED_ERRS	100

#define DM_VERITY_OPT_LOGGING		"ignore_corruption"
#define DM_VERITY_OPT_RESTART		"restart_on_corruption"

static unsigned dm_verity_prefetch_cluster = DM_VERITY_DEFAULT_PREFETCH_SIZE;

module_param_named(prefetch_cluster, dm_verity_prefetch_cluster, uint, S_IRUGO | S_IWUSR);

enum verity_mode {
	DM_VERITY_MODE_EIO = 0,
	DM_VERITY_MODE_LOGGING = 1,
	DM_VERITY_MODE_RESTART = 2
	DM_VERITY_MODE_EIO,
	DM_VERITY_MODE_LOGGING,
	DM_VERITY_MODE_RESTART
};

enum verity_block_type {
@@ -73,8 +74,6 @@ struct dm_verity {
	enum verity_mode mode;	/* mode for handling verification errors */
	unsigned corrupted_errs;/* Number of errors for corrupted blocks */

	mempool_t *vec_mempool;	/* mempool of bio vector */

	struct workqueue_struct *verify_wq;

	/* starting blocks for each tree level. 0 is the lowest level. */
@@ -203,10 +202,13 @@ static int verity_handle_err(struct dm_verity *v, enum verity_block_type type,
	const char *type_str = "";
	struct mapped_device *md = dm_table_get_md(v->ti->table);

	/* Corruption should be visible in device status in all modes */
	v->hash_failed = 1;

	if (v->corrupted_errs >= DM_VERITY_MAX_CORRUPTED_ERRS)
		goto out;

	++v->corrupted_errs;
	v->corrupted_errs++;

	switch (type) {
	case DM_VERITY_BLOCK_TYPE_DATA:
@@ -219,8 +221,8 @@ static int verity_handle_err(struct dm_verity *v, enum verity_block_type type,
		BUG();
	}

	DMERR_LIMIT("%s: %s block %llu is corrupted", v->data_dev->name,
                type_str, block);
	DMERR("%s: %s block %llu is corrupted", v->data_dev->name, type_str,
		block);

	if (v->corrupted_errs == DM_VERITY_MAX_CORRUPTED_ERRS)
		DMERR("%s: reached maximum errors", v->data_dev->name);
@@ -265,7 +267,7 @@ static int verity_verify_level(struct dm_verity_io *io, sector_t block,
	verity_hash_at_level(v, block, level, &hash_block, &offset);

	data = dm_bufio_read(v->bufio, hash_block, &buf);
	if (unlikely(IS_ERR(data)))
	if (IS_ERR(data))
		return PTR_ERR(data);

	aux = dm_bufio_get_aux_data(buf);
@@ -317,8 +319,6 @@ static int verity_verify_level(struct dm_verity_io *io, sector_t block,
			goto release_ret_r;
		}
		if (unlikely(memcmp(result, io_want_digest(v, io), v->digest_size))) {
			v->hash_failed = 1;

			if (verity_handle_err(v, DM_VERITY_BLOCK_TYPE_METADATA,
					      hash_block)) {
				r = -EIO;
@@ -435,8 +435,6 @@ test_block_hash:
			return r;
		}
		if (unlikely(memcmp(result, io_want_digest(v, io), v->digest_size))) {
			v->hash_failed = 1;

			if (verity_handle_err(v, DM_VERITY_BLOCK_TYPE_DATA,
					      io->block + b))
				return -EIO;
@@ -615,6 +613,19 @@ static void verity_status(struct dm_target *ti, status_type_t type,
		else
			for (x = 0; x < v->salt_size; x++)
				DMEMIT("%02x", v->salt[x]);
		if (v->mode != DM_VERITY_MODE_EIO) {
			DMEMIT(" 1 ");
			switch (v->mode) {
			case DM_VERITY_MODE_LOGGING:
				DMEMIT(DM_VERITY_OPT_LOGGING);
				break;
			case DM_VERITY_MODE_RESTART:
				DMEMIT(DM_VERITY_OPT_RESTART);
				break;
			default:
				BUG();
			}
		}
		break;
	}
}
@@ -676,9 +687,6 @@ static void verity_dtr(struct dm_target *ti)
	if (v->verify_wq)
		destroy_workqueue(v->verify_wq);

	if (v->vec_mempool)
		mempool_destroy(v->vec_mempool);

	if (v->bufio)
		dm_bufio_client_destroy(v->bufio);

@@ -716,13 +724,19 @@ static void verity_dtr(struct dm_target *ti)
static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
{
	struct dm_verity *v;
	unsigned num;
	struct dm_arg_set as;
	const char *opt_string;
	unsigned int num, opt_params;
	unsigned long long num_ll;
	int r;
	int i;
	sector_t hash_position;
	char dummy;

	static struct dm_arg _args[] = {
		{0, 1, "Invalid number of feature args"},
	};

	v = kzalloc(sizeof(struct dm_verity), GFP_KERNEL);
	if (!v) {
		ti->error = "Cannot allocate verity structure";
@@ -737,14 +751,14 @@ static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
		goto bad;
	}

	if (argc < 10 || argc > 11) {
		ti->error = "Invalid argument count: 10-11 arguments required";
	if (argc < 10) {
		ti->error = "Not enough arguments";
		r = -EINVAL;
		goto bad;
	}

	if (sscanf(argv[0], "%d%c", &num, &dummy) != 1 ||
	    num < 0 || num > 1) {
	if (sscanf(argv[0], "%u%c", &num, &dummy) != 1 ||
	    num > 1) {
		ti->error = "Invalid version";
		r = -EINVAL;
		goto bad;
@@ -859,15 +873,37 @@ static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
		}
	}

	if (argc > 10) {
		if (sscanf(argv[10], "%d%c", &num, &dummy) != 1 ||
			num < DM_VERITY_MODE_EIO ||
			num > DM_VERITY_MODE_RESTART) {
			ti->error = "Invalid mode";
	argv += 10;
	argc -= 10;

	/* Optional parameters */
	if (argc) {
		as.argc = argc;
		as.argv = argv;

		r = dm_read_arg_group(_args, &as, &opt_params, &ti->error);
		if (r)
			goto bad;

		while (opt_params) {
			opt_params--;
			opt_string = dm_shift_arg(&as);
			if (!opt_string) {
				ti->error = "Not enough feature arguments";
				r = -EINVAL;
				goto bad;
			}

			if (!strcasecmp(opt_string, DM_VERITY_OPT_LOGGING))
				v->mode = DM_VERITY_MODE_LOGGING;
			else if (!strcasecmp(opt_string, DM_VERITY_OPT_RESTART))
				v->mode = DM_VERITY_MODE_RESTART;
			else {
				ti->error = "Invalid feature arguments";
				r = -EINVAL;
				goto bad;
			}
		v->mode = num;
		}
	}

	v->hash_per_block_bits =
@@ -919,14 +955,6 @@ static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv)

	ti->per_bio_data_size = roundup(sizeof(struct dm_verity_io) + v->shash_descsize + v->digest_size * 2, __alignof__(struct dm_verity_io));

	v->vec_mempool = mempool_create_kmalloc_pool(DM_VERITY_MEMPOOL_SIZE,
					BIO_MAX_PAGES * sizeof(struct bio_vec));
	if (!v->vec_mempool) {
		ti->error = "Cannot allocate vector mempool";
		r = -ENOMEM;
		goto bad;
	}

	/* WQ_UNBOUND greatly improves performance when running on ramdisk */
	v->verify_wq = alloc_workqueue("kverityd", WQ_CPU_INTENSIVE | WQ_MEM_RECLAIM | WQ_UNBOUND, num_online_cpus());
	if (!v->verify_wq) {