From patchwork Thu Aug 28 12:55:54 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: David Woodhouse X-Patchwork-Id: 383826 X-Patchwork-Delegate: dwmw2@infradead.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from bombadil.infradead.org (bombadil.infradead.org [IPv6:2001:1868:205::9]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 5C28814011E for ; Thu, 28 Aug 2014 22:58:19 +1000 (EST) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1XMzFB-000812-Tz; Thu, 28 Aug 2014 12:56:01 +0000 Received: from casper.infradead.org ([2001:770:15f::2]) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1XMzF9-00080i-S8 for linux-mtd@bombadil.infradead.org; Thu, 28 Aug 2014 12:56:00 +0000 Received: from shinybook.infradead.org ([2001:8b0:10b:1:e6ce:8fff:fe1f:f2c0]) by casper.infradead.org with esmtpsa (Exim 4.80.1 #2 (Red Hat Linux)) id 1XMzF5-0002rj-LZ; Thu, 28 Aug 2014 12:55:55 +0000 Message-ID: <1409230554.31489.29.camel@infradead.org> Subject: Re: jffs2 about highest_ino From: David Woodhouse To: =?UTF-8?Q?=E8=93=9D=E5=AE=87=E3=81=AE=E5=B9=BD=E6=B7=B1?= <249768522@qq.com> Date: Thu, 28 Aug 2014 13:55:54 +0100 In-Reply-To: References: X-Mailer: Evolution 3.12.5 (3.12.5-1.fc20) Mime-Version: 1.0 X-SRS-Rewrite: SMTP reverse-path rewritten from by casper.infradead.org See http://www.infradead.org/rpr.html Cc: linux-mtd@lists.infradead.org X-BeenThere: linux-mtd@lists.infradead.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: Linux MTD discussion mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-mtd" Errors-To: linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org On Thu, 2014-08-28 at 16:49 +0800, 蓝宇の幽深 wrote: > according to the jffs2 source code when creat a new file > the highest_ino will be add one,I used sqlite-3 in my system > linux2.6.30 and cpu sam9260 ,when "update" or "insert" sqlite-3 will > creat a Statement Journal file and delete it after finish,so once > operate will be increase "highest_ino",after the "highest_ino" more > than 10 million,I reset my system run to ‍‍‍ > > > if (!xattr) > xattr = jffs2_verify_xattr(c); > > > spin_lock(&c->inocache_lock); > > > ic = jffs2_get_ino_cache(c, c->checked_ino++); > > > if (!ic) { > spin_unlock(&c->inocache_lock); > continue; > }‍ > the jffs2 will eat cpu 100% for about 10 seconds and can not feed > watchdog, case the system reset again . so my problem is that whether > the "highest_ino" will decrease ??? Hm, at the very least there ought to be a cond_resched() in there somewhere. But really, the problem is that the iteration over inodes to be checked is *entirely* naïve. We have a hash table with all the existing inodes in it; we should just iterate over its contents, instead of iterating through the available number space from 1 to c->highest_ino and doing all the lookups in the hash table. Something like this... diff --git a/fs/jffs2/gc.c b/fs/jffs2/gc.c index 5a2dec2..6ef5246 100644 --- a/fs/jffs2/gc.c +++ b/fs/jffs2/gc.c @@ -135,6 +135,8 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) return -EINTR; for (;;) { + int bucket, want_ino; + spin_lock(&c->erase_completion_lock); if (!c->unchecked_size) break; @@ -142,29 +144,37 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) /* We can't start doing GC yet. We haven't finished checking the node CRCs etc. Do it now. */ - /* checked_ino is protected by the alloc_sem */ - if (c->checked_ino > c->highest_ino && xattr) { - pr_crit("Checked all inodes but still 0x%x bytes of unchecked space?\n", - c->unchecked_size); - jffs2_dbg_dump_block_lists_nolock(c); - spin_unlock(&c->erase_completion_lock); - mutex_unlock(&c->alloc_sem); - return -ENOSPC; - } - spin_unlock(&c->erase_completion_lock); if (!xattr) xattr = jffs2_verify_xattr(c); spin_lock(&c->inocache_lock); + want_ino = c->checked_ino; + for (bucket = c->checked_ino % c->inocache_hashsize ; bucket < c->inocache_hashsize; bucket++) { + for (ic = c->inocache_list[bucket]; ic; ic = ic->next) { + if (ic->ino >= want_ino) + goto got_next; + } + want_ino = 0; + } - ic = jffs2_get_ino_cache(c, c->checked_ino++); + /* Point c->checked_ino past the end of the last bucket. */ + c->checked_ino = c->highest_ino + c->inocache_hashsize; + c->checked_ino -= (c->checked_ino % c->inocache_hashsize) + 1; - if (!ic) { - spin_unlock(&c->inocache_lock); - continue; - } + spin_unlock(&c->inocache_lock); + + pr_crit("Checked all inodes but still 0x%x bytes of unchecked space?\n", + c->unchecked_size); + jffs2_dbg_dump_block_lists_nolock(c); + mutex_unlock(&c->alloc_sem); + return -ENOSPC; + + got_next: + /* c->checked_ino is actually the *next* one we want to check. And since + we're walking the buckets rather than doing it sequentially, it's: */ + c->checked_ino = ic->ino + c->inocache_hashsize; if (!ic->pino_nlink) { jffs2_dbg(1, "Skipping check of ino #%d with nlink/pino zero\n", @@ -196,7 +206,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) ic->ino); /* We need to come back again for the _same_ inode. We've made no progress in this case, but that should be OK */ - c->checked_ino--; + c->checked_ino = ic->ino; mutex_unlock(&c->alloc_sem); sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock);