Received: by 2002:a25:ef43:0:0:0:0:0 with SMTP id w3csp161199ybm; Tue, 26 May 2020 13:21:56 -0700 (PDT) X-Google-Smtp-Source: ABdhPJy5M6th8QIpO1I33u7TQhSvROpi8+Z8yHCfNXLiR8+BoBLMBNvrkTSyZI9cC/1v/nor6arN X-Received: by 2002:a17:906:c112:: with SMTP id do18mr2449191ejc.231.1590524516650; Tue, 26 May 2020 13:21:56 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1590524516; cv=none; d=google.com; s=arc-20160816; b=cs+9+rDLdOLD7h+ogiGRaVSQQQBjDiCqaKX+RzEO7f5BEo5xxFuToh6G/JHonoPgcw VEY5XkKmUvukws5hAUJSLK/hh/fiwUeoysXkVpG1iJitG2WHQ7drYF1pA6YHVRB9xv1P VQo77EPWPq7aSzcOQHDk87M2PwdW2dB7pDKYERyOW+0Tga4/kz0rduNLIZs8mTgDbf2H DlVpzW11mnKx99ai3X8wrG2d7s+sDUVMH6eVrtlCDccREK32NQFHOYkJUwaPgOajQO5B AhQ41rVAzmXY5ZvJIzZGA6ec0M7Gc4Xn5raK5+e/KghGTBDe4nHYkewOh4n0nhU0WsJ8 qJIA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :user-agent:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=3mlbFVU6Hl8iSgJWGut1xDw760ZeYxNKQuSkU9bXb8A=; b=AGcka1/xsBYxLRDpPS4tbfC6kwkjKY4Au7PsPlUU6vrtNx4SDoH/aR8Zr7PF41Orf8 kW3reSQG5I8CqNm2GCwXLuXRRgiDjB6HUWxiOOs1uoDI1iiWQ4SConYiL8imfQnA/I2Q LTNlDbMCYOsffM0zmV+JCkF96tuOFOxL8Bstz6MOrlXxocfuRjPwJLrT4PKSluU39S2t MxF/rSKdL9/Frhj0lJTAP6sxFEIteFkxioseAFt6gU/8X+MkSPBWacoDBu88K4Ky57DX 8q21gQ6Ho/kD6dme72hekr7Wau7T6HeWH/UYPb2cx319dduWCofRKjZfGBfHl4szeT5D vEuA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=chb4HGiT; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id y18si493448ejf.113.2020.05.26.13.21.31; Tue, 26 May 2020 13:21:56 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=chb4HGiT; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2390986AbgEZTBs (ORCPT + 99 others); Tue, 26 May 2020 15:01:48 -0400 Received: from mail.kernel.org ([198.145.29.99]:56316 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2390347AbgEZTBr (ORCPT ); Tue, 26 May 2020 15:01:47 -0400 Received: from localhost (83-86-89-107.cable.dynamic.v4.ziggo.nl [83.86.89.107]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id 08A022086A; Tue, 26 May 2020 19:01:45 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1590519706; bh=KypJwFIz/vzWZNXCRkyD48q9Lx03p7GF7t2fIGPVXEY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=chb4HGiT9ivYtTKixwLWR36J4/YaWwj93kjJ9sP5EOtA2Ozjhf0RjnD/sIpZZiclh hhwHm4d9PuzuMpkupNpIHYYu554B75pN5PzwWe+N0sZhmQlS8TBMCEYxjbgDp9AeMS kawIIYjaljVL8MdnBjDdqfwl+jycP7RqaHMg9qc8= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Dan Williams , Dexuan Cui , Pedro dAquino Filocre F S Barbuda , Vishal Verma , Sasha Levin Subject: [PATCH 4.14 45/59] libnvdimm/btt: Fix LBA masking during free list population Date: Tue, 26 May 2020 20:53:30 +0200 Message-Id: <20200526183921.484936862@linuxfoundation.org> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20200526183907.123822792@linuxfoundation.org> References: <20200526183907.123822792@linuxfoundation.org> User-Agent: quilt/0.66 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Vishal Verma [ Upstream commit 9dedc73a4658ebcc0c9b58c3cb84e9ac80122213 ] The Linux BTT implementation assumes that log entries will never have the 'zero' flag set, and indeed it never sets that flag for log entries itself. However, the UEFI spec is ambiguous on the exact format of the LBA field of a log entry, specifically as to whether it should include the additional flag bits or not. While a zero bit doesn't make sense in the context of a log entry, other BTT implementations might still have it set. If an implementation does happen to have it set, we would happily read it in as the next block to write to for writes. Since a high bit is set, it pushes the block number out of the range of an 'arena', and we fail such a write with an EIO. Follow the robustness principle, and tolerate such implementations by stripping out the zero flag when populating the free list during initialization. Additionally, use the same stripped out entries for detection of incomplete writes and map restoration that happens at this stage. Add a sysfs file 'log_zero_flags' that indicates the ability to accept such a layout to userspace applications. This enables 'ndctl check-namespace' to recognize whether the kernel is able to handle zero flags, or whether it should attempt a fix-up under the --repair option. Cc: Dan Williams Reported-by: Dexuan Cui Reported-by: Pedro d'Aquino Filocre F S Barbuda Tested-by: Dexuan Cui Signed-off-by: Vishal Verma Signed-off-by: Dan Williams Signed-off-by: Sasha Levin --- drivers/nvdimm/btt.c | 25 +++++++++++++++++++------ drivers/nvdimm/btt.h | 2 ++ drivers/nvdimm/btt_devs.c | 8 ++++++++ 3 files changed, 29 insertions(+), 6 deletions(-) diff --git a/drivers/nvdimm/btt.c b/drivers/nvdimm/btt.c index 61e519f1d768..c46b7e1b0132 100644 --- a/drivers/nvdimm/btt.c +++ b/drivers/nvdimm/btt.c @@ -541,8 +541,8 @@ static int arena_clear_freelist_error(struct arena_info *arena, u32 lane) static int btt_freelist_init(struct arena_info *arena) { int new, ret; - u32 i, map_entry; struct log_entry log_new; + u32 i, map_entry, log_oldmap, log_newmap; arena->freelist = kcalloc(arena->nfree, sizeof(struct free_entry), GFP_KERNEL); @@ -554,16 +554,22 @@ static int btt_freelist_init(struct arena_info *arena) if (new < 0) return new; + /* old and new map entries with any flags stripped out */ + log_oldmap = ent_lba(le32_to_cpu(log_new.old_map)); + log_newmap = ent_lba(le32_to_cpu(log_new.new_map)); + /* sub points to the next one to be overwritten */ arena->freelist[i].sub = 1 - new; arena->freelist[i].seq = nd_inc_seq(le32_to_cpu(log_new.seq)); - arena->freelist[i].block = le32_to_cpu(log_new.old_map); + arena->freelist[i].block = log_oldmap; /* * FIXME: if error clearing fails during init, we want to make * the BTT read-only */ - if (ent_e_flag(log_new.old_map)) { + if (ent_e_flag(log_new.old_map) && + !ent_normal(log_new.old_map)) { + arena->freelist[i].has_err = 1; ret = arena_clear_freelist_error(arena, i); if (ret) dev_err_ratelimited(to_dev(arena), @@ -571,7 +577,7 @@ static int btt_freelist_init(struct arena_info *arena) } /* This implies a newly created or untouched flog entry */ - if (log_new.old_map == log_new.new_map) + if (log_oldmap == log_newmap) continue; /* Check if map recovery is needed */ @@ -579,8 +585,15 @@ static int btt_freelist_init(struct arena_info *arena) NULL, NULL, 0); if (ret) return ret; - if ((le32_to_cpu(log_new.new_map) != map_entry) && - (le32_to_cpu(log_new.old_map) == map_entry)) { + + /* + * The map_entry from btt_read_map is stripped of any flag bits, + * so use the stripped out versions from the log as well for + * testing whether recovery is needed. For restoration, use the + * 'raw' version of the log entries as that captured what we + * were going to write originally. + */ + if ((log_newmap != map_entry) && (log_oldmap == map_entry)) { /* * Last transaction wrote the flog, but wasn't able * to complete the map write. So fix up the map. diff --git a/drivers/nvdimm/btt.h b/drivers/nvdimm/btt.h index 2609683c4167..c3e6a5da2ec7 100644 --- a/drivers/nvdimm/btt.h +++ b/drivers/nvdimm/btt.h @@ -44,6 +44,8 @@ #define ent_e_flag(ent) (!!(ent & MAP_ERR_MASK)) #define ent_z_flag(ent) (!!(ent & MAP_TRIM_MASK)) #define set_e_flag(ent) (ent |= MAP_ERR_MASK) +/* 'normal' is both e and z flags set */ +#define ent_normal(ent) (ent_e_flag(ent) && ent_z_flag(ent)) enum btt_init_state { INIT_UNCHECKED = 0, diff --git a/drivers/nvdimm/btt_devs.c b/drivers/nvdimm/btt_devs.c index e610dd890263..76a74e292fd7 100644 --- a/drivers/nvdimm/btt_devs.c +++ b/drivers/nvdimm/btt_devs.c @@ -159,11 +159,19 @@ static ssize_t size_show(struct device *dev, } static DEVICE_ATTR_RO(size); +static ssize_t log_zero_flags_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "Y\n"); +} +static DEVICE_ATTR_RO(log_zero_flags); + static struct attribute *nd_btt_attributes[] = { &dev_attr_sector_size.attr, &dev_attr_namespace.attr, &dev_attr_uuid.attr, &dev_attr_size.attr, + &dev_attr_log_zero_flags.attr, NULL, }; -- 2.25.1