Received: by 2002:a25:6193:0:0:0:0:0 with SMTP id v141csp399455ybb; Wed, 25 Mar 2020 01:57:10 -0700 (PDT) X-Google-Smtp-Source: ADFU+vvzXq1xjMNyzS7bci646cbraWLRwBEtT24ckGJBJim1hsRSXbOnFFt8Ad2rxSF0A9jjIX1m X-Received: by 2002:a9d:7cd1:: with SMTP id r17mr1758709otn.183.1585126630472; Wed, 25 Mar 2020 01:57:10 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1585126630; cv=none; d=google.com; s=arc-20160816; b=swC5gS4A4sMNiPjhmyGx7UttpnUvoFwV6i086fZPB3rw80IMeWqfcOxYqTLWZ1l8Xk o4WkvwXW8PZDVpXKklWCtcWJjFM4PDn4WUa3F2FNUWBDA9oxkcAb9U2KSVdsevdd2Snz kF+k1TTQKwwqhtct2xXbcGbuvTXg3N81DJ2miZe9o+0GEcH6pd/UCQI3O2unSTQ7ETus a7TMhKFq7VAT7LBi0o6t4tjC1XDjfM8PK8bmgvEN/UNFlSFLHbn0KqKruUdtwQfPGz+O +znKSRGZ4vD5low+QJNH8ftTeGN+x8Cardmip7zaE0p4sh96k/sZnaBB70kUcKvz4wCS PLqA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from; bh=cbG0+x4ea2FMdQN3sPnDPAgcSkoOda6/0Vegxfp8Wg4=; b=h06C2/rVHl1PocDC8O9ZAnlRhbSdDXRW2luDqG8LCIOZiuF4Z9H5lT9mRbEnv7Bal0 bj8dsyLwmwz/xJvXKpH0/StQvo5Yp7yHrprZJGR27CzBVEbMHEZs3CIAWkOuqIalIGIK 8/390SefZV4ou3OfbUmC5ikxBWyOFQG+CIqDFkjkon0sLHb/X+9Ug5HvdTDN23VO/OKK mPICK2pWtaSzsymq0bTTTdwwgsdhs8akvuDidCHb2qNeeXi0ZxrEhpmOAaDq1qw7JpSp KNM6BsKiylYJHnqzYTUY+VXJ+sTLhOdL8nOjUGMvIdSTmvDU++Is7b7G/GeXkhYsSyYn NN3g== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id w65si1353779ooa.42.2020.03.25.01.56.58; Wed, 25 Mar 2020 01:57:10 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727513AbgCYIzm (ORCPT + 99 others); Wed, 25 Mar 2020 04:55:42 -0400 Received: from smtp2207-205.mail.aliyun.com ([121.197.207.205]:50324 "EHLO smtp2207-205.mail.aliyun.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727407AbgCYIzl (ORCPT ); Wed, 25 Mar 2020 04:55:41 -0400 X-Alimail-AntiSpam: AC=CONTINUE;BC=0.07436282|-1;CH=green;DM=|CONTINUE|false|;DS=CONTINUE|ham_system_inform|0.0433585-0.000252064-0.956389;FP=0|0|0|0|0|-1|-1|-1;HT=e02c03302;MF=liaoweixiong@allwinnertech.com;NM=1;PH=DS;RN=17;RT=17;SR=0;TI=SMTPD_---.H50xpyL_1585126516; Received: from PC-liaoweixiong.allwinnertech.com(mailfrom:liaoweixiong@allwinnertech.com fp:SMTPD_---.H50xpyL_1585126516) by smtp.aliyun-inc.com(10.147.42.241); Wed, 25 Mar 2020 16:55:33 +0800 From: WeiXiong Liao To: Kees Cook , Anton Vorontsov , Colin Cross , Tony Luck , Jonathan Corbet , Miquel Raynal , Richard Weinberger , Vignesh Raghavendra , Mauro Carvalho Chehab , Rob Herring , "David S. Miller" , Greg Kroah-Hartman , Jonathan Cameron Cc: linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mtd@lists.infradead.org, WeiXiong Liao Subject: [PATCH v3 08/11] pstore/zone: skip broken zone for MTD device Date: Wed, 25 Mar 2020 16:55:03 +0800 Message-Id: <1585126506-18635-9-git-send-email-liaoweixiong@allwinnertech.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1585126506-18635-1-git-send-email-liaoweixiong@allwinnertech.com> References: <1585126506-18635-1-git-send-email-liaoweixiong@allwinnertech.com> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org It's one of a series of patches to adapt to MTD device. It's different with block device, the MTD device will make new broken blocks (or bad block) while running. It's necessary for pstore/blk to skip the broken block. The MTD driver should return -ENOMSG if meets a bad block, which tells pstore/zone to skip and try next one. Signed-off-by: WeiXiong Liao --- fs/pstore/pstore_blk.c | 10 +++++-- fs/pstore/pstore_zone.c | 65 ++++++++++++++++++++++++++++++++++++--------- include/linux/pstore_blk.h | 3 ++- include/linux/pstore_zone.h | 12 ++++++--- 4 files changed, 71 insertions(+), 19 deletions(-) diff --git a/fs/pstore/pstore_blk.c b/fs/pstore/pstore_blk.c index 560e7b3f0945..d6949146135b 100644 --- a/fs/pstore/pstore_blk.c +++ b/fs/pstore/pstore_blk.c @@ -99,9 +99,12 @@ * means error. * @write: The same as @read, but the following error number: * -EBUSY means try to write again later. + * -ENOMSG means to try next zone. * @panic_write:The write operation only used for panic case. It's optional - * if you do not care panic log. The parameters and return value - * are the same as @read. + * if you do not care panic log. The parameters are relative + * value to storage. + * On success, the number of bytes should be returned, others + * excluding -ENOMSG mean error. -ENOMSG means to try next zone. */ struct psblk_device { unsigned long total_size; @@ -314,6 +317,9 @@ static ssize_t psblk_blk_panic_write(const char *buf, size_t size, /* size and off must align to SECTOR_SIZE for block device */ ret = blkdev_panic_write(buf, off >> SECTOR_SHIFT, size >> SECTOR_SHIFT); + /* try next zone */ + if (ret == -ENOMSG) + return ret; return ret ? -EIO : size; } diff --git a/fs/pstore/pstore_zone.c b/fs/pstore/pstore_zone.c index 1da4fc760d31..84ff53c1aaae 100644 --- a/fs/pstore/pstore_zone.c +++ b/fs/pstore/pstore_zone.c @@ -247,6 +247,9 @@ static int psz_zone_write(struct psz_zone *zone, return 0; dirty: + /* no need to mark dirty if going to try next zone */ + if (wcnt == -ENOMSG) + return -ENOMSG; atomic_set(&zone->dirty, true); /* flush dirty zones nicely */ if (wcnt == -EBUSY && !is_on_panic()) @@ -382,7 +385,11 @@ static int psz_recover_oops_meta(struct psz_context *cxt) return -EINVAL; rcnt = info->read((char *)buf, len, zone->off); - if (rcnt != len) { + if (rcnt == -ENOMSG) { + pr_debug("%s with id %lu may be broken, skip\n", + zone->name, i); + continue; + } else if (rcnt != len) { pr_err("read %s with id %lu failed\n", zone->name, i); return (int)rcnt < 0 ? (int)rcnt : -EIO; } @@ -717,24 +724,58 @@ static void psz_write_kmsg_hdr(struct psz_zone *zone, hdr->counter = 0; } +/* + * In case zone is broken, which may occur to MTD device, we try each zones, + * start at cxt->oops_write_cnt. + */ static inline int notrace psz_oops_write_record(struct psz_context *cxt, struct pstore_record *record) { + int ret = -EBUSY; size_t size, hlen; struct psz_zone *zone; - unsigned int zonenum; + unsigned int i; - zonenum = cxt->oops_write_cnt; - zone = cxt->opszs[zonenum]; - if (unlikely(!zone)) - return -ENOSPC; - cxt->oops_write_cnt = (zonenum + 1) % cxt->oops_max_cnt; + for (i = 0; i < cxt->oops_max_cnt; i++) { + unsigned int zonenum, len; + + zonenum = (cxt->oops_write_cnt + i) % cxt->oops_max_cnt; + zone = cxt->opszs[zonenum]; + if (unlikely(!zone)) + return -ENOSPC; - pr_debug("write %s to zone id %d\n", zone->name, zonenum); - psz_write_kmsg_hdr(zone, record); - hlen = sizeof(struct psz_oops_header); - size = min_t(size_t, record->size, zone->buffer_size - hlen); - return psz_zone_write(zone, FLUSH_ALL, record->buf, size, hlen); + /* avoid destorying old data, allocate a new one */ + len = zone->buffer_size + sizeof(*zone->buffer); + zone->oldbuf = zone->buffer; + zone->buffer = kzalloc(len, GFP_KERNEL); + if (!zone->buffer) { + zone->buffer = zone->oldbuf; + return -ENOMEM; + } + zone->buffer->sig = zone->oldbuf->sig; + + pr_debug("write %s to zone id %d\n", zone->name, zonenum); + psz_write_kmsg_hdr(zone, record); + hlen = sizeof(struct psz_oops_header); + size = min_t(size_t, record->size, zone->buffer_size - hlen); + ret = psz_zone_write(zone, FLUSH_ALL, record->buf, size, hlen); + if (likely(!ret || ret != -ENOMSG)) { + cxt->oops_write_cnt = zonenum + 1; + cxt->oops_write_cnt %= cxt->oops_max_cnt; + /* no need to try next zone, free last zone buffer */ + kfree(zone->oldbuf); + zone->oldbuf = NULL; + return ret; + } + + pr_debug("zone %u may be broken, try next dmesg zone\n", + zonenum); + kfree(zone->buffer); + zone->buffer = zone->oldbuf; + zone->oldbuf = NULL; + } + + return -EBUSY; } static int notrace psz_oops_write(struct psz_context *cxt, diff --git a/include/linux/pstore_blk.h b/include/linux/pstore_blk.h index d8f609e60288..828b0763d477 100644 --- a/include/linux/pstore_blk.h +++ b/include/linux/pstore_blk.h @@ -14,7 +14,8 @@ * @start_sect: start sector to block device * @sects: sectors count on buf * - * Return: On success, zero should be returned. Others mean error. + * Return: On success, zero should be returned. Others excluding -ENOMSG + * mean error. -ENOMSG means to try next zone. * * Panic write to block device must be aligned to SECTOR_SIZE. */ diff --git a/include/linux/pstore_zone.h b/include/linux/pstore_zone.h index a138e8b7dc20..2bfa79bff97b 100644 --- a/include/linux/pstore_zone.h +++ b/include/linux/pstore_zone.h @@ -23,11 +23,15 @@ * @read: The general read operation. Both of the function parameters * @size and @offset are relative value to storage. * On success, the number of bytes should be returned, others - * means error. - * @write: The same as @read, but -EBUSY means try to write again later. + * mean error. + * @write: The same as @read, but the following error number: + * -EBUSY means try to write again later. + * -ENOMSG means to try next zone. * @panic_write:The write operation only used for panic case. It's optional - * if you do not care panic log. The parameters and return value - * are the same as @read. + * if you do not care panic log. The parameters are relative + * value to storage. + * On success, the number of bytes should be returned, others + * excluding -ENOMSG mean error. -ENOMSG means to try next zone. */ struct psz_info { struct module *owner; -- 1.9.1