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