18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * JFFS2 -- Journalling Flash File System, Version 2.
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Copyright © 2001-2007 Red Hat, Inc.
58c2ecf20Sopenharmony_ci * Copyright © 2004-2010 David Woodhouse <dwmw2@infradead.org>
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Created by David Woodhouse <dwmw2@infradead.org>
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * For licensing information, see the file 'LICENCE' in this directory.
108c2ecf20Sopenharmony_ci *
118c2ecf20Sopenharmony_ci */
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#include <linux/kernel.h>
168c2ecf20Sopenharmony_ci#include <linux/sched.h>
178c2ecf20Sopenharmony_ci#include <linux/slab.h>
188c2ecf20Sopenharmony_ci#include <linux/vmalloc.h>
198c2ecf20Sopenharmony_ci#include <linux/mtd/mtd.h>
208c2ecf20Sopenharmony_ci#include <linux/mm.h> /* kvfree() */
218c2ecf20Sopenharmony_ci#include "nodelist.h"
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_cistatic void jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *,
248c2ecf20Sopenharmony_ci		struct jffs2_inode_cache *, struct jffs2_full_dirent **);
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_cistatic inline struct jffs2_inode_cache *
278c2ecf20Sopenharmony_cifirst_inode_chain(int *i, struct jffs2_sb_info *c)
288c2ecf20Sopenharmony_ci{
298c2ecf20Sopenharmony_ci	for (; *i < c->inocache_hashsize; (*i)++) {
308c2ecf20Sopenharmony_ci		if (c->inocache_list[*i])
318c2ecf20Sopenharmony_ci			return c->inocache_list[*i];
328c2ecf20Sopenharmony_ci	}
338c2ecf20Sopenharmony_ci	return NULL;
348c2ecf20Sopenharmony_ci}
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_cistatic inline struct jffs2_inode_cache *
378c2ecf20Sopenharmony_cinext_inode(int *i, struct jffs2_inode_cache *ic, struct jffs2_sb_info *c)
388c2ecf20Sopenharmony_ci{
398c2ecf20Sopenharmony_ci	/* More in this chain? */
408c2ecf20Sopenharmony_ci	if (ic->next)
418c2ecf20Sopenharmony_ci		return ic->next;
428c2ecf20Sopenharmony_ci	(*i)++;
438c2ecf20Sopenharmony_ci	return first_inode_chain(i, c);
448c2ecf20Sopenharmony_ci}
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci#define for_each_inode(i, c, ic)			\
478c2ecf20Sopenharmony_ci	for (i = 0, ic = first_inode_chain(&i, (c));	\
488c2ecf20Sopenharmony_ci	     ic;					\
498c2ecf20Sopenharmony_ci	     ic = next_inode(&i, ic, (c)))
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_cistatic void jffs2_build_inode_pass1(struct jffs2_sb_info *c,
538c2ecf20Sopenharmony_ci				    struct jffs2_inode_cache *ic,
548c2ecf20Sopenharmony_ci				    int *dir_hardlinks)
558c2ecf20Sopenharmony_ci{
568c2ecf20Sopenharmony_ci	struct jffs2_full_dirent *fd;
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	dbg_fsbuild("building directory inode #%u\n", ic->ino);
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	/* For each child, increase nlink */
618c2ecf20Sopenharmony_ci	for(fd = ic->scan_dents; fd; fd = fd->next) {
628c2ecf20Sopenharmony_ci		struct jffs2_inode_cache *child_ic;
638c2ecf20Sopenharmony_ci		if (!fd->ino)
648c2ecf20Sopenharmony_ci			continue;
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci		/* we can get high latency here with huge directories */
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci		child_ic = jffs2_get_ino_cache(c, fd->ino);
698c2ecf20Sopenharmony_ci		if (!child_ic) {
708c2ecf20Sopenharmony_ci			dbg_fsbuild("child \"%s\" (ino #%u) of dir ino #%u doesn't exist!\n",
718c2ecf20Sopenharmony_ci				  fd->name, fd->ino, ic->ino);
728c2ecf20Sopenharmony_ci			jffs2_mark_node_obsolete(c, fd->raw);
738c2ecf20Sopenharmony_ci			/* Clear the ic/raw union so it doesn't cause problems later. */
748c2ecf20Sopenharmony_ci			fd->ic = NULL;
758c2ecf20Sopenharmony_ci			continue;
768c2ecf20Sopenharmony_ci		}
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci		/* From this point, fd->raw is no longer used so we can set fd->ic */
798c2ecf20Sopenharmony_ci		fd->ic = child_ic;
808c2ecf20Sopenharmony_ci		child_ic->pino_nlink++;
818c2ecf20Sopenharmony_ci		/* If we appear (at this stage) to have hard-linked directories,
828c2ecf20Sopenharmony_ci		 * set a flag to trigger a scan later */
838c2ecf20Sopenharmony_ci		if (fd->type == DT_DIR) {
848c2ecf20Sopenharmony_ci			child_ic->flags |= INO_FLAGS_IS_DIR;
858c2ecf20Sopenharmony_ci			if (child_ic->pino_nlink > 1)
868c2ecf20Sopenharmony_ci				*dir_hardlinks = 1;
878c2ecf20Sopenharmony_ci		}
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci		dbg_fsbuild("increased nlink for child \"%s\" (ino #%u)\n", fd->name, fd->ino);
908c2ecf20Sopenharmony_ci		/* Can't free scan_dents so far. We might need them in pass 2 */
918c2ecf20Sopenharmony_ci	}
928c2ecf20Sopenharmony_ci}
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci/* Scan plan:
958c2ecf20Sopenharmony_ci - Scan physical nodes. Build map of inodes/dirents. Allocate inocaches as we go
968c2ecf20Sopenharmony_ci - Scan directory tree from top down, setting nlink in inocaches
978c2ecf20Sopenharmony_ci - Scan inocaches for inodes with nlink==0
988c2ecf20Sopenharmony_ci*/
998c2ecf20Sopenharmony_cistatic int jffs2_build_filesystem(struct jffs2_sb_info *c)
1008c2ecf20Sopenharmony_ci{
1018c2ecf20Sopenharmony_ci	int ret, i, dir_hardlinks = 0;
1028c2ecf20Sopenharmony_ci	struct jffs2_inode_cache *ic;
1038c2ecf20Sopenharmony_ci	struct jffs2_full_dirent *fd;
1048c2ecf20Sopenharmony_ci	struct jffs2_full_dirent *dead_fds = NULL;
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	dbg_fsbuild("build FS data structures\n");
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	/* First, scan the medium and build all the inode caches with
1098c2ecf20Sopenharmony_ci	   lists of physical nodes */
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	c->flags |= JFFS2_SB_FLAG_SCANNING;
1128c2ecf20Sopenharmony_ci	ret = jffs2_scan_medium(c);
1138c2ecf20Sopenharmony_ci	c->flags &= ~JFFS2_SB_FLAG_SCANNING;
1148c2ecf20Sopenharmony_ci	if (ret)
1158c2ecf20Sopenharmony_ci		goto exit;
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	dbg_fsbuild("scanned flash completely\n");
1188c2ecf20Sopenharmony_ci	jffs2_dbg_dump_block_lists_nolock(c);
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	dbg_fsbuild("pass 1 starting\n");
1218c2ecf20Sopenharmony_ci	c->flags |= JFFS2_SB_FLAG_BUILDING;
1228c2ecf20Sopenharmony_ci	/* Now scan the directory tree, increasing nlink according to every dirent found. */
1238c2ecf20Sopenharmony_ci	for_each_inode(i, c, ic) {
1248c2ecf20Sopenharmony_ci		if (ic->scan_dents) {
1258c2ecf20Sopenharmony_ci			jffs2_build_inode_pass1(c, ic, &dir_hardlinks);
1268c2ecf20Sopenharmony_ci			cond_resched();
1278c2ecf20Sopenharmony_ci		}
1288c2ecf20Sopenharmony_ci	}
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	dbg_fsbuild("pass 1 complete\n");
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	/* Next, scan for inodes with nlink == 0 and remove them. If
1338c2ecf20Sopenharmony_ci	   they were directories, then decrement the nlink of their
1348c2ecf20Sopenharmony_ci	   children too, and repeat the scan. As that's going to be
1358c2ecf20Sopenharmony_ci	   a fairly uncommon occurrence, it's not so evil to do it this
1368c2ecf20Sopenharmony_ci	   way. Recursion bad. */
1378c2ecf20Sopenharmony_ci	dbg_fsbuild("pass 2 starting\n");
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	for_each_inode(i, c, ic) {
1408c2ecf20Sopenharmony_ci		if (ic->pino_nlink)
1418c2ecf20Sopenharmony_ci			continue;
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci		jffs2_build_remove_unlinked_inode(c, ic, &dead_fds);
1448c2ecf20Sopenharmony_ci		cond_resched();
1458c2ecf20Sopenharmony_ci	}
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	dbg_fsbuild("pass 2a starting\n");
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci	while (dead_fds) {
1508c2ecf20Sopenharmony_ci		fd = dead_fds;
1518c2ecf20Sopenharmony_ci		dead_fds = fd->next;
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci		ic = jffs2_get_ino_cache(c, fd->ino);
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci		if (ic)
1568c2ecf20Sopenharmony_ci			jffs2_build_remove_unlinked_inode(c, ic, &dead_fds);
1578c2ecf20Sopenharmony_ci		jffs2_free_full_dirent(fd);
1588c2ecf20Sopenharmony_ci	}
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci	dbg_fsbuild("pass 2a complete\n");
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	if (dir_hardlinks) {
1638c2ecf20Sopenharmony_ci		/* If we detected directory hardlinks earlier, *hopefully*
1648c2ecf20Sopenharmony_ci		 * they are gone now because some of the links were from
1658c2ecf20Sopenharmony_ci		 * dead directories which still had some old dirents lying
1668c2ecf20Sopenharmony_ci		 * around and not yet garbage-collected, but which have
1678c2ecf20Sopenharmony_ci		 * been discarded above. So clear the pino_nlink field
1688c2ecf20Sopenharmony_ci		 * in each directory, so that the final scan below can
1698c2ecf20Sopenharmony_ci		 * print appropriate warnings. */
1708c2ecf20Sopenharmony_ci		for_each_inode(i, c, ic) {
1718c2ecf20Sopenharmony_ci			if (ic->flags & INO_FLAGS_IS_DIR)
1728c2ecf20Sopenharmony_ci				ic->pino_nlink = 0;
1738c2ecf20Sopenharmony_ci		}
1748c2ecf20Sopenharmony_ci	}
1758c2ecf20Sopenharmony_ci	dbg_fsbuild("freeing temporary data structures\n");
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	/* Finally, we can scan again and free the dirent structs */
1788c2ecf20Sopenharmony_ci	for_each_inode(i, c, ic) {
1798c2ecf20Sopenharmony_ci		while(ic->scan_dents) {
1808c2ecf20Sopenharmony_ci			fd = ic->scan_dents;
1818c2ecf20Sopenharmony_ci			ic->scan_dents = fd->next;
1828c2ecf20Sopenharmony_ci			/* We do use the pino_nlink field to count nlink of
1838c2ecf20Sopenharmony_ci			 * directories during fs build, so set it to the
1848c2ecf20Sopenharmony_ci			 * parent ino# now. Now that there's hopefully only
1858c2ecf20Sopenharmony_ci			 * one. */
1868c2ecf20Sopenharmony_ci			if (fd->type == DT_DIR) {
1878c2ecf20Sopenharmony_ci				if (!fd->ic) {
1888c2ecf20Sopenharmony_ci					/* We'll have complained about it and marked the coresponding
1898c2ecf20Sopenharmony_ci					   raw node obsolete already. Just skip it. */
1908c2ecf20Sopenharmony_ci					continue;
1918c2ecf20Sopenharmony_ci				}
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci				/* We *have* to have set this in jffs2_build_inode_pass1() */
1948c2ecf20Sopenharmony_ci				BUG_ON(!(fd->ic->flags & INO_FLAGS_IS_DIR));
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci				/* We clear ic->pino_nlink ∀ directories' ic *only* if dir_hardlinks
1978c2ecf20Sopenharmony_ci				 * is set. Otherwise, we know this should never trigger anyway, so
1988c2ecf20Sopenharmony_ci				 * we don't do the check. And ic->pino_nlink still contains the nlink
1998c2ecf20Sopenharmony_ci				 * value (which is 1). */
2008c2ecf20Sopenharmony_ci				if (dir_hardlinks && fd->ic->pino_nlink) {
2018c2ecf20Sopenharmony_ci					JFFS2_ERROR("child dir \"%s\" (ino #%u) of dir ino #%u is also hard linked from dir ino #%u\n",
2028c2ecf20Sopenharmony_ci						    fd->name, fd->ino, ic->ino, fd->ic->pino_nlink);
2038c2ecf20Sopenharmony_ci					/* Should we unlink it from its previous parent? */
2048c2ecf20Sopenharmony_ci				}
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci				/* For directories, ic->pino_nlink holds that parent inode # */
2078c2ecf20Sopenharmony_ci				fd->ic->pino_nlink = ic->ino;
2088c2ecf20Sopenharmony_ci			}
2098c2ecf20Sopenharmony_ci			jffs2_free_full_dirent(fd);
2108c2ecf20Sopenharmony_ci		}
2118c2ecf20Sopenharmony_ci		ic->scan_dents = NULL;
2128c2ecf20Sopenharmony_ci		cond_resched();
2138c2ecf20Sopenharmony_ci	}
2148c2ecf20Sopenharmony_ci	ret = jffs2_build_xattr_subsystem(c);
2158c2ecf20Sopenharmony_ci	if (ret)
2168c2ecf20Sopenharmony_ci		goto exit;
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	c->flags &= ~JFFS2_SB_FLAG_BUILDING;
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	dbg_fsbuild("FS build complete\n");
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci	/* Rotate the lists by some number to ensure wear levelling */
2238c2ecf20Sopenharmony_ci	jffs2_rotate_lists(c);
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci	ret = 0;
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ciexit:
2288c2ecf20Sopenharmony_ci	if (ret) {
2298c2ecf20Sopenharmony_ci		for_each_inode(i, c, ic) {
2308c2ecf20Sopenharmony_ci			while(ic->scan_dents) {
2318c2ecf20Sopenharmony_ci				fd = ic->scan_dents;
2328c2ecf20Sopenharmony_ci				ic->scan_dents = fd->next;
2338c2ecf20Sopenharmony_ci				jffs2_free_full_dirent(fd);
2348c2ecf20Sopenharmony_ci			}
2358c2ecf20Sopenharmony_ci		}
2368c2ecf20Sopenharmony_ci		jffs2_clear_xattr_subsystem(c);
2378c2ecf20Sopenharmony_ci	}
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	return ret;
2408c2ecf20Sopenharmony_ci}
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_cistatic void jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *c,
2438c2ecf20Sopenharmony_ci					struct jffs2_inode_cache *ic,
2448c2ecf20Sopenharmony_ci					struct jffs2_full_dirent **dead_fds)
2458c2ecf20Sopenharmony_ci{
2468c2ecf20Sopenharmony_ci	struct jffs2_raw_node_ref *raw;
2478c2ecf20Sopenharmony_ci	struct jffs2_full_dirent *fd;
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci	dbg_fsbuild("removing ino #%u with nlink == zero.\n", ic->ino);
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	raw = ic->nodes;
2528c2ecf20Sopenharmony_ci	while (raw != (void *)ic) {
2538c2ecf20Sopenharmony_ci		struct jffs2_raw_node_ref *next = raw->next_in_ino;
2548c2ecf20Sopenharmony_ci		dbg_fsbuild("obsoleting node at 0x%08x\n", ref_offset(raw));
2558c2ecf20Sopenharmony_ci		jffs2_mark_node_obsolete(c, raw);
2568c2ecf20Sopenharmony_ci		raw = next;
2578c2ecf20Sopenharmony_ci	}
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	if (ic->scan_dents) {
2608c2ecf20Sopenharmony_ci		int whinged = 0;
2618c2ecf20Sopenharmony_ci		dbg_fsbuild("inode #%u was a directory which may have children...\n", ic->ino);
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci		while(ic->scan_dents) {
2648c2ecf20Sopenharmony_ci			struct jffs2_inode_cache *child_ic;
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci			fd = ic->scan_dents;
2678c2ecf20Sopenharmony_ci			ic->scan_dents = fd->next;
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci			if (!fd->ino) {
2708c2ecf20Sopenharmony_ci				/* It's a deletion dirent. Ignore it */
2718c2ecf20Sopenharmony_ci				dbg_fsbuild("child \"%s\" is a deletion dirent, skipping...\n", fd->name);
2728c2ecf20Sopenharmony_ci				jffs2_free_full_dirent(fd);
2738c2ecf20Sopenharmony_ci				continue;
2748c2ecf20Sopenharmony_ci			}
2758c2ecf20Sopenharmony_ci			if (!whinged)
2768c2ecf20Sopenharmony_ci				whinged = 1;
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci			dbg_fsbuild("removing child \"%s\", ino #%u\n", fd->name, fd->ino);
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci			child_ic = jffs2_get_ino_cache(c, fd->ino);
2818c2ecf20Sopenharmony_ci			if (!child_ic) {
2828c2ecf20Sopenharmony_ci				dbg_fsbuild("cannot remove child \"%s\", ino #%u, because it doesn't exist\n",
2838c2ecf20Sopenharmony_ci						fd->name, fd->ino);
2848c2ecf20Sopenharmony_ci				jffs2_free_full_dirent(fd);
2858c2ecf20Sopenharmony_ci				continue;
2868c2ecf20Sopenharmony_ci			}
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci			/* Reduce nlink of the child. If it's now zero, stick it on the
2898c2ecf20Sopenharmony_ci			   dead_fds list to be cleaned up later. Else just free the fd */
2908c2ecf20Sopenharmony_ci			child_ic->pino_nlink--;
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci			if (!child_ic->pino_nlink) {
2938c2ecf20Sopenharmony_ci				dbg_fsbuild("inode #%u (\"%s\") now has no links; adding to dead_fds list.\n",
2948c2ecf20Sopenharmony_ci					  fd->ino, fd->name);
2958c2ecf20Sopenharmony_ci				fd->next = *dead_fds;
2968c2ecf20Sopenharmony_ci				*dead_fds = fd;
2978c2ecf20Sopenharmony_ci			} else {
2988c2ecf20Sopenharmony_ci				dbg_fsbuild("inode #%u (\"%s\") has now got nlink %d. Ignoring.\n",
2998c2ecf20Sopenharmony_ci					  fd->ino, fd->name, child_ic->pino_nlink);
3008c2ecf20Sopenharmony_ci				jffs2_free_full_dirent(fd);
3018c2ecf20Sopenharmony_ci			}
3028c2ecf20Sopenharmony_ci		}
3038c2ecf20Sopenharmony_ci	}
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	/*
3068c2ecf20Sopenharmony_ci	   We don't delete the inocache from the hash list and free it yet.
3078c2ecf20Sopenharmony_ci	   The erase code will do that, when all the nodes are completely gone.
3088c2ecf20Sopenharmony_ci	*/
3098c2ecf20Sopenharmony_ci}
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_cistatic void jffs2_calc_trigger_levels(struct jffs2_sb_info *c)
3128c2ecf20Sopenharmony_ci{
3138c2ecf20Sopenharmony_ci	uint32_t size;
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci	/* Deletion should almost _always_ be allowed. We're fairly
3168c2ecf20Sopenharmony_ci	   buggered once we stop allowing people to delete stuff
3178c2ecf20Sopenharmony_ci	   because there's not enough free space... */
3188c2ecf20Sopenharmony_ci	c->resv_blocks_deletion = 2;
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci	/* Be conservative about how much space we need before we allow writes.
3218c2ecf20Sopenharmony_ci	   On top of that which is required for deletia, require an extra 2%
3228c2ecf20Sopenharmony_ci	   of the medium to be available, for overhead caused by nodes being
3238c2ecf20Sopenharmony_ci	   split across blocks, etc. */
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci	size = c->flash_size / 50; /* 2% of flash size */
3268c2ecf20Sopenharmony_ci	size += c->nr_blocks * 100; /* And 100 bytes per eraseblock */
3278c2ecf20Sopenharmony_ci	size += c->sector_size - 1; /* ... and round up */
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	c->resv_blocks_write = c->resv_blocks_deletion + (size / c->sector_size);
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci	/* When do we let the GC thread run in the background */
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci	c->resv_blocks_gctrigger = c->resv_blocks_write + 1;
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	/* When do we allow garbage collection to merge nodes to make
3368c2ecf20Sopenharmony_ci	   long-term progress at the expense of short-term space exhaustion? */
3378c2ecf20Sopenharmony_ci	c->resv_blocks_gcmerge = c->resv_blocks_deletion + 1;
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	/* When do we allow garbage collection to eat from bad blocks rather
3408c2ecf20Sopenharmony_ci	   than actually making progress? */
3418c2ecf20Sopenharmony_ci	c->resv_blocks_gcbad = 0;//c->resv_blocks_deletion + 2;
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci	/* What number of 'very dirty' eraseblocks do we allow before we
3448c2ecf20Sopenharmony_ci	   trigger the GC thread even if we don't _need_ the space. When we
3458c2ecf20Sopenharmony_ci	   can't mark nodes obsolete on the medium, the old dirty nodes cause
3468c2ecf20Sopenharmony_ci	   performance problems because we have to inspect and discard them. */
3478c2ecf20Sopenharmony_ci	c->vdirty_blocks_gctrigger = c->resv_blocks_gctrigger;
3488c2ecf20Sopenharmony_ci	if (jffs2_can_mark_obsolete(c))
3498c2ecf20Sopenharmony_ci		c->vdirty_blocks_gctrigger *= 10;
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	/* If there's less than this amount of dirty space, don't bother
3528c2ecf20Sopenharmony_ci	   trying to GC to make more space. It'll be a fruitless task */
3538c2ecf20Sopenharmony_ci	c->nospc_dirty_size = c->sector_size + (c->flash_size / 100);
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci	dbg_fsbuild("trigger levels (size %d KiB, block size %d KiB, %d blocks)\n",
3568c2ecf20Sopenharmony_ci		    c->flash_size / 1024, c->sector_size / 1024, c->nr_blocks);
3578c2ecf20Sopenharmony_ci	dbg_fsbuild("Blocks required to allow deletion:    %d (%d KiB)\n",
3588c2ecf20Sopenharmony_ci		  c->resv_blocks_deletion, c->resv_blocks_deletion*c->sector_size/1024);
3598c2ecf20Sopenharmony_ci	dbg_fsbuild("Blocks required to allow writes:      %d (%d KiB)\n",
3608c2ecf20Sopenharmony_ci		  c->resv_blocks_write, c->resv_blocks_write*c->sector_size/1024);
3618c2ecf20Sopenharmony_ci	dbg_fsbuild("Blocks required to quiesce GC thread: %d (%d KiB)\n",
3628c2ecf20Sopenharmony_ci		  c->resv_blocks_gctrigger, c->resv_blocks_gctrigger*c->sector_size/1024);
3638c2ecf20Sopenharmony_ci	dbg_fsbuild("Blocks required to allow GC merges:   %d (%d KiB)\n",
3648c2ecf20Sopenharmony_ci		  c->resv_blocks_gcmerge, c->resv_blocks_gcmerge*c->sector_size/1024);
3658c2ecf20Sopenharmony_ci	dbg_fsbuild("Blocks required to GC bad blocks:     %d (%d KiB)\n",
3668c2ecf20Sopenharmony_ci		  c->resv_blocks_gcbad, c->resv_blocks_gcbad*c->sector_size/1024);
3678c2ecf20Sopenharmony_ci	dbg_fsbuild("Amount of dirty space required to GC: %d bytes\n",
3688c2ecf20Sopenharmony_ci		  c->nospc_dirty_size);
3698c2ecf20Sopenharmony_ci	dbg_fsbuild("Very dirty blocks before GC triggered: %d\n",
3708c2ecf20Sopenharmony_ci		  c->vdirty_blocks_gctrigger);
3718c2ecf20Sopenharmony_ci}
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ciint jffs2_do_mount_fs(struct jffs2_sb_info *c)
3748c2ecf20Sopenharmony_ci{
3758c2ecf20Sopenharmony_ci	int ret;
3768c2ecf20Sopenharmony_ci	int i;
3778c2ecf20Sopenharmony_ci	int size;
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci	c->free_size = c->flash_size;
3808c2ecf20Sopenharmony_ci	c->nr_blocks = c->flash_size / c->sector_size;
3818c2ecf20Sopenharmony_ci	size = sizeof(struct jffs2_eraseblock) * c->nr_blocks;
3828c2ecf20Sopenharmony_ci#ifndef __ECOS
3838c2ecf20Sopenharmony_ci	if (jffs2_blocks_use_vmalloc(c))
3848c2ecf20Sopenharmony_ci		c->blocks = vzalloc(size);
3858c2ecf20Sopenharmony_ci	else
3868c2ecf20Sopenharmony_ci#endif
3878c2ecf20Sopenharmony_ci		c->blocks = kzalloc(size, GFP_KERNEL);
3888c2ecf20Sopenharmony_ci	if (!c->blocks)
3898c2ecf20Sopenharmony_ci		return -ENOMEM;
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	for (i=0; i<c->nr_blocks; i++) {
3928c2ecf20Sopenharmony_ci		INIT_LIST_HEAD(&c->blocks[i].list);
3938c2ecf20Sopenharmony_ci		c->blocks[i].offset = i * c->sector_size;
3948c2ecf20Sopenharmony_ci		c->blocks[i].free_size = c->sector_size;
3958c2ecf20Sopenharmony_ci	}
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&c->clean_list);
3988c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&c->very_dirty_list);
3998c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&c->dirty_list);
4008c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&c->erasable_list);
4018c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&c->erasing_list);
4028c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&c->erase_checking_list);
4038c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&c->erase_pending_list);
4048c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&c->erasable_pending_wbuf_list);
4058c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&c->erase_complete_list);
4068c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&c->free_list);
4078c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&c->bad_list);
4088c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&c->bad_used_list);
4098c2ecf20Sopenharmony_ci	c->highest_ino = 1;
4108c2ecf20Sopenharmony_ci	c->summary = NULL;
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci	ret = jffs2_sum_init(c);
4138c2ecf20Sopenharmony_ci	if (ret)
4148c2ecf20Sopenharmony_ci		goto out_free;
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ci	if (jffs2_build_filesystem(c)) {
4178c2ecf20Sopenharmony_ci		dbg_fsbuild("build_fs failed\n");
4188c2ecf20Sopenharmony_ci		jffs2_free_ino_caches(c);
4198c2ecf20Sopenharmony_ci		jffs2_free_raw_node_refs(c);
4208c2ecf20Sopenharmony_ci		ret = -EIO;
4218c2ecf20Sopenharmony_ci		goto out_sum_exit;
4228c2ecf20Sopenharmony_ci	}
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci	jffs2_calc_trigger_levels(c);
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_ci	return 0;
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci out_sum_exit:
4298c2ecf20Sopenharmony_ci	jffs2_sum_exit(c);
4308c2ecf20Sopenharmony_ci out_free:
4318c2ecf20Sopenharmony_ci	kvfree(c->blocks);
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci	return ret;
4348c2ecf20Sopenharmony_ci}
435