From patchwork Mon Mar 16 15:55:59 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sami Tolvanen X-Patchwork-Id: 6022571 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 9925DBF90F for ; Mon, 16 Mar 2015 16:00:46 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 7B4FA20328 for ; Mon, 16 Mar 2015 16:00:45 +0000 (UTC) Received: from mx4-phx2.redhat.com (mx4-phx2.redhat.com [209.132.183.25]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 5A4022012B for ; Mon, 16 Mar 2015 16:00:44 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by mx4-phx2.redhat.com (8.13.8/8.13.8) with ESMTP id t2GFu7Gl029384; Mon, 16 Mar 2015 11:56:08 -0400 Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id t2GFu61i023601 for ; Mon, 16 Mar 2015 11:56:06 -0400 Received: from mx1.redhat.com (ext-mx15.extmail.prod.ext.phx2.redhat.com [10.5.110.20]) by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id t2GFu6mo012757 for ; Mon, 16 Mar 2015 11:56:06 -0400 Received: from mail-wg0-f44.google.com (mail-wg0-f44.google.com [74.125.82.44]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id t2GFu3BP016548 (version=TLSv1/SSLv3 cipher=AES128-GCM-SHA256 bits=128 verify=FAIL) for ; Mon, 16 Mar 2015 11:56:04 -0400 Received: by wgbcc7 with SMTP id cc7so43673674wgb.0 for ; Mon, 16 Mar 2015 08:56:03 -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:mime-version:content-type :content-disposition:user-agent; bh=l2J0Y59ZjqdSLqLtzSjRIU3/Yqu784uRXf5htiseOmw=; b=VMdmKDyHl0WpwoiIUzeLv/UHCW2uP/prsvJfldM/LQSnOlp/KCzVS8F8pzacYnzR0n I6MNgIr6UrJdcGN6jmrRVu5qqL3kAEHObrTRkae3QxhhXwP960RHyV9xUF+e4w/P0iYH F/OfuTZGYaxr2dLo7nsjh4Lkp3M4NOi9Phl0VxKMk+pMFk7sB+haf+eQ8ttm5vMZv96m D6NlgzdK7uJ3bRDVJYeUG1E40V2GoeIRY01hUnj3E2s8q3mjNkopskKtj5xGFJpqp3d5 lDJ3uXRmGxPjoarjTY4FRb+1yXOQEV+n+TWnGdXRlwVVbN4+M8jGX9lsoLOW9WyqnCNn ysBQ== 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:mime-version :content-type:content-disposition:user-agent; bh=l2J0Y59ZjqdSLqLtzSjRIU3/Yqu784uRXf5htiseOmw=; b=NOs6pKLjR0wLHWxkwRL+1vC+A1RG42xnxlDxR9goAGHZT/onsPI893PaG3CHNMafyx zOThCP7EhnxgslxxluB1NpWp4SLZrOHG7RS1ihOxnj3Ym4lPat7y5fxFWOH0UIEmK1Nf Jm4XEwKkNMkt38mu4QYSkqN5H+PguidXZRKerGMgbSv5HMR9c8oug4aG6qEHV8a53BkS BHkLrLC9U/jOzyGWq6qXuZ6j9RI+GsgG7QXcbOq1rInZulJtRnnu29120ECnUp2km0lT Jesw34pRiMd9l1O7XGNMBNZwQUtj3IZpqR+iUtvbb8HTKE+zi+IXFikYlXg4mr4laPx7 nx7Q== X-Gm-Message-State: ALoCoQkcG6weI6VhZooDyAtMChrMQaSeSHEfYibko/nj2aMXbDz+cMnPWq191m8QB5iXXJfCq4xp X-Received: by 10.180.87.33 with SMTP id u1mr121240488wiz.20.1426521362912; Mon, 16 Mar 2015 08:56:02 -0700 (PDT) Received: from google.com ([2620:0:1042:2:f57f:56f4:e22c:25e7]) by mx.google.com with ESMTPSA id l6sm15959177wjx.33.2015.03.16.08.56.01 (version=TLSv1.2 cipher=RC4-SHA bits=128/128); Mon, 16 Mar 2015 08:56:02 -0700 (PDT) Date: Mon, 16 Mar 2015 15:55:59 +0000 From: Sami Tolvanen To: mpatocka@redhat.com, msb@chromium.org, wad@chromium.org Message-ID: <20150316155559.GA32397@google.com> MIME-Version: 1.0 Content-Disposition: inline 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) 74.125.82.44 mail-wg0-f44.google.com 74.125.82.44 mail-wg0-f44.google.com X-Scanned-By: MIMEDefang 2.68 on 10.5.11.23 X-Scanned-By: MIMEDefang 2.68 on 10.5.110.20 X-loop: dm-devel@redhat.com Cc: dm-devel@redhat.com Subject: [dm-devel] [PATCH] 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=-2.9 required=5.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FSL_HELO_FAKE, RCVD_IN_DNSWL_HI, T_DKIM_INVALID, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=ham 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 --- Documentation/device-mapper/verity.txt | 15 ++++- drivers/md/dm-verity.c | 98 +++++++++++++++++++++++++++++---- 2 files changed, 103 insertions(+), 10 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..470f14c 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,19 @@ Construction Parameters The hexadecimal encoding of the salt value. + + Optional. The mode of operation. + + 0 is the normal mode of operation where a corrupted block will result in an + I/O error. + + 1 is logging mode where corrupted blocks are logged, but the read operation + will still succeed normally. + + 2 is restart mode, where 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..ab72062 100644 --- a/drivers/md/dm-verity.c +++ b/drivers/md/dm-verity.c @@ -18,20 +18,36 @@ #include #include +#include #include #define DM_MSG_PREFIX "verity" +#define DM_VERITY_ENV_LENGTH 42 +#define DM_VERITY_ENV_VAR_NAME "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 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 +}; + +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 +70,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 +193,54 @@ 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); + + 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_LIMIT("%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 +317,13 @@ 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 +435,11 @@ 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; } } @@ -668,8 +737,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 +859,17 @@ 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"; + r = -EINVAL; + goto bad; + } + v->mode = num; + } + v->hash_per_block_bits = __fls((1 << v->hash_dev_block_bits) / v->digest_size);