Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 733802d9 authored by Artem B. Bityutskiy's avatar Artem B. Bityutskiy Committed by Thomas Gleixner
Browse files

[JFFS2] Debug code simplification, update TODO



Simplify the debugging code further.
Update the TODO list

Signed-off-by: default avatarArtem B. Bityutskiy <dedekind@infradead.org>
Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
parent b523b3ba
Loading
Loading
Loading
Loading
+19 −19
Original line number Diff line number Diff line
$Id: TODO,v 1.10 2002/09/09 16:31:21 dwmw2 Exp $
$Id: TODO,v 1.18 2005/09/22 11:24:56 dedekind Exp $

 - support asynchronous operation -- add a per-fs 'reserved_space' count,
   let each outstanding write reserve the _maximum_ amount of physical
   space it could take. Let GC flush the outstanding writes because the
   reservations will necessarily be pessimistic. With this we could even
   do shared writable mmap, if we can have a fs hook for do_wp_page() to
   make the reservation.
 - disable compression in commit_write()?
 - fine-tune the allocation / GC thresholds
 - chattr support - turning on/off and tuning compression per-inode
@@ -11,26 +17,15 @@ $Id: TODO,v 1.10 2002/09/09 16:31:21 dwmw2 Exp $
 - test, test, test

 - NAND flash support:
	- flush_wbuf using GC to fill it, don't just pad.
	- Deal with write errors. Data don't get lost - we just have to write 
	  the affected node(s) out again somewhere else.
	- make fsync flush only if actually required
	- make sys_sync() work.
	- reboot notifier
	- timed flush of old wbuf
	- fix magical second arg of jffs2_flush_wbuf(). Split into two or more functions instead.

	- almost done :)
	- use bad block check instead of the hardwired byte check

 - Optimisations:
   - Stop GC from decompressing and immediately recompressing nodes which could
     just be copied intact. (We now keep track of REF_PRISTINE flag. Easy now.)
   - Furthermore, in the case where it could be copied intact we don't even need
     to call iget() for it -- if we use (raw_node_raw->flash_offset & 2) as a flag
     to show a node can be copied intact and it's _not_ in icache, we could just do
     it, fix up the next_in_ino list and move on. We would need a way to find out
     _whether_ it's in icache though -- if it's in icache we also need to do the 
     fragment lists, etc. P'raps a flag or pointer in the jffs2_inode_cache could
     help. (We have half of this now.)
   - Split writes so they go to two separate blocks rather than just c->nextblock.
	By writing _new_ nodes to one block, and garbage-collected REF_PRISTINE
	nodes to a different one, we can separate clean nodes from those which
	are likely to become dirty, and end up with blocks which are each far
	closer to 100% or 0% clean, hence speeding up later GC progress dramatically.
   - Stop keeping name in-core with struct jffs2_full_dirent. If we keep the hash in 
     the full dirent, we only need to go to the flash in lookup() when we think we've
     got a match, and in readdir(). 
@@ -38,3 +33,8 @@ $Id: TODO,v 1.10 2002/09/09 16:31:21 dwmw2 Exp $
   - Remove totlen from jffs2_raw_node_ref? Need to have totlen passed into
	jffs2_mark_node_obsolete(). Can all callers work it out?
   - Remove size from jffs2_raw_node_frag. 

dedekind:
1. __jffs2_flush_wbuf() has a strange 'pad' parameter. Eliminate.
2. get_sb()->build_fs()->scan() path... Why get_sb() removes scan()'s crap in
   case of failure? scan() does not clean everything. Fix.
+53 −59
Original line number Diff line number Diff line
@@ -7,7 +7,7 @@
 *
 * For licensing information, see the file 'LICENCE' in this directory.
 *
 * $Id: build.c,v 1.79 2005/09/07 11:21:57 havasi Exp $
 * $Id: build.c,v 1.83 2005/09/21 15:52:33 dedekind Exp $
 *
 */

@@ -18,7 +18,8 @@
#include <linux/mtd/mtd.h>
#include "nodelist.h"

static void jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *, struct jffs2_inode_cache *, struct jffs2_full_dirent **);
static void jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *,
		struct jffs2_inode_cache *, struct jffs2_full_dirent **);

