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