From patchwork Tue Mar 17 16:37:07 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sami Tolvanen X-Patchwork-Id: 6033141 X-Patchwork-Delegate: snitzer@redhat.com Return-Path: X-Original-To: patchwork-dm-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id DCE84BF90F for ; Tue, 17 Mar 2015 16:41:52 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id D2B2820414 for ; Tue, 17 Mar 2015 16:41:51 +0000 (UTC) Received: from mx6-phx2.redhat.com (mx6-phx2.redhat.com [209.132.183.39]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 8785D2034F for ; Tue, 17 Mar 2015 16:41:47 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by mx6-phx2.redhat.com (8.14.4/8.14.4) with ESMTP id t2HGbDUA030019; Tue, 17 Mar 2015 12:37:14 -0400 Received: from int-mx13.intmail.prod.int.phx2.redhat.com (int-mx13.intmail.prod.int.phx2.redhat.com [10.5.11.26]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id t2HGbCt1021866 for ; Tue, 17 Mar 2015 12:37:12 -0400 Received: from mx1.redhat.com (ext-mx11.extmail.prod.ext.phx2.redhat.com [10.5.110.16]) by int-mx13.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id t2HGbCoI020611 for ; Tue, 17 Mar 2015 12:37:12 -0400 Received: from mail-wi0-f175.google.com (mail-wi0-f175.google.com [209.85.212.175]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id t2HGbAR3015660 (version=TLSv1/SSLv3 cipher=AES128-GCM-SHA256 bits=128 verify=FAIL) for ; Tue, 17 Mar 2015 12:37:11 -0400 Received: by wibg7 with SMTP id g7so67987680wib.1 for ; Tue, 17 Mar 2015 09:37:10 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=date:from:to:cc:subject:message-id:references:mime-version :content-type:content-disposition:in-reply-to:user-agent; bh=N/DBMBh6qK5zlheMQncPvUqRjdiDTPGDeekoyWL11eI=; b=LL/hjrcxcY7LzOntsjZT4dA1WpdtlHSeyUYNCu99VaF6krgFeW4YvhLwxujCWDlS+K 0uSmPdkQi5pBCh6ydM3W84wFKK3XfVPERA809sJTA788vS/HmlEJ2dSnoQtFYU5prXKB jX/Q9ToJU8f6WQxjIJeXZLVNadsxo57U+di/c4uvXm92AOSrqSUwhnWGgIo4llZj4iHs Zd61nXKVUVcYAiYo+w6Ep6ga1s5mUrmQ4wZnd54/zoHN3H+y/jPNzIC3CdBHSNoZ95LQ KqKw6qWdLHR5LUV7ZmNjzhk5iLlcrlQZmxUmemEXuykodSWim8WHaEwISldhdtcroCGD pGvw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:date:from:to:cc:subject:message-id:references :mime-version:content-type:content-disposition:in-reply-to :user-agent; bh=N/DBMBh6qK5zlheMQncPvUqRjdiDTPGDeekoyWL11eI=; b=XLJSHPHdIdE1puOHjkG8bQ+ELvRgMxnwz13i6xkLEdJzRJip/KVxj2ahDbzznmtBnI RIXc10Yq+MLqW0sOSbZAVaGgaxaQxFLy9GWqgdGR4azqk2iD4XBAQW1CJXcfxcmhLVVM 8FW9CDMvMEKeNfRTf30oS+qRCb8QNdmpoIIp6tJYovanq0jqOL+uf0Vid69ocQJCuGz9 DUXcXG2knTTaYzGtdGfWxGS5Wo1Iub+tFpFnWKFB9xeLzKZzihyd91iGJVuFttYQb1Qk K9CiJejtdKIBp7p9LEQAPNRekuPitC/XTrb4gnzCkdqerlNXZ4Xa8F7OtTrnXrfj09SL AdvA== X-Gm-Message-State: ALoCoQkZVDyYX532vBiv71CHI9uSpmmNWHAE9xDnb3QdrtKTmQtQ2fCPCgPMWOlf8KQ33C1KkJ0v X-Received: by 10.194.19.166 with SMTP id g6mr135880603wje.150.1426610230019; Tue, 17 Mar 2015 09:37:10 -0700 (PDT) Received: from google.com ([2620:0:1042:2:a586:95d7:271e:41e5]) by mx.google.com with ESMTPSA id e18sm20636348wjz.27.2015.03.17.09.37.08 (version=TLSv1.2 cipher=RC4-SHA bits=128/128); Tue, 17 Mar 2015 09:37:09 -0700 (PDT) Date: Tue, 17 Mar 2015 16:37:07 +0000 From: Sami Tolvanen To: mpatocka@redhat.com, msb@chromium.org, wad@chromium.org Message-ID: <20150317163707.GA39776@google.com> References: <20150316155559.GA32397@google.com> MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: <20150316155559.GA32397@google.com> User-Agent: Mutt/1.5.21 (2010-09-15) X-RedHat-Spam-Score: 1.088 * (BAYES_00, DCC_REPUT_13_19, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, FSL_HELO_FAKE, RCVD_IN_DNSWL_LOW, SPF_PASS, T_RP_MATCHES_RCVD) 209.85.212.175 mail-wi0-f175.google.com 209.85.212.175 mail-wi0-f175.google.com X-Scanned-By: MIMEDefang 2.68 on 10.5.11.26 X-Scanned-By: MIMEDefang 2.68 on 10.5.110.16 X-loop: dm-devel@redhat.com Cc: dm-devel@redhat.com Subject: [dm-devel] [PATCHv2] dm-verity: Add error handling modes for corrupted blocks X-BeenThere: dm-devel@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk Reply-To: device-mapper development List-Id: device-mapper development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: dm-devel-bounces@redhat.com Errors-To: dm-devel-bounces@redhat.com X-Spam-Status: No, score=-0.2 required=5.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FSL_HELO_FAKE, RCVD_IN_DNSWL_MED, T_DKIM_INVALID, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=no version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Add device specific modes to dm-verity to specify how corrupted blocks should be handled. The following modes are defined: - DM_VERITY_MODE_EIO is the default behavior, where reading a corrupted block results in -EIO. - DM_VERITY_MODE_LOGGING only logs corrupted blocks, but does not block the read. - DM_VERITY_MODE_RESTART calls kernel_restart when a corrupted block is discovered. In addition, each mode sends a uevent to notify userspace of corruption and to allow further recovery actions. The driver defaults to previous behavior (DM_VERITY_MODE_EIO) and other modes can be enabled with an additional parameter to the verity table. Signed-off-by: Sami Tolvanen --- Changes since v1: Use words instead of numeric values as the mode parameter Use DMERR when logging corrupted blocks Add the operating mode to STATUSTYPE_TABLE output Add a DM_ prefix to the uevent variable name --- Documentation/device-mapper/verity.txt | 17 +++ drivers/md/dm-verity.c | 122 ++++++++++++++++++++--- 2 files changed, 127 insertions(+), 12 deletions(-) -- dm-devel mailing list dm-devel@redhat.com https://www.redhat.com/mailman/listinfo/dm-devel diff --git a/Documentation/device-mapper/verity.txt b/Documentation/device-mapper/verity.txt index 9884681..7fe478b 100644 --- a/Documentation/device-mapper/verity.txt +++ b/Documentation/device-mapper/verity.txt @@ -10,7 +10,7 @@ Construction Parameters - + This is the type of the on-disk hash format. @@ -62,6 +62,21 @@ Construction Parameters The hexadecimal encoding of the salt value. + + Optional. The mode of operation. + + eio + - The default mode of operation where a corrupted block will result in an + I/O error. + + logging + - Corrupted blocks are logged, but the read operation will still succeed + normally. + + restart + - A corrupted block will result in the system being immediately restarted. + + Theory of operation =================== diff --git a/drivers/md/dm-verity.c b/drivers/md/dm-verity.c index 7a7bab8..35fc1bc 100644 --- a/drivers/md/dm-verity.c +++ b/drivers/md/dm-verity.c @@ -18,20 +18,40 @@ #include #include +#include #include #define DM_MSG_PREFIX "verity" +#define DM_VERITY_ENV_LENGTH 42 +#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_MODE_NAME_EIO "eio" +#define DM_VERITY_MODE_NAME_LOGGING "logging" +#define DM_VERITY_MODE_NAME_RESTART "restart" 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, + DM_VERITY_MODE_LOGGING, + DM_VERITY_MODE_RESTART +}; + +enum verity_block_type { + DM_VERITY_BLOCK_TYPE_DATA, + DM_VERITY_BLOCK_TYPE_METADATA +}; + struct dm_verity { struct dm_dev *data_dev; struct dm_dev *hash_dev; @@ -54,6 +74,8 @@ struct dm_verity { unsigned digest_size; /* digest size for the current hash algorithm */ unsigned shash_descsize;/* the size of temporary space for crypto */ int hash_failed; /* set to 1 if hash of any block failed */ + 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 */ @@ -175,6 +197,57 @@ static void verity_hash_at_level(struct dm_verity *v, sector_t block, int level, } /* + * Handle verification errors. + */ +static int verity_handle_err(struct dm_verity *v, enum verity_block_type type, + unsigned long long block) +{ + char verity_env[DM_VERITY_ENV_LENGTH]; + char *envp[] = { verity_env, NULL }; + 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; + + switch (type) { + case DM_VERITY_BLOCK_TYPE_DATA: + type_str = "data"; + break; + case DM_VERITY_BLOCK_TYPE_METADATA: + type_str = "metadata"; + break; + default: + BUG(); + } + + 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); + + snprintf(verity_env, DM_VERITY_ENV_LENGTH, "%s=%d,%llu", + DM_VERITY_ENV_VAR_NAME, type, block); + + kobject_uevent_env(&disk_to_dev(dm_disk(md))->kobj, KOBJ_CHANGE, envp); + +out: + if (v->mode == DM_VERITY_MODE_LOGGING) + return 0; + + if (v->mode == DM_VERITY_MODE_RESTART) + kernel_restart("dm-verity device corrupted"); + + return 1; +} + +/* * Verify hash of a metadata block pertaining to the specified data block * ("block" argument) at a specified level ("level" argument). * @@ -251,11 +324,11 @@ 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))) { - DMERR_LIMIT("metadata block %llu is corrupted", - (unsigned long long)hash_block); - v->hash_failed = 1; - r = -EIO; - goto release_ret_r; + if (verity_handle_err(v, DM_VERITY_BLOCK_TYPE_METADATA, + hash_block)) { + r = -EIO; + goto release_ret_r; + } } else aux->hash_verified = 1; } @@ -367,10 +440,9 @@ test_block_hash: return r; } if (unlikely(memcmp(result, io_want_digest(v, io), v->digest_size))) { - DMERR_LIMIT("data block %llu is corrupted", - (unsigned long long)(io->block + b)); - v->hash_failed = 1; - return -EIO; + if (verity_handle_err(v, DM_VERITY_BLOCK_TYPE_DATA, + io->block + b)) + return -EIO; } } @@ -546,6 +618,20 @@ 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]); + DMEMIT(" "); + switch (v->mode) { + case DM_VERITY_MODE_EIO: + DMEMIT(DM_VERITY_MODE_NAME_EIO); + break; + case DM_VERITY_MODE_LOGGING: + DMEMIT(DM_VERITY_MODE_NAME_LOGGING); + break; + case DM_VERITY_MODE_RESTART: + DMEMIT(DM_VERITY_MODE_NAME_RESTART); + break; + default: + BUG(); + } break; } } @@ -668,8 +754,8 @@ static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv) goto bad; } - if (argc != 10) { - ti->error = "Invalid argument count: exactly 10 arguments required"; + if (argc < 10 || argc > 11) { + ti->error = "Invalid argument count: 10-11 arguments required"; r = -EINVAL; goto bad; } @@ -790,6 +876,20 @@ static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv) } } + if (argc > 10) { + if (!strcmp(argv[10], DM_VERITY_MODE_NAME_EIO)) + v->mode = DM_VERITY_MODE_EIO; + else if (!strcmp(argv[10], DM_VERITY_MODE_NAME_LOGGING)) + v->mode = DM_VERITY_MODE_LOGGING; + else if (!strcmp(argv[10], DM_VERITY_MODE_NAME_RESTART)) + v->mode = DM_VERITY_MODE_RESTART; + else { + ti->error = "Invalid mode"; + r = -EINVAL; + goto bad; + } + } + v->hash_per_block_bits = __fls((1 << v->hash_dev_block_bits) / v->digest_size);