jffs2 about highest_ino
David Woodhouse
dwmw2 at infradead.org
Thu Aug 28 05:55:54 PDT 2014
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);
--
David Woodhouse Open Source Technology Centre
David.Woodhouse at intel.com Intel Corporation
-------------- next part --------------
A non-text attachment was scrubbed...
Name: smime.p7s
Type: application/x-pkcs7-signature
Size: 5745 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-mtd/attachments/20140828/835d6661/attachment.bin>
More information about the linux-mtd
mailing list