xref: /openbmc/linux/fs/jffs2/build.c (revision 2612e3bbc0386368a850140a6c9b990cd496a5ec)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * JFFS2 -- Journalling Flash File System, Version 2.
31da177e4SLinus Torvalds  *
4c00c310eSDavid Woodhouse  * Copyright © 2001-2007 Red Hat, Inc.
56088c058SDavid Woodhouse  * Copyright © 2004-2010 David Woodhouse <dwmw2@infradead.org>
61da177e4SLinus Torvalds  *
71da177e4SLinus Torvalds  * Created by David Woodhouse <dwmw2@infradead.org>
81da177e4SLinus Torvalds  *
91da177e4SLinus Torvalds  * For licensing information, see the file 'LICENCE' in this directory.
101da177e4SLinus Torvalds  *
111da177e4SLinus Torvalds  */
121da177e4SLinus Torvalds 
135a528957SJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
145a528957SJoe Perches 
151da177e4SLinus Torvalds #include <linux/kernel.h>
161da177e4SLinus Torvalds #include <linux/sched.h>
171da177e4SLinus Torvalds #include <linux/slab.h>
181da177e4SLinus Torvalds #include <linux/vmalloc.h>
191da177e4SLinus Torvalds #include <linux/mtd/mtd.h>
201d5cfdb0STetsuo Handa #include <linux/mm.h> /* kvfree() */
211da177e4SLinus Torvalds #include "nodelist.h"
221da177e4SLinus Torvalds 
23733802d9SArtem B. Bityutskiy static void jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *,
24733802d9SArtem B. Bityutskiy 		struct jffs2_inode_cache *, struct jffs2_full_dirent **);
251da177e4SLinus Torvalds 
261da177e4SLinus Torvalds static inline struct jffs2_inode_cache *
first_inode_chain(int * i,struct jffs2_sb_info * c)271da177e4SLinus Torvalds first_inode_chain(int *i, struct jffs2_sb_info *c)
281da177e4SLinus Torvalds {
2965e5a0e1SDaniel Drake 	for (; *i < c->inocache_hashsize; (*i)++) {
301da177e4SLinus Torvalds 		if (c->inocache_list[*i])
311da177e4SLinus Torvalds 			return c->inocache_list[*i];
321da177e4SLinus Torvalds 	}
331da177e4SLinus Torvalds 	return NULL;
341da177e4SLinus Torvalds }
351da177e4SLinus Torvalds 
361da177e4SLinus Torvalds static inline struct jffs2_inode_cache *
next_inode(int * i,struct jffs2_inode_cache * ic,struct jffs2_sb_info * c)371da177e4SLinus Torvalds next_inode(int *i, struct jffs2_inode_cache *ic, struct jffs2_sb_info *c)
381da177e4SLinus Torvalds {
391da177e4SLinus Torvalds 	/* More in this chain? */
401da177e4SLinus Torvalds 	if (ic->next)
411da177e4SLinus Torvalds 		return ic->next;
421da177e4SLinus Torvalds 	(*i)++;
431da177e4SLinus Torvalds 	return first_inode_chain(i, c);
441da177e4SLinus Torvalds }
451da177e4SLinus Torvalds 
461da177e4SLinus Torvalds #define for_each_inode(i, c, ic)			\
471da177e4SLinus Torvalds 	for (i = 0, ic = first_inode_chain(&i, (c));	\
481da177e4SLinus Torvalds 	     ic;					\
491da177e4SLinus Torvalds 	     ic = next_inode(&i, ic, (c)))
501da177e4SLinus Torvalds 
511da177e4SLinus Torvalds 
jffs2_build_inode_pass1(struct jffs2_sb_info * c,struct jffs2_inode_cache * ic,int * dir_hardlinks)52858119e1SArjan van de Ven static void jffs2_build_inode_pass1(struct jffs2_sb_info *c,
53be629c62SDavid Woodhouse 				    struct jffs2_inode_cache *ic,
54be629c62SDavid Woodhouse 				    int *dir_hardlinks)
551da177e4SLinus Torvalds {
561da177e4SLinus Torvalds 	struct jffs2_full_dirent *fd;
571da177e4SLinus Torvalds 
58733802d9SArtem B. Bityutskiy 	dbg_fsbuild("building directory inode #%u\n", ic->ino);
591da177e4SLinus Torvalds 
601da177e4SLinus Torvalds 	/* For each child, increase nlink */
611da177e4SLinus Torvalds 	for(fd = ic->scan_dents; fd; fd = fd->next) {
621da177e4SLinus Torvalds 		struct jffs2_inode_cache *child_ic;
631da177e4SLinus Torvalds 		if (!fd->ino)
641da177e4SLinus Torvalds 			continue;
651da177e4SLinus Torvalds 
66733802d9SArtem B. Bityutskiy 		/* we can get high latency here with huge directories */
671da177e4SLinus Torvalds 
681da177e4SLinus Torvalds 		child_ic = jffs2_get_ino_cache(c, fd->ino);
691da177e4SLinus Torvalds 		if (!child_ic) {
70733802d9SArtem B. Bityutskiy 			dbg_fsbuild("child \"%s\" (ino #%u) of dir ino #%u doesn't exist!\n",
711da177e4SLinus Torvalds 				  fd->name, fd->ino, ic->ino);
721da177e4SLinus Torvalds 			jffs2_mark_node_obsolete(c, fd->raw);
73be629c62SDavid Woodhouse 			/* Clear the ic/raw union so it doesn't cause problems later. */
74be629c62SDavid Woodhouse 			fd->ic = NULL;
751da177e4SLinus Torvalds 			continue;
761da177e4SLinus Torvalds 		}
771da177e4SLinus Torvalds 
78be629c62SDavid Woodhouse 		/* From this point, fd->raw is no longer used so we can set fd->ic */
79be629c62SDavid Woodhouse 		fd->ic = child_ic;
8027c72b04SDavid Woodhouse 		child_ic->pino_nlink++;
81be629c62SDavid Woodhouse 		/* If we appear (at this stage) to have hard-linked directories,
82be629c62SDavid Woodhouse 		 * set a flag to trigger a scan later */
83be629c62SDavid Woodhouse 		if (fd->type == DT_DIR) {
84be629c62SDavid Woodhouse 			child_ic->flags |= INO_FLAGS_IS_DIR;
85be629c62SDavid Woodhouse 			if (child_ic->pino_nlink > 1)
86be629c62SDavid Woodhouse 				*dir_hardlinks = 1;
87be629c62SDavid Woodhouse 		}
8827c72b04SDavid Woodhouse 
89733802d9SArtem B. Bityutskiy 		dbg_fsbuild("increased nlink for child \"%s\" (ino #%u)\n", fd->name, fd->ino);
90733802d9SArtem B. Bityutskiy 		/* Can't free scan_dents so far. We might need them in pass 2 */
911da177e4SLinus Torvalds 	}
921da177e4SLinus Torvalds }
931da177e4SLinus Torvalds 
941da177e4SLinus Torvalds /* Scan plan:
951da177e4SLinus Torvalds  - Scan physical nodes. Build map of inodes/dirents. Allocate inocaches as we go
961da177e4SLinus Torvalds  - Scan directory tree from top down, setting nlink in inocaches
971da177e4SLinus Torvalds  - Scan inocaches for inodes with nlink==0
981da177e4SLinus Torvalds */
jffs2_build_filesystem(struct jffs2_sb_info * c)991da177e4SLinus Torvalds static int jffs2_build_filesystem(struct jffs2_sb_info *c)
1001da177e4SLinus Torvalds {
101be629c62SDavid Woodhouse 	int ret, i, dir_hardlinks = 0;
1021da177e4SLinus Torvalds 	struct jffs2_inode_cache *ic;
1031da177e4SLinus Torvalds 	struct jffs2_full_dirent *fd;
1041da177e4SLinus Torvalds 	struct jffs2_full_dirent *dead_fds = NULL;
1051da177e4SLinus Torvalds 
106733802d9SArtem B. Bityutskiy 	dbg_fsbuild("build FS data structures\n");
107733802d9SArtem B. Bityutskiy 
1081da177e4SLinus Torvalds 	/* First, scan the medium and build all the inode caches with
1091da177e4SLinus Torvalds 	   lists of physical nodes */
1101da177e4SLinus Torvalds 
11131fbdf7aSArtem B. Bityuckiy 	c->flags |= JFFS2_SB_FLAG_SCANNING;
1121da177e4SLinus Torvalds 	ret = jffs2_scan_medium(c);
11331fbdf7aSArtem B. Bityuckiy 	c->flags &= ~JFFS2_SB_FLAG_SCANNING;
1141da177e4SLinus Torvalds 	if (ret)
1151da177e4SLinus Torvalds 		goto exit;
1161da177e4SLinus Torvalds 
117733802d9SArtem B. Bityutskiy 	dbg_fsbuild("scanned flash completely\n");
118e0c8e42fSArtem B. Bityutskiy 	jffs2_dbg_dump_block_lists_nolock(c);
1191da177e4SLinus Torvalds 
120733802d9SArtem B. Bityutskiy 	dbg_fsbuild("pass 1 starting\n");
12131fbdf7aSArtem B. Bityuckiy 	c->flags |= JFFS2_SB_FLAG_BUILDING;
1221da177e4SLinus Torvalds 	/* Now scan the directory tree, increasing nlink according to every dirent found. */
1231da177e4SLinus Torvalds 	for_each_inode(i, c, ic) {
1241da177e4SLinus Torvalds 		if (ic->scan_dents) {
125be629c62SDavid Woodhouse 			jffs2_build_inode_pass1(c, ic, &dir_hardlinks);
1261da177e4SLinus Torvalds 			cond_resched();
1271da177e4SLinus Torvalds 		}
1281da177e4SLinus Torvalds 	}
1291da177e4SLinus Torvalds 
130733802d9SArtem B. Bityutskiy 	dbg_fsbuild("pass 1 complete\n");
1311da177e4SLinus Torvalds 
1321da177e4SLinus Torvalds 	/* Next, scan for inodes with nlink == 0 and remove them. If
1331da177e4SLinus Torvalds 	   they were directories, then decrement the nlink of their
1341da177e4SLinus Torvalds 	   children too, and repeat the scan. As that's going to be
1351da177e4SLinus Torvalds 	   a fairly uncommon occurrence, it's not so evil to do it this
1361da177e4SLinus Torvalds 	   way. Recursion bad. */
137733802d9SArtem B. Bityutskiy 	dbg_fsbuild("pass 2 starting\n");
1381da177e4SLinus Torvalds 
1391da177e4SLinus Torvalds 	for_each_inode(i, c, ic) {
14027c72b04SDavid Woodhouse 		if (ic->pino_nlink)
1411da177e4SLinus Torvalds 			continue;
1421da177e4SLinus Torvalds 
1431da177e4SLinus Torvalds 		jffs2_build_remove_unlinked_inode(c, ic, &dead_fds);
1441da177e4SLinus Torvalds 		cond_resched();
1451da177e4SLinus Torvalds 	}
1461da177e4SLinus Torvalds 
147733802d9SArtem B. Bityutskiy 	dbg_fsbuild("pass 2a starting\n");
1481da177e4SLinus Torvalds 
1491da177e4SLinus Torvalds 	while (dead_fds) {
1501da177e4SLinus Torvalds 		fd = dead_fds;
1511da177e4SLinus Torvalds 		dead_fds = fd->next;
1521da177e4SLinus Torvalds 
1531da177e4SLinus Torvalds 		ic = jffs2_get_ino_cache(c, fd->ino);
1541da177e4SLinus Torvalds 
1551da177e4SLinus Torvalds 		if (ic)
1561da177e4SLinus Torvalds 			jffs2_build_remove_unlinked_inode(c, ic, &dead_fds);
1571da177e4SLinus Torvalds 		jffs2_free_full_dirent(fd);
1581da177e4SLinus Torvalds 	}
1591da177e4SLinus Torvalds 
160733802d9SArtem B. Bityutskiy 	dbg_fsbuild("pass 2a complete\n");
161be629c62SDavid Woodhouse 
162be629c62SDavid Woodhouse 	if (dir_hardlinks) {
163be629c62SDavid Woodhouse 		/* If we detected directory hardlinks earlier, *hopefully*
164be629c62SDavid Woodhouse 		 * they are gone now because some of the links were from
165be629c62SDavid Woodhouse 		 * dead directories which still had some old dirents lying
166be629c62SDavid Woodhouse 		 * around and not yet garbage-collected, but which have
167be629c62SDavid Woodhouse 		 * been discarded above. So clear the pino_nlink field
168be629c62SDavid Woodhouse 		 * in each directory, so that the final scan below can
169be629c62SDavid Woodhouse 		 * print appropriate warnings. */
170be629c62SDavid Woodhouse 		for_each_inode(i, c, ic) {
171be629c62SDavid Woodhouse 			if (ic->flags & INO_FLAGS_IS_DIR)
172be629c62SDavid Woodhouse 				ic->pino_nlink = 0;
173be629c62SDavid Woodhouse 		}
174be629c62SDavid Woodhouse 	}
175733802d9SArtem B. Bityutskiy 	dbg_fsbuild("freeing temporary data structures\n");
1761da177e4SLinus Torvalds 
1771da177e4SLinus Torvalds 	/* Finally, we can scan again and free the dirent structs */
1781da177e4SLinus Torvalds 	for_each_inode(i, c, ic) {
1791da177e4SLinus Torvalds 		while(ic->scan_dents) {
1801da177e4SLinus Torvalds 			fd = ic->scan_dents;
1811da177e4SLinus Torvalds 			ic->scan_dents = fd->next;
182be629c62SDavid Woodhouse 			/* We do use the pino_nlink field to count nlink of
183be629c62SDavid Woodhouse 			 * directories during fs build, so set it to the
184be629c62SDavid Woodhouse 			 * parent ino# now. Now that there's hopefully only
185be629c62SDavid Woodhouse 			 * one. */
186be629c62SDavid Woodhouse 			if (fd->type == DT_DIR) {
187be629c62SDavid Woodhouse 				if (!fd->ic) {
188be629c62SDavid Woodhouse 					/* We'll have complained about it and marked the coresponding
189be629c62SDavid Woodhouse 					   raw node obsolete already. Just skip it. */
190be629c62SDavid Woodhouse 					continue;
191be629c62SDavid Woodhouse 				}
192be629c62SDavid Woodhouse 
193be629c62SDavid Woodhouse 				/* We *have* to have set this in jffs2_build_inode_pass1() */
194be629c62SDavid Woodhouse 				BUG_ON(!(fd->ic->flags & INO_FLAGS_IS_DIR));
195be629c62SDavid Woodhouse 
196be629c62SDavid Woodhouse 				/* We clear ic->pino_nlink ∀ directories' ic *only* if dir_hardlinks
197be629c62SDavid Woodhouse 				 * is set. Otherwise, we know this should never trigger anyway, so
198be629c62SDavid Woodhouse 				 * we don't do the check. And ic->pino_nlink still contains the nlink
199be629c62SDavid Woodhouse 				 * value (which is 1). */
200be629c62SDavid Woodhouse 				if (dir_hardlinks && fd->ic->pino_nlink) {
201be629c62SDavid Woodhouse 					JFFS2_ERROR("child dir \"%s\" (ino #%u) of dir ino #%u is also hard linked from dir ino #%u\n",
202be629c62SDavid Woodhouse 						    fd->name, fd->ino, ic->ino, fd->ic->pino_nlink);
203be629c62SDavid Woodhouse 					/* Should we unlink it from its previous parent? */
204be629c62SDavid Woodhouse 				}
205be629c62SDavid Woodhouse 
206be629c62SDavid Woodhouse 				/* For directories, ic->pino_nlink holds that parent inode # */
207be629c62SDavid Woodhouse 				fd->ic->pino_nlink = ic->ino;
208be629c62SDavid Woodhouse 			}
2091da177e4SLinus Torvalds 			jffs2_free_full_dirent(fd);
2101da177e4SLinus Torvalds 		}
2111da177e4SLinus Torvalds 		ic->scan_dents = NULL;
2121da177e4SLinus Torvalds 		cond_resched();
2131da177e4SLinus Torvalds 	}
214*1168f095SFabian Frederick 	ret = jffs2_build_xattr_subsystem(c);
215*1168f095SFabian Frederick 	if (ret)
216*1168f095SFabian Frederick 		goto exit;
217*1168f095SFabian Frederick 
21831fbdf7aSArtem B. Bityuckiy 	c->flags &= ~JFFS2_SB_FLAG_BUILDING;
21931fbdf7aSArtem B. Bityuckiy 
220733802d9SArtem B. Bityutskiy 	dbg_fsbuild("FS build complete\n");
2211da177e4SLinus Torvalds 
2221da177e4SLinus Torvalds 	/* Rotate the lists by some number to ensure wear levelling */
2231da177e4SLinus Torvalds 	jffs2_rotate_lists(c);
2241da177e4SLinus Torvalds 
2251da177e4SLinus Torvalds 	ret = 0;
2261da177e4SLinus Torvalds 
2271da177e4SLinus Torvalds exit:
2281da177e4SLinus Torvalds 	if (ret) {
2291da177e4SLinus Torvalds 		for_each_inode(i, c, ic) {
2301da177e4SLinus Torvalds 			while(ic->scan_dents) {
2311da177e4SLinus Torvalds 				fd = ic->scan_dents;
2321da177e4SLinus Torvalds 				ic->scan_dents = fd->next;
2331da177e4SLinus Torvalds 				jffs2_free_full_dirent(fd);
2341da177e4SLinus Torvalds 			}
2351da177e4SLinus Torvalds 		}
236aa98d7cfSKaiGai Kohei 		jffs2_clear_xattr_subsystem(c);
2371da177e4SLinus Torvalds 	}
2381da177e4SLinus Torvalds 
2391da177e4SLinus Torvalds 	return ret;
2401da177e4SLinus Torvalds }
2411da177e4SLinus Torvalds 
jffs2_build_remove_unlinked_inode(struct jffs2_sb_info * c,struct jffs2_inode_cache * ic,struct jffs2_full_dirent ** dead_fds)242733802d9SArtem B. Bityutskiy static void jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *c,
243733802d9SArtem B. Bityutskiy 					struct jffs2_inode_cache *ic,
244733802d9SArtem B. Bityutskiy 					struct jffs2_full_dirent **dead_fds)
2451da177e4SLinus Torvalds {
2461da177e4SLinus Torvalds 	struct jffs2_raw_node_ref *raw;
2471da177e4SLinus Torvalds 	struct jffs2_full_dirent *fd;
2481da177e4SLinus Torvalds 
249733802d9SArtem B. Bityutskiy 	dbg_fsbuild("removing ino #%u with nlink == zero.\n", ic->ino);
2501da177e4SLinus Torvalds 
2511da177e4SLinus Torvalds 	raw = ic->nodes;
2521da177e4SLinus Torvalds 	while (raw != (void *)ic) {
2531da177e4SLinus Torvalds 		struct jffs2_raw_node_ref *next = raw->next_in_ino;
254733802d9SArtem B. Bityutskiy 		dbg_fsbuild("obsoleting node at 0x%08x\n", ref_offset(raw));
2551da177e4SLinus Torvalds 		jffs2_mark_node_obsolete(c, raw);
2561da177e4SLinus Torvalds 		raw = next;
2571da177e4SLinus Torvalds 	}
2581da177e4SLinus Torvalds 
2591da177e4SLinus Torvalds 	if (ic->scan_dents) {
2601da177e4SLinus Torvalds 		int whinged = 0;
261733802d9SArtem B. Bityutskiy 		dbg_fsbuild("inode #%u was a directory which may have children...\n", ic->ino);
2621da177e4SLinus Torvalds 
2631da177e4SLinus Torvalds 		while(ic->scan_dents) {
2641da177e4SLinus Torvalds 			struct jffs2_inode_cache *child_ic;
2651da177e4SLinus Torvalds 
2661da177e4SLinus Torvalds 			fd = ic->scan_dents;
2671da177e4SLinus Torvalds 			ic->scan_dents = fd->next;
2681da177e4SLinus Torvalds 
2691da177e4SLinus Torvalds 			if (!fd->ino) {
2701da177e4SLinus Torvalds 				/* It's a deletion dirent. Ignore it */
271733802d9SArtem B. Bityutskiy 				dbg_fsbuild("child \"%s\" is a deletion dirent, skipping...\n", fd->name);
2721da177e4SLinus Torvalds 				jffs2_free_full_dirent(fd);
2731da177e4SLinus Torvalds 				continue;
2741da177e4SLinus Torvalds 			}
275733802d9SArtem B. Bityutskiy 			if (!whinged)
2761da177e4SLinus Torvalds 				whinged = 1;
2771da177e4SLinus Torvalds 
278733802d9SArtem B. Bityutskiy 			dbg_fsbuild("removing child \"%s\", ino #%u\n", fd->name, fd->ino);
2791da177e4SLinus Torvalds 
2801da177e4SLinus Torvalds 			child_ic = jffs2_get_ino_cache(c, fd->ino);
2811da177e4SLinus Torvalds 			if (!child_ic) {
282733802d9SArtem B. Bityutskiy 				dbg_fsbuild("cannot remove child \"%s\", ino #%u, because it doesn't exist\n",
283733802d9SArtem B. Bityutskiy 						fd->name, fd->ino);
2841da177e4SLinus Torvalds 				jffs2_free_full_dirent(fd);
2851da177e4SLinus Torvalds 				continue;
2861da177e4SLinus Torvalds 			}
2871da177e4SLinus Torvalds 
2881da177e4SLinus Torvalds 			/* Reduce nlink of the child. If it's now zero, stick it on the
2891da177e4SLinus Torvalds 			   dead_fds list to be cleaned up later. Else just free the fd */
29027c72b04SDavid Woodhouse 			child_ic->pino_nlink--;
2911da177e4SLinus Torvalds 
29227c72b04SDavid Woodhouse 			if (!child_ic->pino_nlink) {
29327c72b04SDavid Woodhouse 				dbg_fsbuild("inode #%u (\"%s\") now has no links; adding to dead_fds list.\n",
294733802d9SArtem B. Bityutskiy 					  fd->ino, fd->name);
2951da177e4SLinus Torvalds 				fd->next = *dead_fds;
2961da177e4SLinus Torvalds 				*dead_fds = fd;
2971da177e4SLinus Torvalds 			} else {
298733802d9SArtem B. Bityutskiy 				dbg_fsbuild("inode #%u (\"%s\") has now got nlink %d. Ignoring.\n",
29927c72b04SDavid Woodhouse 					  fd->ino, fd->name, child_ic->pino_nlink);
3001da177e4SLinus Torvalds 				jffs2_free_full_dirent(fd);
3011da177e4SLinus Torvalds 			}
3021da177e4SLinus Torvalds 		}
3031da177e4SLinus Torvalds 	}
3041da177e4SLinus Torvalds 
3051da177e4SLinus Torvalds 	/*
3061da177e4SLinus Torvalds 	   We don't delete the inocache from the hash list and free it yet.
3071da177e4SLinus Torvalds 	   The erase code will do that, when all the nodes are completely gone.
3081da177e4SLinus Torvalds 	*/
3091da177e4SLinus Torvalds }
3101da177e4SLinus Torvalds 
jffs2_calc_trigger_levels(struct jffs2_sb_info * c)3111da177e4SLinus Torvalds static void jffs2_calc_trigger_levels(struct jffs2_sb_info *c)
3121da177e4SLinus Torvalds {
3131da177e4SLinus Torvalds 	uint32_t size;
3141da177e4SLinus Torvalds 
3151da177e4SLinus Torvalds 	/* Deletion should almost _always_ be allowed. We're fairly
3161da177e4SLinus Torvalds 	   buggered once we stop allowing people to delete stuff
3171da177e4SLinus Torvalds 	   because there's not enough free space... */
3181da177e4SLinus Torvalds 	c->resv_blocks_deletion = 2;
3191da177e4SLinus Torvalds 
3201da177e4SLinus Torvalds 	/* Be conservative about how much space we need before we allow writes.
3211da177e4SLinus Torvalds 	   On top of that which is required for deletia, require an extra 2%
3221da177e4SLinus Torvalds 	   of the medium to be available, for overhead caused by nodes being
3231da177e4SLinus Torvalds 	   split across blocks, etc. */
3241da177e4SLinus Torvalds 
3251da177e4SLinus Torvalds 	size = c->flash_size / 50; /* 2% of flash size */
3261da177e4SLinus Torvalds 	size += c->nr_blocks * 100; /* And 100 bytes per eraseblock */
3271da177e4SLinus Torvalds 	size += c->sector_size - 1; /* ... and round up */
3281da177e4SLinus Torvalds 
3291da177e4SLinus Torvalds 	c->resv_blocks_write = c->resv_blocks_deletion + (size / c->sector_size);
3301da177e4SLinus Torvalds 
3311da177e4SLinus Torvalds 	/* When do we let the GC thread run in the background */
3321da177e4SLinus Torvalds 
3331da177e4SLinus Torvalds 	c->resv_blocks_gctrigger = c->resv_blocks_write + 1;
3341da177e4SLinus Torvalds 
3351da177e4SLinus Torvalds 	/* When do we allow garbage collection to merge nodes to make
3361da177e4SLinus Torvalds 	   long-term progress at the expense of short-term space exhaustion? */
3371da177e4SLinus Torvalds 	c->resv_blocks_gcmerge = c->resv_blocks_deletion + 1;
3381da177e4SLinus Torvalds 
3391da177e4SLinus Torvalds 	/* When do we allow garbage collection to eat from bad blocks rather
3401da177e4SLinus Torvalds 	   than actually making progress? */
3411da177e4SLinus Torvalds 	c->resv_blocks_gcbad = 0;//c->resv_blocks_deletion + 2;
3421da177e4SLinus Torvalds 
3438fb870dfSDavid Woodhouse 	/* What number of 'very dirty' eraseblocks do we allow before we
3448fb870dfSDavid Woodhouse 	   trigger the GC thread even if we don't _need_ the space. When we
3458fb870dfSDavid Woodhouse 	   can't mark nodes obsolete on the medium, the old dirty nodes cause
3468fb870dfSDavid Woodhouse 	   performance problems because we have to inspect and discard them. */
34785becc53SDavid Woodhouse 	c->vdirty_blocks_gctrigger = c->resv_blocks_gctrigger;
3488fb870dfSDavid Woodhouse 	if (jffs2_can_mark_obsolete(c))
3498fb870dfSDavid Woodhouse 		c->vdirty_blocks_gctrigger *= 10;
3508fb870dfSDavid Woodhouse 
3511da177e4SLinus Torvalds 	/* If there's less than this amount of dirty space, don't bother
3521da177e4SLinus Torvalds 	   trying to GC to make more space. It'll be a fruitless task */
3531da177e4SLinus Torvalds 	c->nospc_dirty_size = c->sector_size + (c->flash_size / 100);
3541da177e4SLinus Torvalds 
3555a528957SJoe Perches 	dbg_fsbuild("trigger levels (size %d KiB, block size %d KiB, %d blocks)\n",
356733802d9SArtem B. Bityutskiy 		    c->flash_size / 1024, c->sector_size / 1024, c->nr_blocks);
357733802d9SArtem B. Bityutskiy 	dbg_fsbuild("Blocks required to allow deletion:    %d (%d KiB)\n",
358733802d9SArtem B. Bityutskiy 		  c->resv_blocks_deletion, c->resv_blocks_deletion*c->sector_size/1024);
359733802d9SArtem B. Bityutskiy 	dbg_fsbuild("Blocks required to allow writes:      %d (%d KiB)\n",
360733802d9SArtem B. Bityutskiy 		  c->resv_blocks_write, c->resv_blocks_write*c->sector_size/1024);
361733802d9SArtem B. Bityutskiy 	dbg_fsbuild("Blocks required to quiesce GC thread: %d (%d KiB)\n",
362733802d9SArtem B. Bityutskiy 		  c->resv_blocks_gctrigger, c->resv_blocks_gctrigger*c->sector_size/1024);
363733802d9SArtem B. Bityutskiy 	dbg_fsbuild("Blocks required to allow GC merges:   %d (%d KiB)\n",
364733802d9SArtem B. Bityutskiy 		  c->resv_blocks_gcmerge, c->resv_blocks_gcmerge*c->sector_size/1024);
365733802d9SArtem B. Bityutskiy 	dbg_fsbuild("Blocks required to GC bad blocks:     %d (%d KiB)\n",
366733802d9SArtem B. Bityutskiy 		  c->resv_blocks_gcbad, c->resv_blocks_gcbad*c->sector_size/1024);
367733802d9SArtem B. Bityutskiy 	dbg_fsbuild("Amount of dirty space required to GC: %d bytes\n",
368733802d9SArtem B. Bityutskiy 		  c->nospc_dirty_size);
3698fb870dfSDavid Woodhouse 	dbg_fsbuild("Very dirty blocks before GC triggered: %d\n",
3708fb870dfSDavid Woodhouse 		  c->vdirty_blocks_gctrigger);
3711da177e4SLinus Torvalds }
3721da177e4SLinus Torvalds 
jffs2_do_mount_fs(struct jffs2_sb_info * c)3731da177e4SLinus Torvalds int jffs2_do_mount_fs(struct jffs2_sb_info *c)
3741da177e4SLinus Torvalds {
375c617e842SFerenc Havasi 	int ret;
3761da177e4SLinus Torvalds 	int i;
377d55849aaSArtem B. Bityutskiy 	int size;
3781da177e4SLinus Torvalds 
3791da177e4SLinus Torvalds 	c->free_size = c->flash_size;
3801da177e4SLinus Torvalds 	c->nr_blocks = c->flash_size / c->sector_size;
381d55849aaSArtem B. Bityutskiy 	size = sizeof(struct jffs2_eraseblock) * c->nr_blocks;
382737b7661SAndrew Lunn #ifndef __ECOS
3834ce1f562SFerenc Havasi 	if (jffs2_blocks_use_vmalloc(c))
3847ddbead6SJoe Perches 		c->blocks = vzalloc(size);
3851da177e4SLinus Torvalds 	else
386737b7661SAndrew Lunn #endif
3877ddbead6SJoe Perches 		c->blocks = kzalloc(size, GFP_KERNEL);
3881da177e4SLinus Torvalds 	if (!c->blocks)
3891da177e4SLinus Torvalds 		return -ENOMEM;
390d55849aaSArtem B. Bityutskiy 
3911da177e4SLinus Torvalds 	for (i=0; i<c->nr_blocks; i++) {
3921da177e4SLinus Torvalds 		INIT_LIST_HEAD(&c->blocks[i].list);
3931da177e4SLinus Torvalds 		c->blocks[i].offset = i * c->sector_size;
3941da177e4SLinus Torvalds 		c->blocks[i].free_size = c->sector_size;
3951da177e4SLinus Torvalds 	}
3961da177e4SLinus Torvalds 
3971da177e4SLinus Torvalds 	INIT_LIST_HEAD(&c->clean_list);
3981da177e4SLinus Torvalds 	INIT_LIST_HEAD(&c->very_dirty_list);
3991da177e4SLinus Torvalds 	INIT_LIST_HEAD(&c->dirty_list);
4001da177e4SLinus Torvalds 	INIT_LIST_HEAD(&c->erasable_list);
4011da177e4SLinus Torvalds 	INIT_LIST_HEAD(&c->erasing_list);
402e2bc322bSDavid Woodhouse 	INIT_LIST_HEAD(&c->erase_checking_list);
4031da177e4SLinus Torvalds 	INIT_LIST_HEAD(&c->erase_pending_list);
4041da177e4SLinus Torvalds 	INIT_LIST_HEAD(&c->erasable_pending_wbuf_list);
4051da177e4SLinus Torvalds 	INIT_LIST_HEAD(&c->erase_complete_list);
4061da177e4SLinus Torvalds 	INIT_LIST_HEAD(&c->free_list);
4071da177e4SLinus Torvalds 	INIT_LIST_HEAD(&c->bad_list);
4081da177e4SLinus Torvalds 	INIT_LIST_HEAD(&c->bad_used_list);
4091da177e4SLinus Torvalds 	c->highest_ino = 1;
410e631ddbaSFerenc Havasi 	c->summary = NULL;
411e631ddbaSFerenc Havasi 
412c617e842SFerenc Havasi 	ret = jffs2_sum_init(c);
413c617e842SFerenc Havasi 	if (ret)
414cfa72397SDmitry Adamushko 		goto out_free;
4151da177e4SLinus Torvalds 
4161da177e4SLinus Torvalds 	if (jffs2_build_filesystem(c)) {
417733802d9SArtem B. Bityutskiy 		dbg_fsbuild("build_fs failed\n");
4181da177e4SLinus Torvalds 		jffs2_free_ino_caches(c);
4191da177e4SLinus Torvalds 		jffs2_free_raw_node_refs(c);
420cfa72397SDmitry Adamushko 		ret = -EIO;
421d051cef7SBaokun Li 		goto out_sum_exit;
422cfa72397SDmitry Adamushko 	}
423cfa72397SDmitry Adamushko 
424cfa72397SDmitry Adamushko 	jffs2_calc_trigger_levels(c);
425cfa72397SDmitry Adamushko 
426cfa72397SDmitry Adamushko 	return 0;
427cfa72397SDmitry Adamushko 
428d051cef7SBaokun Li  out_sum_exit:
429d051cef7SBaokun Li 	jffs2_sum_exit(c);
430cfa72397SDmitry Adamushko  out_free:
4311d5cfdb0STetsuo Handa 	kvfree(c->blocks);
432737b7661SAndrew Lunn 
433cfa72397SDmitry Adamushko 	return ret;
4341da177e4SLinus Torvalds }
435