static inline struct jffs2_inode_cache *
first_inode_chain(int *i, struct jffs2_sb_info *c)
@@ -46,11 +47,12 @@ next_inode(int *i, struct jffs2_inode_cache *ic, struct jffs2_sb_info *c)
	     ic = next_inode(&i, ic, (c)))


static inline void jffs2_build_inode_pass1(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic)
static inline void jffs2_build_inode_pass1(struct jffs2_sb_info *c,
					struct jffs2_inode_cache *ic)
{
	struct jffs2_full_dirent *fd;

	D1(printk(KERN_DEBUG "jffs2_build_inode building directory inode #%u\n", ic->ino));
	dbg_fsbuild("building directory inode #%u\n", ic->ino);

	/* For each child, increase nlink */
	for(fd = ic->scan_dents; fd; fd = fd->next) {
@@ -58,26 +60,23 @@ static inline void jffs2_build_inode_pass1(struct jffs2_sb_info *c, struct jffs2
		if (!fd->ino)
			continue;

		/* XXX: Can get high latency here with huge directories */
		/* we can get high latency here with huge directories */

		child_ic = jffs2_get_ino_cache(c, fd->ino);
		if (!child_ic) {
			printk(KERN_NOTICE "Eep. Child \"%s\" (ino #%u) of dir ino #%u doesn't exist!\n",
			dbg_fsbuild("child \"%s\" (ino #%u) of dir ino #%u doesn't exist!\n",
				  fd->name, fd->ino, ic->ino);
			jffs2_mark_node_obsolete(c, fd->raw);
			continue;
		}

		if (child_ic->nlink++ && fd->type == DT_DIR) {
			printk(KERN_NOTICE "Child dir \"%s\" (ino #%u) of dir ino #%u appears to be a hard link\n", fd->name, fd->ino, ic->ino);
			if (fd->ino == 1 && ic->ino == 1) {
				printk(KERN_NOTICE "This is mostly harmless, and probably caused by creating a JFFS2 image\n");
				printk(KERN_NOTICE "using a buggy version of mkfs.jffs2. Use at least v1.17.\n");
			}
			/* What do we do about it? */
			JFFS2_ERROR("child dir \"%s\" (ino #%u) of dir ino #%u appears to be a hard link\n",
				fd->name, fd->ino, ic->ino);
			/* TODO: What do we do about it? */
		}
		D1(printk(KERN_DEBUG "Increased nlink for child \"%s\" (ino #%u)\n", fd->name, fd->ino));
		/* Can't free them. We might need them in pass 2 */
		dbg_fsbuild("increased nlink for child \"%s\" (ino #%u)\n", fd->name, fd->ino);
		/* Can't free scan_dents so far. We might need them in pass 2 */
	}
}

@@ -94,6 +93,8 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c)
	struct jffs2_full_dirent *fd;
	struct jffs2_full_dirent *dead_fds = NULL;

	dbg_fsbuild("build FS data structures\n");

