18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * JFFS2 -- Journalling Flash File System, Version 2. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright © 2001-2007 Red Hat, Inc. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Created by David Woodhouse <dwmw2@infradead.org> 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * For licensing information, see the file 'LICENCE' in this directory. 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <linux/kernel.h> 158c2ecf20Sopenharmony_ci#include <linux/mtd/mtd.h> 168c2ecf20Sopenharmony_ci#include <linux/compiler.h> 178c2ecf20Sopenharmony_ci#include <linux/sched/signal.h> 188c2ecf20Sopenharmony_ci#include "nodelist.h" 198c2ecf20Sopenharmony_ci#include "debug.h" 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci/* 228c2ecf20Sopenharmony_ci * Check whether the user is allowed to write. 238c2ecf20Sopenharmony_ci */ 248c2ecf20Sopenharmony_cistatic int jffs2_rp_can_write(struct jffs2_sb_info *c) 258c2ecf20Sopenharmony_ci{ 268c2ecf20Sopenharmony_ci uint32_t avail; 278c2ecf20Sopenharmony_ci struct jffs2_mount_opts *opts = &c->mount_opts; 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci avail = c->dirty_size + c->free_size + c->unchecked_size + 308c2ecf20Sopenharmony_ci c->erasing_size - c->resv_blocks_write * c->sector_size 318c2ecf20Sopenharmony_ci - c->nospc_dirty_size; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci if (avail < 2 * opts->rp_size) 348c2ecf20Sopenharmony_ci jffs2_dbg(1, "rpsize %u, dirty_size %u, free_size %u, " 358c2ecf20Sopenharmony_ci "erasing_size %u, unchecked_size %u, " 368c2ecf20Sopenharmony_ci "nr_erasing_blocks %u, avail %u, resrv %u\n", 378c2ecf20Sopenharmony_ci opts->rp_size, c->dirty_size, c->free_size, 388c2ecf20Sopenharmony_ci c->erasing_size, c->unchecked_size, 398c2ecf20Sopenharmony_ci c->nr_erasing_blocks, avail, c->nospc_dirty_size); 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci if (avail > opts->rp_size) 428c2ecf20Sopenharmony_ci return 1; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci /* Always allow root */ 458c2ecf20Sopenharmony_ci if (capable(CAP_SYS_RESOURCE)) 468c2ecf20Sopenharmony_ci return 1; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci jffs2_dbg(1, "forbid writing\n"); 498c2ecf20Sopenharmony_ci return 0; 508c2ecf20Sopenharmony_ci} 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci/** 538c2ecf20Sopenharmony_ci * jffs2_reserve_space - request physical space to write nodes to flash 548c2ecf20Sopenharmony_ci * @c: superblock info 558c2ecf20Sopenharmony_ci * @minsize: Minimum acceptable size of allocation 568c2ecf20Sopenharmony_ci * @len: Returned value of allocation length 578c2ecf20Sopenharmony_ci * @prio: Allocation type - ALLOC_{NORMAL,DELETION} 588c2ecf20Sopenharmony_ci * 598c2ecf20Sopenharmony_ci * Requests a block of physical space on the flash. Returns zero for success 608c2ecf20Sopenharmony_ci * and puts 'len' into the appropriate place, or returns -ENOSPC or other 618c2ecf20Sopenharmony_ci * error if appropriate. Doesn't return len since that's 628c2ecf20Sopenharmony_ci * 638c2ecf20Sopenharmony_ci * If it returns zero, jffs2_reserve_space() also downs the per-filesystem 648c2ecf20Sopenharmony_ci * allocation semaphore, to prevent more than one allocation from being 658c2ecf20Sopenharmony_ci * active at any time. The semaphore is later released by jffs2_commit_allocation() 668c2ecf20Sopenharmony_ci * 678c2ecf20Sopenharmony_ci * jffs2_reserve_space() may trigger garbage collection in order to make room 688c2ecf20Sopenharmony_ci * for the requested allocation. 698c2ecf20Sopenharmony_ci */ 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_cistatic int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, 728c2ecf20Sopenharmony_ci uint32_t *len, uint32_t sumsize); 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ciint jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, 758c2ecf20Sopenharmony_ci uint32_t *len, int prio, uint32_t sumsize) 768c2ecf20Sopenharmony_ci{ 778c2ecf20Sopenharmony_ci int ret = -EAGAIN; 788c2ecf20Sopenharmony_ci int blocksneeded = c->resv_blocks_write; 798c2ecf20Sopenharmony_ci /* align it */ 808c2ecf20Sopenharmony_ci minsize = PAD(minsize); 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci jffs2_dbg(1, "%s(): Requested 0x%x bytes\n", __func__, minsize); 838c2ecf20Sopenharmony_ci mutex_lock(&c->alloc_sem); 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci jffs2_dbg(1, "%s(): alloc sem got\n", __func__); 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci spin_lock(&c->erase_completion_lock); 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci /* 908c2ecf20Sopenharmony_ci * Check if the free space is greater then size of the reserved pool. 918c2ecf20Sopenharmony_ci * If not, only allow root to proceed with writing. 928c2ecf20Sopenharmony_ci */ 938c2ecf20Sopenharmony_ci if (prio != ALLOC_DELETION && !jffs2_rp_can_write(c)) { 948c2ecf20Sopenharmony_ci ret = -ENOSPC; 958c2ecf20Sopenharmony_ci goto out; 968c2ecf20Sopenharmony_ci } 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci /* this needs a little more thought (true <tglx> :)) */ 998c2ecf20Sopenharmony_ci while(ret == -EAGAIN) { 1008c2ecf20Sopenharmony_ci while(c->nr_free_blocks + c->nr_erasing_blocks < blocksneeded) { 1018c2ecf20Sopenharmony_ci uint32_t dirty, avail; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci /* calculate real dirty size 1048c2ecf20Sopenharmony_ci * dirty_size contains blocks on erase_pending_list 1058c2ecf20Sopenharmony_ci * those blocks are counted in c->nr_erasing_blocks. 1068c2ecf20Sopenharmony_ci * If one block is actually erased, it is not longer counted as dirty_space 1078c2ecf20Sopenharmony_ci * but it is counted in c->nr_erasing_blocks, so we add it and subtract it 1088c2ecf20Sopenharmony_ci * with c->nr_erasing_blocks * c->sector_size again. 1098c2ecf20Sopenharmony_ci * Blocks on erasable_list are counted as dirty_size, but not in c->nr_erasing_blocks 1108c2ecf20Sopenharmony_ci * This helps us to force gc and pick eventually a clean block to spread the load. 1118c2ecf20Sopenharmony_ci * We add unchecked_size here, as we hopefully will find some space to use. 1128c2ecf20Sopenharmony_ci * This will affect the sum only once, as gc first finishes checking 1138c2ecf20Sopenharmony_ci * of nodes. 1148c2ecf20Sopenharmony_ci */ 1158c2ecf20Sopenharmony_ci dirty = c->dirty_size + c->erasing_size - c->nr_erasing_blocks * c->sector_size + c->unchecked_size; 1168c2ecf20Sopenharmony_ci if (dirty < c->nospc_dirty_size) { 1178c2ecf20Sopenharmony_ci if (prio == ALLOC_DELETION && c->nr_free_blocks + c->nr_erasing_blocks >= c->resv_blocks_deletion) { 1188c2ecf20Sopenharmony_ci jffs2_dbg(1, "%s(): Low on dirty space to GC, but it's a deletion. Allowing...\n", 1198c2ecf20Sopenharmony_ci __func__); 1208c2ecf20Sopenharmony_ci break; 1218c2ecf20Sopenharmony_ci } 1228c2ecf20Sopenharmony_ci jffs2_dbg(1, "dirty size 0x%08x + unchecked_size 0x%08x < nospc_dirty_size 0x%08x, returning -ENOSPC\n", 1238c2ecf20Sopenharmony_ci dirty, c->unchecked_size, 1248c2ecf20Sopenharmony_ci c->sector_size); 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci spin_unlock(&c->erase_completion_lock); 1278c2ecf20Sopenharmony_ci mutex_unlock(&c->alloc_sem); 1288c2ecf20Sopenharmony_ci return -ENOSPC; 1298c2ecf20Sopenharmony_ci } 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci /* Calc possibly available space. Possibly available means that we 1328c2ecf20Sopenharmony_ci * don't know, if unchecked size contains obsoleted nodes, which could give us some 1338c2ecf20Sopenharmony_ci * more usable space. This will affect the sum only once, as gc first finishes checking 1348c2ecf20Sopenharmony_ci * of nodes. 1358c2ecf20Sopenharmony_ci + Return -ENOSPC, if the maximum possibly available space is less or equal than 1368c2ecf20Sopenharmony_ci * blocksneeded * sector_size. 1378c2ecf20Sopenharmony_ci * This blocks endless gc looping on a filesystem, which is nearly full, even if 1388c2ecf20Sopenharmony_ci * the check above passes. 1398c2ecf20Sopenharmony_ci */ 1408c2ecf20Sopenharmony_ci avail = c->free_size + c->dirty_size + c->erasing_size + c->unchecked_size; 1418c2ecf20Sopenharmony_ci if ( (avail / c->sector_size) <= blocksneeded) { 1428c2ecf20Sopenharmony_ci if (prio == ALLOC_DELETION && c->nr_free_blocks + c->nr_erasing_blocks >= c->resv_blocks_deletion) { 1438c2ecf20Sopenharmony_ci jffs2_dbg(1, "%s(): Low on possibly available space, but it's a deletion. Allowing...\n", 1448c2ecf20Sopenharmony_ci __func__); 1458c2ecf20Sopenharmony_ci break; 1468c2ecf20Sopenharmony_ci } 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci jffs2_dbg(1, "max. available size 0x%08x < blocksneeded * sector_size 0x%08x, returning -ENOSPC\n", 1498c2ecf20Sopenharmony_ci avail, blocksneeded * c->sector_size); 1508c2ecf20Sopenharmony_ci spin_unlock(&c->erase_completion_lock); 1518c2ecf20Sopenharmony_ci mutex_unlock(&c->alloc_sem); 1528c2ecf20Sopenharmony_ci return -ENOSPC; 1538c2ecf20Sopenharmony_ci } 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci mutex_unlock(&c->alloc_sem); 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci jffs2_dbg(1, "Triggering GC pass. nr_free_blocks %d, nr_erasing_blocks %d, free_size 0x%08x, dirty_size 0x%08x, wasted_size 0x%08x, used_size 0x%08x, erasing_size 0x%08x, bad_size 0x%08x (total 0x%08x of 0x%08x)\n", 1588c2ecf20Sopenharmony_ci c->nr_free_blocks, c->nr_erasing_blocks, 1598c2ecf20Sopenharmony_ci c->free_size, c->dirty_size, c->wasted_size, 1608c2ecf20Sopenharmony_ci c->used_size, c->erasing_size, c->bad_size, 1618c2ecf20Sopenharmony_ci c->free_size + c->dirty_size + 1628c2ecf20Sopenharmony_ci c->wasted_size + c->used_size + 1638c2ecf20Sopenharmony_ci c->erasing_size + c->bad_size, 1648c2ecf20Sopenharmony_ci c->flash_size); 1658c2ecf20Sopenharmony_ci spin_unlock(&c->erase_completion_lock); 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci ret = jffs2_garbage_collect_pass(c); 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci if (ret == -EAGAIN) { 1708c2ecf20Sopenharmony_ci spin_lock(&c->erase_completion_lock); 1718c2ecf20Sopenharmony_ci if (c->nr_erasing_blocks && 1728c2ecf20Sopenharmony_ci list_empty(&c->erase_pending_list) && 1738c2ecf20Sopenharmony_ci list_empty(&c->erase_complete_list)) { 1748c2ecf20Sopenharmony_ci DECLARE_WAITQUEUE(wait, current); 1758c2ecf20Sopenharmony_ci set_current_state(TASK_UNINTERRUPTIBLE); 1768c2ecf20Sopenharmony_ci add_wait_queue(&c->erase_wait, &wait); 1778c2ecf20Sopenharmony_ci jffs2_dbg(1, "%s waiting for erase to complete\n", 1788c2ecf20Sopenharmony_ci __func__); 1798c2ecf20Sopenharmony_ci spin_unlock(&c->erase_completion_lock); 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci schedule(); 1828c2ecf20Sopenharmony_ci remove_wait_queue(&c->erase_wait, &wait); 1838c2ecf20Sopenharmony_ci } else 1848c2ecf20Sopenharmony_ci spin_unlock(&c->erase_completion_lock); 1858c2ecf20Sopenharmony_ci } else if (ret) 1868c2ecf20Sopenharmony_ci return ret; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci cond_resched(); 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci if (signal_pending(current)) 1918c2ecf20Sopenharmony_ci return -EINTR; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci mutex_lock(&c->alloc_sem); 1948c2ecf20Sopenharmony_ci spin_lock(&c->erase_completion_lock); 1958c2ecf20Sopenharmony_ci } 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci ret = jffs2_do_reserve_space(c, minsize, len, sumsize); 1988c2ecf20Sopenharmony_ci if (ret) { 1998c2ecf20Sopenharmony_ci jffs2_dbg(1, "%s(): ret is %d\n", __func__, ret); 2008c2ecf20Sopenharmony_ci } 2018c2ecf20Sopenharmony_ci } 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ciout: 2048c2ecf20Sopenharmony_ci spin_unlock(&c->erase_completion_lock); 2058c2ecf20Sopenharmony_ci if (!ret) 2068c2ecf20Sopenharmony_ci ret = jffs2_prealloc_raw_node_refs(c, c->nextblock, 1); 2078c2ecf20Sopenharmony_ci if (ret) 2088c2ecf20Sopenharmony_ci mutex_unlock(&c->alloc_sem); 2098c2ecf20Sopenharmony_ci return ret; 2108c2ecf20Sopenharmony_ci} 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ciint jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, 2138c2ecf20Sopenharmony_ci uint32_t *len, uint32_t sumsize) 2148c2ecf20Sopenharmony_ci{ 2158c2ecf20Sopenharmony_ci int ret; 2168c2ecf20Sopenharmony_ci minsize = PAD(minsize); 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci jffs2_dbg(1, "%s(): Requested 0x%x bytes\n", __func__, minsize); 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci while (true) { 2218c2ecf20Sopenharmony_ci spin_lock(&c->erase_completion_lock); 2228c2ecf20Sopenharmony_ci ret = jffs2_do_reserve_space(c, minsize, len, sumsize); 2238c2ecf20Sopenharmony_ci if (ret) { 2248c2ecf20Sopenharmony_ci jffs2_dbg(1, "%s(): looping, ret is %d\n", 2258c2ecf20Sopenharmony_ci __func__, ret); 2268c2ecf20Sopenharmony_ci } 2278c2ecf20Sopenharmony_ci spin_unlock(&c->erase_completion_lock); 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci if (ret == -EAGAIN) 2308c2ecf20Sopenharmony_ci cond_resched(); 2318c2ecf20Sopenharmony_ci else 2328c2ecf20Sopenharmony_ci break; 2338c2ecf20Sopenharmony_ci } 2348c2ecf20Sopenharmony_ci if (!ret) 2358c2ecf20Sopenharmony_ci ret = jffs2_prealloc_raw_node_refs(c, c->nextblock, 1); 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci return ret; 2388c2ecf20Sopenharmony_ci} 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci/* Classify nextblock (clean, dirty of verydirty) and force to select an other one */ 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_cistatic void jffs2_close_nextblock(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) 2448c2ecf20Sopenharmony_ci{ 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci if (c->nextblock == NULL) { 2478c2ecf20Sopenharmony_ci jffs2_dbg(1, "%s(): Erase block at 0x%08x has already been placed in a list\n", 2488c2ecf20Sopenharmony_ci __func__, jeb->offset); 2498c2ecf20Sopenharmony_ci return; 2508c2ecf20Sopenharmony_ci } 2518c2ecf20Sopenharmony_ci /* Check, if we have a dirty block now, or if it was dirty already */ 2528c2ecf20Sopenharmony_ci if (ISDIRTY (jeb->wasted_size + jeb->dirty_size)) { 2538c2ecf20Sopenharmony_ci c->dirty_size += jeb->wasted_size; 2548c2ecf20Sopenharmony_ci c->wasted_size -= jeb->wasted_size; 2558c2ecf20Sopenharmony_ci jeb->dirty_size += jeb->wasted_size; 2568c2ecf20Sopenharmony_ci jeb->wasted_size = 0; 2578c2ecf20Sopenharmony_ci if (VERYDIRTY(c, jeb->dirty_size)) { 2588c2ecf20Sopenharmony_ci jffs2_dbg(1, "Adding full erase block at 0x%08x to very_dirty_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n", 2598c2ecf20Sopenharmony_ci jeb->offset, jeb->free_size, jeb->dirty_size, 2608c2ecf20Sopenharmony_ci jeb->used_size); 2618c2ecf20Sopenharmony_ci list_add_tail(&jeb->list, &c->very_dirty_list); 2628c2ecf20Sopenharmony_ci } else { 2638c2ecf20Sopenharmony_ci jffs2_dbg(1, "Adding full erase block at 0x%08x to dirty_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n", 2648c2ecf20Sopenharmony_ci jeb->offset, jeb->free_size, jeb->dirty_size, 2658c2ecf20Sopenharmony_ci jeb->used_size); 2668c2ecf20Sopenharmony_ci list_add_tail(&jeb->list, &c->dirty_list); 2678c2ecf20Sopenharmony_ci } 2688c2ecf20Sopenharmony_ci } else { 2698c2ecf20Sopenharmony_ci jffs2_dbg(1, "Adding full erase block at 0x%08x to clean_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n", 2708c2ecf20Sopenharmony_ci jeb->offset, jeb->free_size, jeb->dirty_size, 2718c2ecf20Sopenharmony_ci jeb->used_size); 2728c2ecf20Sopenharmony_ci list_add_tail(&jeb->list, &c->clean_list); 2738c2ecf20Sopenharmony_ci } 2748c2ecf20Sopenharmony_ci c->nextblock = NULL; 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci} 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci/* Select a new jeb for nextblock */ 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_cistatic int jffs2_find_nextblock(struct jffs2_sb_info *c) 2818c2ecf20Sopenharmony_ci{ 2828c2ecf20Sopenharmony_ci struct list_head *next; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci /* Take the next block off the 'free' list */ 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci if (list_empty(&c->free_list)) { 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci if (!c->nr_erasing_blocks && 2898c2ecf20Sopenharmony_ci !list_empty(&c->erasable_list)) { 2908c2ecf20Sopenharmony_ci struct jffs2_eraseblock *ejeb; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci ejeb = list_entry(c->erasable_list.next, struct jffs2_eraseblock, list); 2938c2ecf20Sopenharmony_ci list_move_tail(&ejeb->list, &c->erase_pending_list); 2948c2ecf20Sopenharmony_ci c->nr_erasing_blocks++; 2958c2ecf20Sopenharmony_ci jffs2_garbage_collect_trigger(c); 2968c2ecf20Sopenharmony_ci jffs2_dbg(1, "%s(): Triggering erase of erasable block at 0x%08x\n", 2978c2ecf20Sopenharmony_ci __func__, ejeb->offset); 2988c2ecf20Sopenharmony_ci } 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci if (!c->nr_erasing_blocks && 3018c2ecf20Sopenharmony_ci !list_empty(&c->erasable_pending_wbuf_list)) { 3028c2ecf20Sopenharmony_ci jffs2_dbg(1, "%s(): Flushing write buffer\n", 3038c2ecf20Sopenharmony_ci __func__); 3048c2ecf20Sopenharmony_ci /* c->nextblock is NULL, no update to c->nextblock allowed */ 3058c2ecf20Sopenharmony_ci spin_unlock(&c->erase_completion_lock); 3068c2ecf20Sopenharmony_ci jffs2_flush_wbuf_pad(c); 3078c2ecf20Sopenharmony_ci spin_lock(&c->erase_completion_lock); 3088c2ecf20Sopenharmony_ci /* Have another go. It'll be on the erasable_list now */ 3098c2ecf20Sopenharmony_ci return -EAGAIN; 3108c2ecf20Sopenharmony_ci } 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci if (!c->nr_erasing_blocks) { 3138c2ecf20Sopenharmony_ci /* Ouch. We're in GC, or we wouldn't have got here. 3148c2ecf20Sopenharmony_ci And there's no space left. At all. */ 3158c2ecf20Sopenharmony_ci pr_crit("Argh. No free space left for GC. nr_erasing_blocks is %d. nr_free_blocks is %d. (erasableempty: %s, erasingempty: %s, erasependingempty: %s)\n", 3168c2ecf20Sopenharmony_ci c->nr_erasing_blocks, c->nr_free_blocks, 3178c2ecf20Sopenharmony_ci list_empty(&c->erasable_list) ? "yes" : "no", 3188c2ecf20Sopenharmony_ci list_empty(&c->erasing_list) ? "yes" : "no", 3198c2ecf20Sopenharmony_ci list_empty(&c->erase_pending_list) ? "yes" : "no"); 3208c2ecf20Sopenharmony_ci return -ENOSPC; 3218c2ecf20Sopenharmony_ci } 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci spin_unlock(&c->erase_completion_lock); 3248c2ecf20Sopenharmony_ci /* Don't wait for it; just erase one right now */ 3258c2ecf20Sopenharmony_ci jffs2_erase_pending_blocks(c, 1); 3268c2ecf20Sopenharmony_ci spin_lock(&c->erase_completion_lock); 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci /* An erase may have failed, decreasing the 3298c2ecf20Sopenharmony_ci amount of free space available. So we must 3308c2ecf20Sopenharmony_ci restart from the beginning */ 3318c2ecf20Sopenharmony_ci return -EAGAIN; 3328c2ecf20Sopenharmony_ci } 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci next = c->free_list.next; 3358c2ecf20Sopenharmony_ci list_del(next); 3368c2ecf20Sopenharmony_ci c->nextblock = list_entry(next, struct jffs2_eraseblock, list); 3378c2ecf20Sopenharmony_ci c->nr_free_blocks--; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci jffs2_sum_reset_collected(c->summary); /* reset collected summary */ 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci#ifdef CONFIG_JFFS2_FS_WRITEBUFFER 3428c2ecf20Sopenharmony_ci /* adjust write buffer offset, else we get a non contiguous write bug */ 3438c2ecf20Sopenharmony_ci if (!(c->wbuf_ofs % c->sector_size) && !c->wbuf_len) 3448c2ecf20Sopenharmony_ci c->wbuf_ofs = 0xffffffff; 3458c2ecf20Sopenharmony_ci#endif 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci jffs2_dbg(1, "%s(): new nextblock = 0x%08x\n", 3488c2ecf20Sopenharmony_ci __func__, c->nextblock->offset); 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci return 0; 3518c2ecf20Sopenharmony_ci} 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci/* Called with alloc sem _and_ erase_completion_lock */ 3548c2ecf20Sopenharmony_cistatic int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, 3558c2ecf20Sopenharmony_ci uint32_t *len, uint32_t sumsize) 3568c2ecf20Sopenharmony_ci{ 3578c2ecf20Sopenharmony_ci struct jffs2_eraseblock *jeb = c->nextblock; 3588c2ecf20Sopenharmony_ci uint32_t reserved_size; /* for summary information at the end of the jeb */ 3598c2ecf20Sopenharmony_ci int ret; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci restart: 3628c2ecf20Sopenharmony_ci reserved_size = 0; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci if (jffs2_sum_active() && (sumsize != JFFS2_SUMMARY_NOSUM_SIZE)) { 3658c2ecf20Sopenharmony_ci /* NOSUM_SIZE means not to generate summary */ 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci if (jeb) { 3688c2ecf20Sopenharmony_ci reserved_size = PAD(sumsize + c->summary->sum_size + JFFS2_SUMMARY_FRAME_SIZE); 3698c2ecf20Sopenharmony_ci dbg_summary("minsize=%d , jeb->free=%d ," 3708c2ecf20Sopenharmony_ci "summary->size=%d , sumsize=%d\n", 3718c2ecf20Sopenharmony_ci minsize, jeb->free_size, 3728c2ecf20Sopenharmony_ci c->summary->sum_size, sumsize); 3738c2ecf20Sopenharmony_ci } 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci /* Is there enough space for writing out the current node, or we have to 3768c2ecf20Sopenharmony_ci write out summary information now, close this jeb and select new nextblock? */ 3778c2ecf20Sopenharmony_ci if (jeb && (PAD(minsize) + PAD(c->summary->sum_size + sumsize + 3788c2ecf20Sopenharmony_ci JFFS2_SUMMARY_FRAME_SIZE) > jeb->free_size)) { 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci /* Has summary been disabled for this jeb? */ 3818c2ecf20Sopenharmony_ci if (jffs2_sum_is_disabled(c->summary)) { 3828c2ecf20Sopenharmony_ci sumsize = JFFS2_SUMMARY_NOSUM_SIZE; 3838c2ecf20Sopenharmony_ci goto restart; 3848c2ecf20Sopenharmony_ci } 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci /* Writing out the collected summary information */ 3878c2ecf20Sopenharmony_ci dbg_summary("generating summary for 0x%08x.\n", jeb->offset); 3888c2ecf20Sopenharmony_ci ret = jffs2_sum_write_sumnode(c); 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci if (ret) 3918c2ecf20Sopenharmony_ci return ret; 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci if (jffs2_sum_is_disabled(c->summary)) { 3948c2ecf20Sopenharmony_ci /* jffs2_write_sumnode() couldn't write out the summary information 3958c2ecf20Sopenharmony_ci diabling summary for this jeb and free the collected information 3968c2ecf20Sopenharmony_ci */ 3978c2ecf20Sopenharmony_ci sumsize = JFFS2_SUMMARY_NOSUM_SIZE; 3988c2ecf20Sopenharmony_ci goto restart; 3998c2ecf20Sopenharmony_ci } 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci jffs2_close_nextblock(c, jeb); 4028c2ecf20Sopenharmony_ci jeb = NULL; 4038c2ecf20Sopenharmony_ci /* keep always valid value in reserved_size */ 4048c2ecf20Sopenharmony_ci reserved_size = PAD(sumsize + c->summary->sum_size + JFFS2_SUMMARY_FRAME_SIZE); 4058c2ecf20Sopenharmony_ci } 4068c2ecf20Sopenharmony_ci } else { 4078c2ecf20Sopenharmony_ci if (jeb && minsize > jeb->free_size) { 4088c2ecf20Sopenharmony_ci uint32_t waste; 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci /* Skip the end of this block and file it as having some dirty space */ 4118c2ecf20Sopenharmony_ci /* If there's a pending write to it, flush now */ 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci if (jffs2_wbuf_dirty(c)) { 4148c2ecf20Sopenharmony_ci spin_unlock(&c->erase_completion_lock); 4158c2ecf20Sopenharmony_ci jffs2_dbg(1, "%s(): Flushing write buffer\n", 4168c2ecf20Sopenharmony_ci __func__); 4178c2ecf20Sopenharmony_ci jffs2_flush_wbuf_pad(c); 4188c2ecf20Sopenharmony_ci spin_lock(&c->erase_completion_lock); 4198c2ecf20Sopenharmony_ci jeb = c->nextblock; 4208c2ecf20Sopenharmony_ci goto restart; 4218c2ecf20Sopenharmony_ci } 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci spin_unlock(&c->erase_completion_lock); 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci ret = jffs2_prealloc_raw_node_refs(c, jeb, 1); 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci /* Just lock it again and continue. Nothing much can change because 4288c2ecf20Sopenharmony_ci we hold c->alloc_sem anyway. In fact, it's not entirely clear why 4298c2ecf20Sopenharmony_ci we hold c->erase_completion_lock in the majority of this function... 4308c2ecf20Sopenharmony_ci but that's a question for another (more caffeine-rich) day. */ 4318c2ecf20Sopenharmony_ci spin_lock(&c->erase_completion_lock); 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci if (ret) 4348c2ecf20Sopenharmony_ci return ret; 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci waste = jeb->free_size; 4378c2ecf20Sopenharmony_ci jffs2_link_node_ref(c, jeb, 4388c2ecf20Sopenharmony_ci (jeb->offset + c->sector_size - waste) | REF_OBSOLETE, 4398c2ecf20Sopenharmony_ci waste, NULL); 4408c2ecf20Sopenharmony_ci /* FIXME: that made it count as dirty. Convert to wasted */ 4418c2ecf20Sopenharmony_ci jeb->dirty_size -= waste; 4428c2ecf20Sopenharmony_ci c->dirty_size -= waste; 4438c2ecf20Sopenharmony_ci jeb->wasted_size += waste; 4448c2ecf20Sopenharmony_ci c->wasted_size += waste; 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci jffs2_close_nextblock(c, jeb); 4478c2ecf20Sopenharmony_ci jeb = NULL; 4488c2ecf20Sopenharmony_ci } 4498c2ecf20Sopenharmony_ci } 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci if (!jeb) { 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci ret = jffs2_find_nextblock(c); 4548c2ecf20Sopenharmony_ci if (ret) 4558c2ecf20Sopenharmony_ci return ret; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci jeb = c->nextblock; 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci if (jeb->free_size != c->sector_size - c->cleanmarker_size) { 4608c2ecf20Sopenharmony_ci pr_warn("Eep. Block 0x%08x taken from free_list had free_size of 0x%08x!!\n", 4618c2ecf20Sopenharmony_ci jeb->offset, jeb->free_size); 4628c2ecf20Sopenharmony_ci goto restart; 4638c2ecf20Sopenharmony_ci } 4648c2ecf20Sopenharmony_ci } 4658c2ecf20Sopenharmony_ci /* OK, jeb (==c->nextblock) is now pointing at a block which definitely has 4668c2ecf20Sopenharmony_ci enough space */ 4678c2ecf20Sopenharmony_ci *len = jeb->free_size - reserved_size; 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci if (c->cleanmarker_size && jeb->used_size == c->cleanmarker_size && 4708c2ecf20Sopenharmony_ci !jeb->first_node->next_in_ino) { 4718c2ecf20Sopenharmony_ci /* Only node in it beforehand was a CLEANMARKER node (we think). 4728c2ecf20Sopenharmony_ci So mark it obsolete now that there's going to be another node 4738c2ecf20Sopenharmony_ci in the block. This will reduce used_size to zero but We've 4748c2ecf20Sopenharmony_ci already set c->nextblock so that jffs2_mark_node_obsolete() 4758c2ecf20Sopenharmony_ci won't try to refile it to the dirty_list. 4768c2ecf20Sopenharmony_ci */ 4778c2ecf20Sopenharmony_ci spin_unlock(&c->erase_completion_lock); 4788c2ecf20Sopenharmony_ci jffs2_mark_node_obsolete(c, jeb->first_node); 4798c2ecf20Sopenharmony_ci spin_lock(&c->erase_completion_lock); 4808c2ecf20Sopenharmony_ci } 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci jffs2_dbg(1, "%s(): Giving 0x%x bytes at 0x%x\n", 4838c2ecf20Sopenharmony_ci __func__, 4848c2ecf20Sopenharmony_ci *len, jeb->offset + (c->sector_size - jeb->free_size)); 4858c2ecf20Sopenharmony_ci return 0; 4868c2ecf20Sopenharmony_ci} 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci/** 4898c2ecf20Sopenharmony_ci * jffs2_add_physical_node_ref - add a physical node reference to the list 4908c2ecf20Sopenharmony_ci * @c: superblock info 4918c2ecf20Sopenharmony_ci * @new: new node reference to add 4928c2ecf20Sopenharmony_ci * @len: length of this physical node 4938c2ecf20Sopenharmony_ci * 4948c2ecf20Sopenharmony_ci * Should only be used to report nodes for which space has been allocated 4958c2ecf20Sopenharmony_ci * by jffs2_reserve_space. 4968c2ecf20Sopenharmony_ci * 4978c2ecf20Sopenharmony_ci * Must be called with the alloc_sem held. 4988c2ecf20Sopenharmony_ci */ 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_cistruct jffs2_raw_node_ref *jffs2_add_physical_node_ref(struct jffs2_sb_info *c, 5018c2ecf20Sopenharmony_ci uint32_t ofs, uint32_t len, 5028c2ecf20Sopenharmony_ci struct jffs2_inode_cache *ic) 5038c2ecf20Sopenharmony_ci{ 5048c2ecf20Sopenharmony_ci struct jffs2_eraseblock *jeb; 5058c2ecf20Sopenharmony_ci struct jffs2_raw_node_ref *new; 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci jeb = &c->blocks[ofs / c->sector_size]; 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci jffs2_dbg(1, "%s(): Node at 0x%x(%d), size 0x%x\n", 5108c2ecf20Sopenharmony_ci __func__, ofs & ~3, ofs & 3, len); 5118c2ecf20Sopenharmony_ci#if 1 5128c2ecf20Sopenharmony_ci /* Allow non-obsolete nodes only to be added at the end of c->nextblock, 5138c2ecf20Sopenharmony_ci if c->nextblock is set. Note that wbuf.c will file obsolete nodes 5148c2ecf20Sopenharmony_ci even after refiling c->nextblock */ 5158c2ecf20Sopenharmony_ci if ((c->nextblock || ((ofs & 3) != REF_OBSOLETE)) 5168c2ecf20Sopenharmony_ci && (jeb != c->nextblock || (ofs & ~3) != jeb->offset + (c->sector_size - jeb->free_size))) { 5178c2ecf20Sopenharmony_ci pr_warn("argh. node added in wrong place at 0x%08x(%d)\n", 5188c2ecf20Sopenharmony_ci ofs & ~3, ofs & 3); 5198c2ecf20Sopenharmony_ci if (c->nextblock) 5208c2ecf20Sopenharmony_ci pr_warn("nextblock 0x%08x", c->nextblock->offset); 5218c2ecf20Sopenharmony_ci else 5228c2ecf20Sopenharmony_ci pr_warn("No nextblock"); 5238c2ecf20Sopenharmony_ci pr_cont(", expected at %08x\n", 5248c2ecf20Sopenharmony_ci jeb->offset + (c->sector_size - jeb->free_size)); 5258c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 5268c2ecf20Sopenharmony_ci } 5278c2ecf20Sopenharmony_ci#endif 5288c2ecf20Sopenharmony_ci spin_lock(&c->erase_completion_lock); 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci new = jffs2_link_node_ref(c, jeb, ofs, len, ic); 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci if (!jeb->free_size && !jeb->dirty_size && !ISDIRTY(jeb->wasted_size)) { 5338c2ecf20Sopenharmony_ci /* If it lives on the dirty_list, jffs2_reserve_space will put it there */ 5348c2ecf20Sopenharmony_ci jffs2_dbg(1, "Adding full erase block at 0x%08x to clean_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n", 5358c2ecf20Sopenharmony_ci jeb->offset, jeb->free_size, jeb->dirty_size, 5368c2ecf20Sopenharmony_ci jeb->used_size); 5378c2ecf20Sopenharmony_ci if (jffs2_wbuf_dirty(c)) { 5388c2ecf20Sopenharmony_ci /* Flush the last write in the block if it's outstanding */ 5398c2ecf20Sopenharmony_ci spin_unlock(&c->erase_completion_lock); 5408c2ecf20Sopenharmony_ci jffs2_flush_wbuf_pad(c); 5418c2ecf20Sopenharmony_ci spin_lock(&c->erase_completion_lock); 5428c2ecf20Sopenharmony_ci } 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci list_add_tail(&jeb->list, &c->clean_list); 5458c2ecf20Sopenharmony_ci c->nextblock = NULL; 5468c2ecf20Sopenharmony_ci } 5478c2ecf20Sopenharmony_ci jffs2_dbg_acct_sanity_check_nolock(c,jeb); 5488c2ecf20Sopenharmony_ci jffs2_dbg_acct_paranoia_check_nolock(c, jeb); 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci spin_unlock(&c->erase_completion_lock); 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci return new; 5538c2ecf20Sopenharmony_ci} 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_civoid jffs2_complete_reservation(struct jffs2_sb_info *c) 5578c2ecf20Sopenharmony_ci{ 5588c2ecf20Sopenharmony_ci jffs2_dbg(1, "jffs2_complete_reservation()\n"); 5598c2ecf20Sopenharmony_ci spin_lock(&c->erase_completion_lock); 5608c2ecf20Sopenharmony_ci jffs2_garbage_collect_trigger(c); 5618c2ecf20Sopenharmony_ci spin_unlock(&c->erase_completion_lock); 5628c2ecf20Sopenharmony_ci mutex_unlock(&c->alloc_sem); 5638c2ecf20Sopenharmony_ci} 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_cistatic inline int on_list(struct list_head *obj, struct list_head *head) 5668c2ecf20Sopenharmony_ci{ 5678c2ecf20Sopenharmony_ci struct list_head *this; 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci list_for_each(this, head) { 5708c2ecf20Sopenharmony_ci if (this == obj) { 5718c2ecf20Sopenharmony_ci jffs2_dbg(1, "%p is on list at %p\n", obj, head); 5728c2ecf20Sopenharmony_ci return 1; 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci } 5758c2ecf20Sopenharmony_ci } 5768c2ecf20Sopenharmony_ci return 0; 5778c2ecf20Sopenharmony_ci} 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_civoid jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *ref) 5808c2ecf20Sopenharmony_ci{ 5818c2ecf20Sopenharmony_ci struct jffs2_eraseblock *jeb; 5828c2ecf20Sopenharmony_ci int blocknr; 5838c2ecf20Sopenharmony_ci struct jffs2_unknown_node n; 5848c2ecf20Sopenharmony_ci int ret, addedsize; 5858c2ecf20Sopenharmony_ci size_t retlen; 5868c2ecf20Sopenharmony_ci uint32_t freed_len; 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci if(unlikely(!ref)) { 5898c2ecf20Sopenharmony_ci pr_notice("EEEEEK. jffs2_mark_node_obsolete called with NULL node\n"); 5908c2ecf20Sopenharmony_ci return; 5918c2ecf20Sopenharmony_ci } 5928c2ecf20Sopenharmony_ci if (ref_obsolete(ref)) { 5938c2ecf20Sopenharmony_ci jffs2_dbg(1, "%s(): called with already obsolete node at 0x%08x\n", 5948c2ecf20Sopenharmony_ci __func__, ref_offset(ref)); 5958c2ecf20Sopenharmony_ci return; 5968c2ecf20Sopenharmony_ci } 5978c2ecf20Sopenharmony_ci blocknr = ref->flash_offset / c->sector_size; 5988c2ecf20Sopenharmony_ci if (blocknr >= c->nr_blocks) { 5998c2ecf20Sopenharmony_ci pr_notice("raw node at 0x%08x is off the end of device!\n", 6008c2ecf20Sopenharmony_ci ref->flash_offset); 6018c2ecf20Sopenharmony_ci BUG(); 6028c2ecf20Sopenharmony_ci } 6038c2ecf20Sopenharmony_ci jeb = &c->blocks[blocknr]; 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci if (jffs2_can_mark_obsolete(c) && !jffs2_is_readonly(c) && 6068c2ecf20Sopenharmony_ci !(c->flags & (JFFS2_SB_FLAG_SCANNING | JFFS2_SB_FLAG_BUILDING))) { 6078c2ecf20Sopenharmony_ci /* Hm. This may confuse static lock analysis. If any of the above 6088c2ecf20Sopenharmony_ci three conditions is false, we're going to return from this 6098c2ecf20Sopenharmony_ci function without actually obliterating any nodes or freeing 6108c2ecf20Sopenharmony_ci any jffs2_raw_node_refs. So we don't need to stop erases from 6118c2ecf20Sopenharmony_ci happening, or protect against people holding an obsolete 6128c2ecf20Sopenharmony_ci jffs2_raw_node_ref without the erase_completion_lock. */ 6138c2ecf20Sopenharmony_ci mutex_lock(&c->erase_free_sem); 6148c2ecf20Sopenharmony_ci } 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci spin_lock(&c->erase_completion_lock); 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci freed_len = ref_totlen(c, jeb, ref); 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci if (ref_flags(ref) == REF_UNCHECKED) { 6218c2ecf20Sopenharmony_ci D1(if (unlikely(jeb->unchecked_size < freed_len)) { 6228c2ecf20Sopenharmony_ci pr_notice("raw unchecked node of size 0x%08x freed from erase block %d at 0x%08x, but unchecked_size was already 0x%08x\n", 6238c2ecf20Sopenharmony_ci freed_len, blocknr, 6248c2ecf20Sopenharmony_ci ref->flash_offset, jeb->used_size); 6258c2ecf20Sopenharmony_ci BUG(); 6268c2ecf20Sopenharmony_ci }) 6278c2ecf20Sopenharmony_ci jffs2_dbg(1, "Obsoleting previously unchecked node at 0x%08x of len %x\n", 6288c2ecf20Sopenharmony_ci ref_offset(ref), freed_len); 6298c2ecf20Sopenharmony_ci jeb->unchecked_size -= freed_len; 6308c2ecf20Sopenharmony_ci c->unchecked_size -= freed_len; 6318c2ecf20Sopenharmony_ci } else { 6328c2ecf20Sopenharmony_ci D1(if (unlikely(jeb->used_size < freed_len)) { 6338c2ecf20Sopenharmony_ci pr_notice("raw node of size 0x%08x freed from erase block %d at 0x%08x, but used_size was already 0x%08x\n", 6348c2ecf20Sopenharmony_ci freed_len, blocknr, 6358c2ecf20Sopenharmony_ci ref->flash_offset, jeb->used_size); 6368c2ecf20Sopenharmony_ci BUG(); 6378c2ecf20Sopenharmony_ci }) 6388c2ecf20Sopenharmony_ci jffs2_dbg(1, "Obsoleting node at 0x%08x of len %#x: ", 6398c2ecf20Sopenharmony_ci ref_offset(ref), freed_len); 6408c2ecf20Sopenharmony_ci jeb->used_size -= freed_len; 6418c2ecf20Sopenharmony_ci c->used_size -= freed_len; 6428c2ecf20Sopenharmony_ci } 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci // Take care, that wasted size is taken into concern 6458c2ecf20Sopenharmony_ci if ((jeb->dirty_size || ISDIRTY(jeb->wasted_size + freed_len)) && jeb != c->nextblock) { 6468c2ecf20Sopenharmony_ci jffs2_dbg(1, "Dirtying\n"); 6478c2ecf20Sopenharmony_ci addedsize = freed_len; 6488c2ecf20Sopenharmony_ci jeb->dirty_size += freed_len; 6498c2ecf20Sopenharmony_ci c->dirty_size += freed_len; 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci /* Convert wasted space to dirty, if not a bad block */ 6528c2ecf20Sopenharmony_ci if (jeb->wasted_size) { 6538c2ecf20Sopenharmony_ci if (on_list(&jeb->list, &c->bad_used_list)) { 6548c2ecf20Sopenharmony_ci jffs2_dbg(1, "Leaving block at %08x on the bad_used_list\n", 6558c2ecf20Sopenharmony_ci jeb->offset); 6568c2ecf20Sopenharmony_ci addedsize = 0; /* To fool the refiling code later */ 6578c2ecf20Sopenharmony_ci } else { 6588c2ecf20Sopenharmony_ci jffs2_dbg(1, "Converting %d bytes of wasted space to dirty in block at %08x\n", 6598c2ecf20Sopenharmony_ci jeb->wasted_size, jeb->offset); 6608c2ecf20Sopenharmony_ci addedsize += jeb->wasted_size; 6618c2ecf20Sopenharmony_ci jeb->dirty_size += jeb->wasted_size; 6628c2ecf20Sopenharmony_ci c->dirty_size += jeb->wasted_size; 6638c2ecf20Sopenharmony_ci c->wasted_size -= jeb->wasted_size; 6648c2ecf20Sopenharmony_ci jeb->wasted_size = 0; 6658c2ecf20Sopenharmony_ci } 6668c2ecf20Sopenharmony_ci } 6678c2ecf20Sopenharmony_ci } else { 6688c2ecf20Sopenharmony_ci jffs2_dbg(1, "Wasting\n"); 6698c2ecf20Sopenharmony_ci addedsize = 0; 6708c2ecf20Sopenharmony_ci jeb->wasted_size += freed_len; 6718c2ecf20Sopenharmony_ci c->wasted_size += freed_len; 6728c2ecf20Sopenharmony_ci } 6738c2ecf20Sopenharmony_ci ref->flash_offset = ref_offset(ref) | REF_OBSOLETE; 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci jffs2_dbg_acct_sanity_check_nolock(c, jeb); 6768c2ecf20Sopenharmony_ci jffs2_dbg_acct_paranoia_check_nolock(c, jeb); 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci if (c->flags & JFFS2_SB_FLAG_SCANNING) { 6798c2ecf20Sopenharmony_ci /* Flash scanning is in progress. Don't muck about with the block 6808c2ecf20Sopenharmony_ci lists because they're not ready yet, and don't actually 6818c2ecf20Sopenharmony_ci obliterate nodes that look obsolete. If they weren't 6828c2ecf20Sopenharmony_ci marked obsolete on the flash at the time they _became_ 6838c2ecf20Sopenharmony_ci obsolete, there was probably a reason for that. */ 6848c2ecf20Sopenharmony_ci spin_unlock(&c->erase_completion_lock); 6858c2ecf20Sopenharmony_ci /* We didn't lock the erase_free_sem */ 6868c2ecf20Sopenharmony_ci return; 6878c2ecf20Sopenharmony_ci } 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci if (jeb == c->nextblock) { 6908c2ecf20Sopenharmony_ci jffs2_dbg(2, "Not moving nextblock 0x%08x to dirty/erase_pending list\n", 6918c2ecf20Sopenharmony_ci jeb->offset); 6928c2ecf20Sopenharmony_ci } else if (!jeb->used_size && !jeb->unchecked_size) { 6938c2ecf20Sopenharmony_ci if (jeb == c->gcblock) { 6948c2ecf20Sopenharmony_ci jffs2_dbg(1, "gcblock at 0x%08x completely dirtied. Clearing gcblock...\n", 6958c2ecf20Sopenharmony_ci jeb->offset); 6968c2ecf20Sopenharmony_ci c->gcblock = NULL; 6978c2ecf20Sopenharmony_ci } else { 6988c2ecf20Sopenharmony_ci jffs2_dbg(1, "Eraseblock at 0x%08x completely dirtied. Removing from (dirty?) list...\n", 6998c2ecf20Sopenharmony_ci jeb->offset); 7008c2ecf20Sopenharmony_ci list_del(&jeb->list); 7018c2ecf20Sopenharmony_ci } 7028c2ecf20Sopenharmony_ci if (jffs2_wbuf_dirty(c)) { 7038c2ecf20Sopenharmony_ci jffs2_dbg(1, "...and adding to erasable_pending_wbuf_list\n"); 7048c2ecf20Sopenharmony_ci list_add_tail(&jeb->list, &c->erasable_pending_wbuf_list); 7058c2ecf20Sopenharmony_ci } else { 7068c2ecf20Sopenharmony_ci if (jiffies & 127) { 7078c2ecf20Sopenharmony_ci /* Most of the time, we just erase it immediately. Otherwise we 7088c2ecf20Sopenharmony_ci spend ages scanning it on mount, etc. */ 7098c2ecf20Sopenharmony_ci jffs2_dbg(1, "...and adding to erase_pending_list\n"); 7108c2ecf20Sopenharmony_ci list_add_tail(&jeb->list, &c->erase_pending_list); 7118c2ecf20Sopenharmony_ci c->nr_erasing_blocks++; 7128c2ecf20Sopenharmony_ci jffs2_garbage_collect_trigger(c); 7138c2ecf20Sopenharmony_ci } else { 7148c2ecf20Sopenharmony_ci /* Sometimes, however, we leave it elsewhere so it doesn't get 7158c2ecf20Sopenharmony_ci immediately reused, and we spread the load a bit. */ 7168c2ecf20Sopenharmony_ci jffs2_dbg(1, "...and adding to erasable_list\n"); 7178c2ecf20Sopenharmony_ci list_add_tail(&jeb->list, &c->erasable_list); 7188c2ecf20Sopenharmony_ci } 7198c2ecf20Sopenharmony_ci } 7208c2ecf20Sopenharmony_ci jffs2_dbg(1, "Done OK\n"); 7218c2ecf20Sopenharmony_ci } else if (jeb == c->gcblock) { 7228c2ecf20Sopenharmony_ci jffs2_dbg(2, "Not moving gcblock 0x%08x to dirty_list\n", 7238c2ecf20Sopenharmony_ci jeb->offset); 7248c2ecf20Sopenharmony_ci } else if (ISDIRTY(jeb->dirty_size) && !ISDIRTY(jeb->dirty_size - addedsize)) { 7258c2ecf20Sopenharmony_ci jffs2_dbg(1, "Eraseblock at 0x%08x is freshly dirtied. Removing from clean list...\n", 7268c2ecf20Sopenharmony_ci jeb->offset); 7278c2ecf20Sopenharmony_ci list_del(&jeb->list); 7288c2ecf20Sopenharmony_ci jffs2_dbg(1, "...and adding to dirty_list\n"); 7298c2ecf20Sopenharmony_ci list_add_tail(&jeb->list, &c->dirty_list); 7308c2ecf20Sopenharmony_ci } else if (VERYDIRTY(c, jeb->dirty_size) && 7318c2ecf20Sopenharmony_ci !VERYDIRTY(c, jeb->dirty_size - addedsize)) { 7328c2ecf20Sopenharmony_ci jffs2_dbg(1, "Eraseblock at 0x%08x is now very dirty. Removing from dirty list...\n", 7338c2ecf20Sopenharmony_ci jeb->offset); 7348c2ecf20Sopenharmony_ci list_del(&jeb->list); 7358c2ecf20Sopenharmony_ci jffs2_dbg(1, "...and adding to very_dirty_list\n"); 7368c2ecf20Sopenharmony_ci list_add_tail(&jeb->list, &c->very_dirty_list); 7378c2ecf20Sopenharmony_ci } else { 7388c2ecf20Sopenharmony_ci jffs2_dbg(1, "Eraseblock at 0x%08x not moved anywhere. (free 0x%08x, dirty 0x%08x, used 0x%08x)\n", 7398c2ecf20Sopenharmony_ci jeb->offset, jeb->free_size, jeb->dirty_size, 7408c2ecf20Sopenharmony_ci jeb->used_size); 7418c2ecf20Sopenharmony_ci } 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci spin_unlock(&c->erase_completion_lock); 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci if (!jffs2_can_mark_obsolete(c) || jffs2_is_readonly(c) || 7468c2ecf20Sopenharmony_ci (c->flags & JFFS2_SB_FLAG_BUILDING)) { 7478c2ecf20Sopenharmony_ci /* We didn't lock the erase_free_sem */ 7488c2ecf20Sopenharmony_ci return; 7498c2ecf20Sopenharmony_ci } 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci /* The erase_free_sem is locked, and has been since before we marked the node obsolete 7528c2ecf20Sopenharmony_ci and potentially put its eraseblock onto the erase_pending_list. Thus, we know that 7538c2ecf20Sopenharmony_ci the block hasn't _already_ been erased, and that 'ref' itself hasn't been freed yet 7548c2ecf20Sopenharmony_ci by jffs2_free_jeb_node_refs() in erase.c. Which is nice. */ 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci jffs2_dbg(1, "obliterating obsoleted node at 0x%08x\n", 7578c2ecf20Sopenharmony_ci ref_offset(ref)); 7588c2ecf20Sopenharmony_ci ret = jffs2_flash_read(c, ref_offset(ref), sizeof(n), &retlen, (char *)&n); 7598c2ecf20Sopenharmony_ci if (ret) { 7608c2ecf20Sopenharmony_ci pr_warn("Read error reading from obsoleted node at 0x%08x: %d\n", 7618c2ecf20Sopenharmony_ci ref_offset(ref), ret); 7628c2ecf20Sopenharmony_ci goto out_erase_sem; 7638c2ecf20Sopenharmony_ci } 7648c2ecf20Sopenharmony_ci if (retlen != sizeof(n)) { 7658c2ecf20Sopenharmony_ci pr_warn("Short read from obsoleted node at 0x%08x: %zd\n", 7668c2ecf20Sopenharmony_ci ref_offset(ref), retlen); 7678c2ecf20Sopenharmony_ci goto out_erase_sem; 7688c2ecf20Sopenharmony_ci } 7698c2ecf20Sopenharmony_ci if (PAD(je32_to_cpu(n.totlen)) != PAD(freed_len)) { 7708c2ecf20Sopenharmony_ci pr_warn("Node totlen on flash (0x%08x) != totlen from node ref (0x%08x)\n", 7718c2ecf20Sopenharmony_ci je32_to_cpu(n.totlen), freed_len); 7728c2ecf20Sopenharmony_ci goto out_erase_sem; 7738c2ecf20Sopenharmony_ci } 7748c2ecf20Sopenharmony_ci if (!(je16_to_cpu(n.nodetype) & JFFS2_NODE_ACCURATE)) { 7758c2ecf20Sopenharmony_ci jffs2_dbg(1, "Node at 0x%08x was already marked obsolete (nodetype 0x%04x)\n", 7768c2ecf20Sopenharmony_ci ref_offset(ref), je16_to_cpu(n.nodetype)); 7778c2ecf20Sopenharmony_ci goto out_erase_sem; 7788c2ecf20Sopenharmony_ci } 7798c2ecf20Sopenharmony_ci /* XXX FIXME: This is ugly now */ 7808c2ecf20Sopenharmony_ci n.nodetype = cpu_to_je16(je16_to_cpu(n.nodetype) & ~JFFS2_NODE_ACCURATE); 7818c2ecf20Sopenharmony_ci ret = jffs2_flash_write(c, ref_offset(ref), sizeof(n), &retlen, (char *)&n); 7828c2ecf20Sopenharmony_ci if (ret) { 7838c2ecf20Sopenharmony_ci pr_warn("Write error in obliterating obsoleted node at 0x%08x: %d\n", 7848c2ecf20Sopenharmony_ci ref_offset(ref), ret); 7858c2ecf20Sopenharmony_ci goto out_erase_sem; 7868c2ecf20Sopenharmony_ci } 7878c2ecf20Sopenharmony_ci if (retlen != sizeof(n)) { 7888c2ecf20Sopenharmony_ci pr_warn("Short write in obliterating obsoleted node at 0x%08x: %zd\n", 7898c2ecf20Sopenharmony_ci ref_offset(ref), retlen); 7908c2ecf20Sopenharmony_ci goto out_erase_sem; 7918c2ecf20Sopenharmony_ci } 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci /* Nodes which have been marked obsolete no longer need to be 7948c2ecf20Sopenharmony_ci associated with any inode. Remove them from the per-inode list. 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci Note we can't do this for NAND at the moment because we need 7978c2ecf20Sopenharmony_ci obsolete dirent nodes to stay on the lists, because of the 7988c2ecf20Sopenharmony_ci horridness in jffs2_garbage_collect_deletion_dirent(). Also 7998c2ecf20Sopenharmony_ci because we delete the inocache, and on NAND we need that to 8008c2ecf20Sopenharmony_ci stay around until all the nodes are actually erased, in order 8018c2ecf20Sopenharmony_ci to stop us from giving the same inode number to another newly 8028c2ecf20Sopenharmony_ci created inode. */ 8038c2ecf20Sopenharmony_ci if (ref->next_in_ino) { 8048c2ecf20Sopenharmony_ci struct jffs2_inode_cache *ic; 8058c2ecf20Sopenharmony_ci struct jffs2_raw_node_ref **p; 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_ci spin_lock(&c->erase_completion_lock); 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci ic = jffs2_raw_ref_to_ic(ref); 8108c2ecf20Sopenharmony_ci for (p = &ic->nodes; (*p) != ref; p = &((*p)->next_in_ino)) 8118c2ecf20Sopenharmony_ci ; 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_ci *p = ref->next_in_ino; 8148c2ecf20Sopenharmony_ci ref->next_in_ino = NULL; 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci switch (ic->class) { 8178c2ecf20Sopenharmony_ci#ifdef CONFIG_JFFS2_FS_XATTR 8188c2ecf20Sopenharmony_ci case RAWNODE_CLASS_XATTR_DATUM: 8198c2ecf20Sopenharmony_ci jffs2_release_xattr_datum(c, (struct jffs2_xattr_datum *)ic); 8208c2ecf20Sopenharmony_ci break; 8218c2ecf20Sopenharmony_ci case RAWNODE_CLASS_XATTR_REF: 8228c2ecf20Sopenharmony_ci jffs2_release_xattr_ref(c, (struct jffs2_xattr_ref *)ic); 8238c2ecf20Sopenharmony_ci break; 8248c2ecf20Sopenharmony_ci#endif 8258c2ecf20Sopenharmony_ci default: 8268c2ecf20Sopenharmony_ci if (ic->nodes == (void *)ic && ic->pino_nlink == 0) 8278c2ecf20Sopenharmony_ci jffs2_del_ino_cache(c, ic); 8288c2ecf20Sopenharmony_ci break; 8298c2ecf20Sopenharmony_ci } 8308c2ecf20Sopenharmony_ci spin_unlock(&c->erase_completion_lock); 8318c2ecf20Sopenharmony_ci } 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci out_erase_sem: 8348c2ecf20Sopenharmony_ci mutex_unlock(&c->erase_free_sem); 8358c2ecf20Sopenharmony_ci} 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ciint jffs2_thread_should_wake(struct jffs2_sb_info *c) 8388c2ecf20Sopenharmony_ci{ 8398c2ecf20Sopenharmony_ci int ret = 0; 8408c2ecf20Sopenharmony_ci uint32_t dirty; 8418c2ecf20Sopenharmony_ci int nr_very_dirty = 0; 8428c2ecf20Sopenharmony_ci struct jffs2_eraseblock *jeb; 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci if (!list_empty(&c->erase_complete_list) || 8458c2ecf20Sopenharmony_ci !list_empty(&c->erase_pending_list)) 8468c2ecf20Sopenharmony_ci return 1; 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci if (c->unchecked_size) { 8498c2ecf20Sopenharmony_ci jffs2_dbg(1, "jffs2_thread_should_wake(): unchecked_size %d, check_ino #%d\n", 8508c2ecf20Sopenharmony_ci c->unchecked_size, c->check_ino); 8518c2ecf20Sopenharmony_ci return 1; 8528c2ecf20Sopenharmony_ci } 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci /* dirty_size contains blocks on erase_pending_list 8558c2ecf20Sopenharmony_ci * those blocks are counted in c->nr_erasing_blocks. 8568c2ecf20Sopenharmony_ci * If one block is actually erased, it is not longer counted as dirty_space 8578c2ecf20Sopenharmony_ci * but it is counted in c->nr_erasing_blocks, so we add it and subtract it 8588c2ecf20Sopenharmony_ci * with c->nr_erasing_blocks * c->sector_size again. 8598c2ecf20Sopenharmony_ci * Blocks on erasable_list are counted as dirty_size, but not in c->nr_erasing_blocks 8608c2ecf20Sopenharmony_ci * This helps us to force gc and pick eventually a clean block to spread the load. 8618c2ecf20Sopenharmony_ci */ 8628c2ecf20Sopenharmony_ci dirty = c->dirty_size + c->erasing_size - c->nr_erasing_blocks * c->sector_size; 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci if (c->nr_free_blocks + c->nr_erasing_blocks < c->resv_blocks_gctrigger && 8658c2ecf20Sopenharmony_ci (dirty > c->nospc_dirty_size)) 8668c2ecf20Sopenharmony_ci ret = 1; 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci list_for_each_entry(jeb, &c->very_dirty_list, list) { 8698c2ecf20Sopenharmony_ci nr_very_dirty++; 8708c2ecf20Sopenharmony_ci if (nr_very_dirty == c->vdirty_blocks_gctrigger) { 8718c2ecf20Sopenharmony_ci ret = 1; 8728c2ecf20Sopenharmony_ci /* In debug mode, actually go through and count them all */ 8738c2ecf20Sopenharmony_ci D1(continue); 8748c2ecf20Sopenharmony_ci break; 8758c2ecf20Sopenharmony_ci } 8768c2ecf20Sopenharmony_ci } 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci jffs2_dbg(1, "%s(): nr_free_blocks %d, nr_erasing_blocks %d, dirty_size 0x%x, vdirty_blocks %d: %s\n", 8798c2ecf20Sopenharmony_ci __func__, c->nr_free_blocks, c->nr_erasing_blocks, 8808c2ecf20Sopenharmony_ci c->dirty_size, nr_very_dirty, ret ? "yes" : "no"); 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci return ret; 8838c2ecf20Sopenharmony_ci} 884