From patchwork Thu Jul 19 23:50:11 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Theuns Verwoerd X-Patchwork-Id: 946656 X-Patchwork-Delegate: dwmw2@infradead.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.infradead.org (client-ip=2607:7c80:54:e::133; helo=bombadil.infradead.org; envelope-from=linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=alliedtelesis.co.nz Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="KO6vBQsY"; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=alliedtelesis.co.nz header.i=@alliedtelesis.co.nz header.b="fiNgZt0y"; dkim-atps=neutral Received: from bombadil.infradead.org (bombadil.infradead.org [IPv6:2607:7c80:54:e::133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 41WrQG6CPMz9s1R for ; Fri, 20 Jul 2018 09:51:34 +1000 (AEST) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:MIME-Version:Cc:List-Subscribe: List-Help:List-Post:List-Archive:List-Unsubscribe:List-Id:References: In-Reply-To:Message-Id:Date:Subject:To:From:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Owner; bh=p52JKMeoFMacYZv+T39+F07oxixgVWUZ/Sseau4aHTg=; b=KO6vBQsYPUBJyaAlAM8s65TwnB /QEjBtDGa3DegYytMi0zg6SAJS5CycuNafkcl9V6a++d/MpxZWmwAlcvl2ST/nQempanh+XsYF1M3 u1yVSQogpnRfuI365jqLGnQtr5vP+BX4cYCV1jSrfE/+JM2WiN8WwEg24fD755aMQJLJ+6eLONKm5 d5S19taxRXG0wmqKCvo761eXOTBtuZZXd1tE45BHdwBgDXA+Fejg0Ohx+R6yHawq41lJparoVvUCC eAWtRqRZitCVQNqaShIRJxJ76A1Ck/axSVKirkw+VsSlJoGlszw0xom4fSolQKj7pK/JDt1idT+YJ koGdSfjA==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1fgIhj-0004wU-Pz; Thu, 19 Jul 2018 23:51:27 +0000 Received: from gate2.alliedtelesis.co.nz ([2001:df5:b000:5::4]) by bombadil.infradead.org with esmtps (Exim 4.90_1 #2 (Red Hat Linux)) id 1fgIhY-0004Ye-Je for linux-mtd@lists.infradead.org; Thu, 19 Jul 2018 23:51:18 +0000 Received: from mmarshal3.atlnz.lc (mmarshal3.atlnz.lc [10.32.18.43]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by gate2.alliedtelesis.co.nz (Postfix) with ESMTPS id 356FE8365F; Fri, 20 Jul 2018 11:50:22 +1200 (NZST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=alliedtelesis.co.nz; s=mail; t=1532044222; bh=d7Zq3KdnRzs5/bzq7D/gl41p3G+03wOCg8YjFYqGRxQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=fiNgZt0yaex9XVgEaEZLfdozrdGYkP9S87vqRcQoyz1aADVXolvIWUYm1EhH2COfz KZ9Lb4iace3DgnjNrgjDmdTftvOoMRphsqrD0vYSmSL8BOiM/tYrVwpSosgSPeWKsk aSTkVR+5ucnexY0al3EYleOCMFAR4cIFwnA7b7zc= Received: from smtp (Not Verified[10.32.16.33]) by mmarshal3.atlnz.lc with Trustwave SEG (v7, 5, 8, 10121) id ; Fri, 20 Jul 2018 11:50:22 +1200 Received: from theunsv-dl.ws.atlnz.lc (theunsv-dl.ws.atlnz.lc [10.33.14.29]) by smtp (Postfix) with ESMTP id 08F1413EED3; Fri, 20 Jul 2018 11:50:23 +1200 (NZST) Received: by theunsv-dl.ws.atlnz.lc (Postfix, from userid 1451) id EA8535A04AF; Fri, 20 Jul 2018 11:50:21 +1200 (NZST) From: Theuns Verwoerd To: dwmw2@infradead.org, linux-mtd@lists.infradead.org, linux-kernel@vger.kernel.org Subject: [PATCH 1/2] jffs2: Provide forced dirty node cleanup via POLL signal Date: Fri, 20 Jul 2018 11:50:11 +1200 Message-Id: X-Mailer: git-send-email 2.18.0 In-Reply-To: References: X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20180719_165117_090432_AD71EAE4 X-CRM114-Status: GOOD ( 14.31 ) X-Spam-Score: -0.1 (/) X-Spam-Report: SpamAssassin version 3.4.1 on bombadil.infradead.org summary: Content analysis details: (-0.1 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 SPF_HELO_PASS SPF: HELO matches SPF record -0.0 SPF_PASS SPF: sender matches SPF record 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature X-BeenThere: linux-mtd@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: Linux MTD discussion mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Theuns Verwoerd MIME-Version: 1.0 Sender: "linux-mtd" Errors-To: linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org Secure deletion under JFFS2 is complicated by the log of dirty nodes that may contain obsoleted versions of sensitive data. There is an existing mechanism to trigger a single gc step via -HUP signal; extend this to trigger gc collection of all currently-dirty data via a -POLL signal. On receipt of -POLL, the gc will retire the current nextblock, store the last dirty list entry, and keep continuously cycling collection until that entry has been cleaned. Signed-off-by: Theuns Verwoerd --- fs/jffs2/background.c | 31 ++++++++++++++++++++++++++++++- fs/jffs2/build.c | 1 + fs/jffs2/jffs2_fs_sb.h | 2 ++ fs/jffs2/nodelist.h | 1 + fs/jffs2/nodemgmt.c | 6 +++++- 5 files changed, 39 insertions(+), 2 deletions(-) diff --git a/fs/jffs2/background.c b/fs/jffs2/background.c index 453a6a1fff34..4c29e2d323c4 100644 --- a/fs/jffs2/background.c +++ b/fs/jffs2/background.c @@ -72,15 +72,27 @@ void jffs2_stop_garbage_collect_thread(struct jffs2_sb_info *c) wait_for_completion(&c->gc_thread_exit); } +static int list_contains(struct list_head *list, struct list_head *entry) +{ + struct list_head *ptr; + + list_for_each(ptr, list) { + if (ptr == entry) + return 1; + } + return 0; +} + static int jffs2_garbage_collect_thread(void *_c) { struct jffs2_sb_info *c = _c; sigset_t hupmask; - siginitset(&hupmask, sigmask(SIGHUP)); + siginitset(&hupmask, sigmask(SIGHUP) | sigmask(SIGPOLL)); allow_signal(SIGKILL); allow_signal(SIGSTOP); allow_signal(SIGHUP); + allow_signal(SIGPOLL); c->gc_task = current; complete(&c->gc_thread_start); @@ -143,6 +155,15 @@ static int jffs2_garbage_collect_thread(void *_c) jffs2_dbg(1, "%s(): SIGHUP received\n", __func__); break; + case SIGPOLL: + if (!c->tidemark) { + /* Force retire current half-used block */ + if (c->nextblock) + jffs2_close_nextblock(c, c->nextblock); + /* Keep going until we hit the last element in the (now) current dirty list */ + c->tidemark = c->dirty_list.prev; + } + break; default: jffs2_dbg(1, "%s(): signal %ld received\n", __func__, signr); @@ -156,6 +177,14 @@ static int jffs2_garbage_collect_thread(void *_c) pr_notice("No space for garbage collection. Aborting GC thread\n"); goto die; } + /* If we're working towards a tidemark, keep going until it's clean */ + if (c->tidemark && ( + !list_empty(&c->very_dirty_list) || + list_contains(&c->dirty_list, c->tidemark) || + (&c->gcblock->list) == c->tidemark)) + goto again; + else if (c->tidemark) + c->tidemark = NULL; } die: spin_lock(&c->erase_completion_lock); diff --git a/fs/jffs2/build.c b/fs/jffs2/build.c index b288c8ae1236..7d128705648f 100644 --- a/fs/jffs2/build.c +++ b/fs/jffs2/build.c @@ -405,6 +405,7 @@ int jffs2_do_mount_fs(struct jffs2_sb_info *c) INIT_LIST_HEAD(&c->bad_used_list); c->highest_ino = 1; c->summary = NULL; + c->tidemark = NULL; ret = jffs2_sum_init(c); if (ret) diff --git a/fs/jffs2/jffs2_fs_sb.h b/fs/jffs2/jffs2_fs_sb.h index 778275f48a87..25960589e3c0 100644 --- a/fs/jffs2/jffs2_fs_sb.h +++ b/fs/jffs2/jffs2_fs_sb.h @@ -87,6 +87,8 @@ struct jffs2_sb_info { uint32_t nospc_dirty_size; + struct list_head *tidemark; /* Last dirty block at the time a full sync started */ + uint32_t nr_blocks; struct jffs2_eraseblock *blocks; /* The whole array of blocks. Used for getting blocks * from the offset (blocks[ofs / sector_size]) */ diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h index 0637271f3770..73348bc7f545 100644 --- a/fs/jffs2/nodelist.h +++ b/fs/jffs2/nodelist.h @@ -386,6 +386,7 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *len, int prio, uint32_t sumsize); int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *len, uint32_t sumsize); +void jffs2_close_nextblock(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb); struct jffs2_raw_node_ref *jffs2_add_physical_node_ref(struct jffs2_sb_info *c, uint32_t ofs, uint32_t len, struct jffs2_inode_cache *ic); diff --git a/fs/jffs2/nodemgmt.c b/fs/jffs2/nodemgmt.c index a7bbe879cfc3..c07c53f69516 100644 --- a/fs/jffs2/nodemgmt.c +++ b/fs/jffs2/nodemgmt.c @@ -240,7 +240,7 @@ int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, /* Classify nextblock (clean, dirty of verydirty) and force to select an other one */ -static void jffs2_close_nextblock(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) +void jffs2_close_nextblock(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) { if (c->nextblock == NULL) { @@ -875,6 +875,10 @@ int jffs2_thread_should_wake(struct jffs2_sb_info *c) } } + /* Pending cleanup, always wake */ + if (c->tidemark) + ret = 1; + jffs2_dbg(1, "%s(): nr_free_blocks %d, nr_erasing_blocks %d, dirty_size 0x%x, vdirty_blocks %d: %s\n", __func__, c->nr_free_blocks, c->nr_erasing_blocks, c->dirty_size, nr_very_dirty, ret ? "yes" : "no");