	/* First, scan the medium and build all the inode caches with
	   lists of physical nodes */

@@ -103,33 +104,29 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c)
	if (ret)
		goto exit;

	D1(printk(KERN_DEBUG "Scanned flash completely\n"));
	dbg_fsbuild("scanned flash completely\n");
	jffs2_dbg_dump_block_lists_nolock(c);

	dbg_fsbuild("pass 1 starting\n");
	c->flags |= JFFS2_SB_FLAG_BUILDING;
	/* Now scan the directory tree, increasing nlink according to every dirent found. */
	for_each_inode(i, c, ic) {
		D1(printk(KERN_DEBUG "Pass 1: ino #%u\n", ic->ino));

		D1(BUG_ON(ic->ino > c->highest_ino));

		if (ic->scan_dents) {
			jffs2_build_inode_pass1(c, ic);
			cond_resched();
		}
	}

	D1(printk(KERN_DEBUG "Pass 1 complete\n"));
	dbg_fsbuild("pass 1 complete\n");

	/* Next, scan for inodes with nlink == 0 and remove them. If
	   they were directories, then decrement the nlink of their
	   children too, and repeat the scan. As that's going to be
	   a fairly uncommon occurrence, it's not so evil to do it this
	   way. Recursion bad. */
	D1(printk(KERN_DEBUG "Pass 2 starting\n"));
	dbg_fsbuild("pass 2 starting\n");

	for_each_inode(i, c, ic) {
		D1(printk(KERN_DEBUG "Pass 2: ino #%u, nlink %d, ic %p, nodes %p\n", ic->ino, ic->nlink, ic, ic->nodes));
		if (ic->nlink)
			continue;
			
@@ -137,26 +134,24 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c)
		cond_resched();
	} 

	D1(printk(KERN_DEBUG "Pass 2a starting\n"));
	dbg_fsbuild("pass 2a starting\n");

	while (dead_fds) {
		fd = dead_fds;
		dead_fds = fd->next;

		ic = jffs2_get_ino_cache(c, fd->ino);
		D1(printk(KERN_DEBUG "Removing dead_fd ino #%u (\"%s\"), ic at %p\n", fd->ino, fd->name, ic));

		if (ic)
			jffs2_build_remove_unlinked_inode(c, ic, &dead_fds);
		jffs2_free_full_dirent(fd);
	}

	D1(printk(KERN_DEBUG "Pass 2 complete\n"));
	dbg_fsbuild("pass 2a complete\n");
	dbg_fsbuild("freeing temporary data structures\n");
	
	/* Finally, we can scan again and free the dirent structs */
	for_each_inode(i, c, ic) {
		D1(printk(KERN_DEBUG "Pass 3: ino #%u, ic %p, nodes %p\n", ic->ino, ic, ic->nodes));

		while(ic->scan_dents) {
			fd = ic->scan_dents;
			ic->scan_dents = fd->next;
@@ -167,8 +162,7 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c)
	}
	c->flags &= ~JFFS2_SB_FLAG_BUILDING;
	
	D1(printk(KERN_DEBUG "Pass 3 complete\n"));
	jffs2_dbg_dump_block_lists_nolock(c);
	dbg_fsbuild("FS build complete\n");

	/* Rotate the lists by some number to ensure wear levelling */
	jffs2_rotate_lists(c);
@@ -189,24 +183,26 @@ exit:
	return ret;
}

static void jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic, struct jffs2_full_dirent **dead_fds)
static void jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *c,
					struct jffs2_inode_cache *ic,
					struct jffs2_full_dirent **dead_fds)
{
	struct jffs2_raw_node_ref *raw;
	struct jffs2_full_dirent *fd;

	D1(printk(KERN_DEBUG "JFFS2: Removing ino #%u with nlink == zero.\n", ic->ino));
	dbg_fsbuild("removing ino #%u with nlink == zero.\n", ic->ino);
	
	raw = ic->nodes;
	while (raw != (void *)ic) {
		struct jffs2_raw_node_ref *next = raw->next_in_ino;
		D1(printk(KERN_DEBUG "obsoleting node at 0x%08x\n", ref_offset(raw)));
		dbg_fsbuild("obsoleting node at 0x%08x\n", ref_offset(raw));
		jffs2_mark_node_obsolete(c, raw);
		raw = next;
	}

	if (ic->scan_dents) {
		int whinged = 0;
		D1(printk(KERN_DEBUG "Inode #%u was a directory which may have children...\n", ic->ino));
		dbg_fsbuild("inode #%u was a directory which may have children...\n", ic->ino);

		while(ic->scan_dents) {
			struct jffs2_inode_cache *child_ic;
@@ -216,21 +212,19 @@ static void jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *c, struct jf

			if (!fd->ino) {
				/* It's a deletion dirent. Ignore it */
				D1(printk(KERN_DEBUG "Child \"%s\" is a deletion dirent, skipping...\n", fd->name));
				dbg_fsbuild("child \"%s\" is a deletion dirent, skipping...\n", fd->name);
				jffs2_free_full_dirent(fd);
				continue;
			}
			if (!whinged) {
			if (!whinged)
				whinged = 1;
				printk(KERN_NOTICE "Inode #%u was a directory with children - removing those too...\n", ic->ino);
			}

			D1(printk(KERN_DEBUG "Removing child \"%s\", ino #%u\n",
				  fd->name, fd->ino));
			dbg_fsbuild("removing child \"%s\", ino #%u\n", fd->name, fd->ino);
			
			child_ic = jffs2_get_ino_cache(c, fd->ino);
			if (!child_ic) {
				printk(KERN_NOTICE "Cannot remove child \"%s\", ino #%u, because it doesn't exist\n", fd->name, fd->ino);
				dbg_fsbuild("cannot remove child \"%s\", ino #%u, because it doesn't exist\n",
						fd->name, fd->ino);
				jffs2_free_full_dirent(fd);
				continue;
			}
@@ -241,13 +235,13 @@ static void jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *c, struct jf
			child_ic->nlink--;
			
			if (!child_ic->nlink) {
				D1(printk(KERN_DEBUG "Inode #%u (\"%s\") has now got zero nlink. Adding to dead_fds list.\n",
					  fd->ino, fd->name));
				dbg_fsbuild("inode #%u (\"%s\") has now got zero nlink, adding to dead_fds list.\n",
					  fd->ino, fd->name);
				fd->next = *dead_fds;
				*dead_fds = fd;
			} else {
				D1(printk(KERN_DEBUG "Inode #%u (\"%s\") has now got nlink %d. Ignoring.\n",
					  fd->ino, fd->name, child_ic->nlink));
				dbg_fsbuild("inode #%u (\"%s\") has now got nlink %d. Ignoring.\n",
					  fd->ino, fd->name, child_ic->nlink);
				jffs2_free_full_dirent(fd);
			}
		}
@@ -295,20 +289,20 @@ static void jffs2_calc_trigger_levels(struct jffs2_sb_info *c)
	   trying to GC to make more space. It'll be a fruitless task */
	c->nospc_dirty_size = c->sector_size + (c->flash_size / 100);

	D1(printk(KERN_DEBUG "JFFS2 trigger levels (size %d KiB, block size %d KiB, %d blocks)\n",
		  c->flash_size / 1024, c->sector_size / 1024, c->nr_blocks));
	D1(printk(KERN_DEBUG "Blocks required to allow deletion:    %d (%d KiB)\n",
		  c->resv_blocks_deletion, c->resv_blocks_deletion*c->sector_size/1024));
	D1(printk(KERN_DEBUG "Blocks required to allow writes:      %d (%d KiB)\n",
		  c->resv_blocks_write, c->resv_blocks_write*c->sector_size/1024));
	D1(printk(KERN_DEBUG "Blocks required to quiesce GC thread: %d (%d KiB)\n",
		  c->resv_blocks_gctrigger, c->resv_blocks_gctrigger*c->sector_size/1024));
	D1(printk(KERN_DEBUG "Blocks required to allow GC merges:   %d (%d KiB)\n",
		  c->resv_blocks_gcmerge, c->resv_blocks_gcmerge*c->sector_size/1024));
	D1(printk(KERN_DEBUG "Blocks required to GC bad blocks:     %d (%d KiB)\n",
		  c->resv_blocks_gcbad, c->resv_blocks_gcbad*c->sector_size/1024));
	D1(printk(KERN_DEBUG "Amount of dirty space required to GC: %d bytes\n",
		  c->nospc_dirty_size));
	dbg_fsbuild("JFFS2 trigger levels (size %d KiB, block size %d KiB, %d blocks)\n",
		  c->flash_size / 1024, c->sector_size / 1024, c->nr_blocks);
	dbg_fsbuild("Blocks required to allow deletion:    %d (%d KiB)\n",
		  c->resv_blocks_deletion, c->resv_blocks_deletion*c->sector_size/1024);
	dbg_fsbuild("Blocks required to allow writes:      %d (%d KiB)\n",
		  c->resv_blocks_write, c->resv_blocks_write*c->sector_size/1024);
	dbg_fsbuild("Blocks required to quiesce GC thread: %d (%d KiB)\n",
		  c->resv_blocks_gctrigger, c->resv_blocks_gctrigger*c->sector_size/1024);
	dbg_fsbuild("Blocks required to allow GC merges:   %d (%d KiB)\n",
		  c->resv_blocks_gcmerge, c->resv_blocks_gcmerge*c->sector_size/1024);
	dbg_fsbuild("Blocks required to GC bad blocks:     %d (%d KiB)\n",
		  c->resv_blocks_gcbad, c->resv_blocks_gcbad*c->sector_size/1024);
	dbg_fsbuild("Amount of dirty space required to GC: %d bytes\n",
		  c->nospc_dirty_size);
} 

int jffs2_do_mount_fs(struct jffs2_sb_info *c)
@@ -358,7 +352,7 @@ int jffs2_do_mount_fs(struct jffs2_sb_info *c)
		return ret;

	if (jffs2_build_filesystem(c)) {
		D1(printk(KERN_DEBUG "build_fs failed\n"));
		dbg_fsbuild("build_fs failed\n");
		jffs2_free_ino_caches(c);
		jffs2_free_raw_node_refs(c);
#ifndef __ECOS
+2 −1
Original line number Diff line number Diff line
@@ -7,7 +7,7 @@
 *
 * For licensing information, see the file 'LICENCE' in this directory.
 *
 * $Id: debug.c,v 1.10 2005/09/14 16:57:32 dedekind Exp $
 * $Id: debug.c,v 1.11 2005/09/21 13:28:35 dedekind Exp $
 *
 */
#include <linux/kernel.h>
@@ -15,6 +15,7 @@
#include <linux/pagemap.h>
#include <linux/crc32.h>
#include <linux/jffs2.h>
#include <linux/mtd/mtd.h>
#include "nodelist.h"
#include "debug.h"

+32 −18
Original line number Diff line number Diff line
@@ -7,7 +7,7 @@
 *
 * For licensing information, see the file 'LICENCE' in this directory.
 *
 * $Id: debug.h,v 1.16 2005/09/14 16:57:32 dedekind Exp $
 * $Id: debug.h,v 1.18 2005/09/21 10:26:26 dedekind Exp $
 *
 */
#ifndef _JFFS2_DEBUG_H_
@@ -23,16 +23,23 @@
/* Enable "paranoia" checks and dumps */
#define JFFS2_DBG_PARANOIA_CHECKS
#define JFFS2_DBG_DUMPS

/* 
 * By defining/undefining the below macros one may select debugging messages
 * fro specific JFFS2 subsystems.
 */
#define JFFS2_DBG_READINODE_MESSAGES
#define JFFS2_DBG_FRAGTREE_MESSAGES
#define JFFS2_DBG_DENTLIST_MESSAGES
#define JFFS2_DBG_NODEREF_MESSAGES
#define JFFS2_DBG_INOCACHE_MESSAGES
#define JFFS2_DBG_SUMMARY_MESSAGES
#define JFFS2_DBG_FSBUILD_MESSAGES
#endif

#if CONFIG_JFFS2_FS_DEBUG == 2
#define JFFS2_DBG_FRAGTREE2_MESSAGES
#define JFFS2_DBG_MEMALLOC_MESSAGES
#endif

/* Sanity checks are supposed to be light-weight and enabled by default */
@@ -40,7 +47,7 @@

/* 
 * Dx() are mainly used for debugging messages, they must go away and be
 * superseded by nicer JFFS2_DBG_XXX() macros...
 * superseded by nicer dbg_xxx() macros...
 */
#if CONFIG_JFFS2_FS_DEBUG > 0
#define D1(x) x
@@ -105,56 +112,63 @@
 */
/* Read inode debugging messages */
#ifdef JFFS2_DBG_READINODE_MESSAGES
#define JFFS2_DBG_READINODE(fmt, ...)	JFFS2_DEBUG(fmt, ##__VA_ARGS__)
#define dbg_readinode(fmt, ...)	JFFS2_DEBUG(fmt, ##__VA_ARGS__)
#else
#define JFFS2_DBG_READINODE(fmt, ...)
#define dbg_readinode(fmt, ...)
#endif

/* Fragtree build debugging messages */
#ifdef JFFS2_DBG_FRAGTREE_MESSAGES
#define JFFS2_DBG_FRAGTREE(fmt, ...)	JFFS2_DEBUG(fmt, ##__VA_ARGS__)
#define dbg_fragtree(fmt, ...)	JFFS2_DEBUG(fmt, ##__VA_ARGS__)
#else
#define JFFS2_DBG_FRAGTREE(fmt, ...)
#define dbg_fragtree(fmt, ...)
#endif
#ifdef JFFS2_DBG_FRAGTREE2_MESSAGES
#define JFFS2_DBG_FRAGTREE2(fmt, ...)	JFFS2_DEBUG(fmt, ##__VA_ARGS__)
#define dbg_fragtree2(fmt, ...)	JFFS2_DEBUG(fmt, ##__VA_ARGS__)
#else
#define JFFS2_DBG_FRAGTREE2(fmt, ...)
#define dbg_fragtree2(fmt, ...)
#endif

/* Directory entry list manilulation debugging messages */
#ifdef JFFS2_DBG_DENTLIST_MESSAGES
#define JFFS2_DBG_DENTLIST(fmt, ...)	JFFS2_DEBUG(fmt, ##__VA_ARGS__)
#define dbg_dentlist(fmt, ...)	JFFS2_DEBUG(fmt, ##__VA_ARGS__)
#else
#define JFFS2_DBG_DENTLIST(fmt, ...)
#define dbg_dentlist(fmt, ...)
#endif

/* Print the messages about manipulating node_refs */
#ifdef JFFS2_DBG_NODEREF_MESSAGES
#define JFFS2_DBG_NODEREF(fmt, ...)	JFFS2_DEBUG(fmt, ##__VA_ARGS__)
#define dbg_noderef(fmt, ...)	JFFS2_DEBUG(fmt, ##__VA_ARGS__)
#else
#define JFFS2_DBG_NODEREF(fmt, ...)
#define dbg_noderef(fmt, ...)
#endif

/* Manipulations with the list of inodes (JFFS2 inocache) */
#ifdef JFFS2_DBG_INOCACHE_MESSAGES
#define JFFS2_DBG_INOCACHE(fmt, ...)	JFFS2_DEBUG(fmt, ##__VA_ARGS__)
#define dbg_inocache(fmt, ...)	JFFS2_DEBUG(fmt, ##__VA_ARGS__)
#else
#define JFFS2_DBG_INOCACHE(fmt, ...)
#define dbg_inocache(fmt, ...)
#endif

/* Summary debugging messages */
#ifdef JFFS2_DBG_SUMMARY_MESSAGES
#define JFFS2_DBG_SUMMARY(fmt, ...)	JFFS2_DEBUG(fmt, ##__VA_ARGS__)
#define dbg_summary(fmt, ...)	JFFS2_DEBUG(fmt, ##__VA_ARGS__)
#else
#define dbg_summary(fmt, ...)
#endif

/* File system build messages */
#ifdef JFFS2_DBG_FSBUILD_MESSAGES
#define dbg_fsbuild(fmt, ...)	JFFS2_DEBUG(fmt, ##__VA_ARGS__)
#else
#define JFFS2_DBG_SUMMARY(fmt, ...)
#define dbg_fsbuild(fmt, ...)
#endif

/* Watch the object allocations */
#ifdef JFFS2_DBG_MEMALLOC_MESSAGES
#define JFFS2_DBG_MEMALLOC(fmt, ...)	JFFS2_DEBUG(fmt, ##__VA_ARGS__)
#define dbg_memalloc(fmt, ...)	JFFS2_DEBUG(fmt, ##__VA_ARGS__)
#else
#define JFFS2_DBG_MEMALLOC(fmt, ...)
#define dbg_memalloc(fmt, ...)
#endif


+1 −1
Original line number Diff line number Diff line
@@ -7,7 +7,7 @@
 *
 * For licensing information, see the file 'LICENCE' in this directory.
 *
 * $Id: erase.c,v 1.83 2005/07/22 10:32:08 dedekind Exp $
 * $Id: erase.c,v 1.85 2005/09/20 14:53:15 dedekind Exp $
 *
 */

Loading