162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * JFFS2 -- Journalling Flash File System, Version 2. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright © 2001-2007 Red Hat, Inc. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Created by David Woodhouse <dwmw2@infradead.org> 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * For licensing information, see the file 'LICENCE' in this directory. 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include <linux/kernel.h> 1562306a36Sopenharmony_ci#include <linux/mtd/mtd.h> 1662306a36Sopenharmony_ci#include <linux/compiler.h> 1762306a36Sopenharmony_ci#include <linux/sched/signal.h> 1862306a36Sopenharmony_ci#include "nodelist.h" 1962306a36Sopenharmony_ci#include "debug.h" 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci/* 2262306a36Sopenharmony_ci * Check whether the user is allowed to write. 2362306a36Sopenharmony_ci */ 2462306a36Sopenharmony_cistatic int jffs2_rp_can_write(struct jffs2_sb_info *c) 2562306a36Sopenharmony_ci{ 2662306a36Sopenharmony_ci uint32_t avail; 2762306a36Sopenharmony_ci struct jffs2_mount_opts *opts = &c->mount_opts; 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci avail = c->dirty_size + c->free_size + c->unchecked_size + 3062306a36Sopenharmony_ci c->erasing_size - c->resv_blocks_write * c->sector_size 3162306a36Sopenharmony_ci - c->nospc_dirty_size; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci if (avail < 2 * opts->rp_size) 3462306a36Sopenharmony_ci jffs2_dbg(1, "rpsize %u, dirty_size %u, free_size %u, " 3562306a36Sopenharmony_ci "erasing_size %u, unchecked_size %u, " 3662306a36Sopenharmony_ci "nr_erasing_blocks %u, avail %u, resrv %u\n", 3762306a36Sopenharmony_ci opts->rp_size, c->dirty_size, c->free_size, 3862306a36Sopenharmony_ci c->erasing_size, c->unchecked_size, 3962306a36Sopenharmony_ci c->nr_erasing_blocks, avail, c->nospc_dirty_size); 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci if (avail > opts->rp_size) 4262306a36Sopenharmony_ci return 1; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci /* Always allow root */ 4562306a36Sopenharmony_ci if (capable(CAP_SYS_RESOURCE)) 4662306a36Sopenharmony_ci return 1; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci jffs2_dbg(1, "forbid writing\n"); 4962306a36Sopenharmony_ci return 0; 5062306a36Sopenharmony_ci} 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci/** 5362306a36Sopenharmony_ci * jffs2_reserve_space - request physical space to write nodes to flash 5462306a36Sopenharmony_ci * @c: superblock info 5562306a36Sopenharmony_ci * @minsize: Minimum acceptable size of allocation 5662306a36Sopenharmony_ci * @len: Returned value of allocation length 5762306a36Sopenharmony_ci * @prio: Allocation type - ALLOC_{NORMAL,DELETION} 5862306a36Sopenharmony_ci * 5962306a36Sopenharmony_ci * Requests a block of physical space on the flash. Returns zero for success 6062306a36Sopenharmony_ci * and puts 'len' into the appropriate place, or returns -ENOSPC or other 6162306a36Sopenharmony_ci * error if appropriate. Doesn't return len since that's 6262306a36Sopenharmony_ci * 6362306a36Sopenharmony_ci * If it returns zero, jffs2_reserve_space() also downs the per-filesystem 6462306a36Sopenharmony_ci * allocation semaphore, to prevent more than one allocation from being 6562306a36Sopenharmony_ci * active at any time. The semaphore is later released by jffs2_commit_allocation() 6662306a36Sopenharmony_ci * 6762306a36Sopenharmony_ci * jffs2_reserve_space() may trigger garbage collection in order to make room 6862306a36Sopenharmony_ci * for the requested allocation. 6962306a36Sopenharmony_ci */ 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cistatic int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, 7262306a36Sopenharmony_ci uint32_t *len, uint32_t sumsize); 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ciint jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, 7562306a36Sopenharmony_ci uint32_t *len, int prio, uint32_t sumsize) 7662306a36Sopenharmony_ci{ 7762306a36Sopenharmony_ci int ret = -EAGAIN; 7862306a36Sopenharmony_ci int blocksneeded = c->resv_blocks_write; 7962306a36Sopenharmony_ci /* align it */ 8062306a36Sopenharmony_ci minsize = PAD(minsize); 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci jffs2_dbg(1, "%s(): Requested 0x%x bytes\n", __func__, minsize); 8362306a36Sopenharmony_ci mutex_lock(&c->alloc_sem); 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci jffs2_dbg(1, "%s(): alloc sem got\n", __func__); 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci spin_lock(&c->erase_completion_lock); 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci /* 9062306a36Sopenharmony_ci * Check if the free space is greater then size of the reserved pool. 9162306a36Sopenharmony_ci * If not, only allow root to proceed with writing. 9262306a36Sopenharmony_ci */ 9362306a36Sopenharmony_ci if (prio != ALLOC_DELETION && !jffs2_rp_can_write(c)) { 9462306a36Sopenharmony_ci ret = -ENOSPC; 9562306a36Sopenharmony_ci goto out; 9662306a36Sopenharmony_ci } 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci /* this needs a little more thought (true <tglx> :)) */ 9962306a36Sopenharmony_ci while(ret == -EAGAIN) { 10062306a36Sopenharmony_ci while(c->nr_free_blocks + c->nr_erasing_blocks < blocksneeded) { 10162306a36Sopenharmony_ci uint32_t dirty, avail; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci /* calculate real dirty size 10462306a36Sopenharmony_ci * dirty_size contains blocks on erase_pending_list 10562306a36Sopenharmony_ci * those blocks are counted in c->nr_erasing_blocks. 10662306a36Sopenharmony_ci * If one block is actually erased, it is not longer counted as dirty_space 10762306a36Sopenharmony_ci * but it is counted in c->nr_erasing_blocks, so we add it and subtract it 10862306a36Sopenharmony_ci * with c->nr_erasing_blocks * c->sector_size again. 10962306a36Sopenharmony_ci * Blocks on erasable_list are counted as dirty_size, but not in c->nr_erasing_blocks 11062306a36Sopenharmony_ci * This helps us to force gc and pick eventually a clean block to spread the load. 11162306a36Sopenharmony_ci * We add unchecked_size here, as we hopefully will find some space to use. 11262306a36Sopenharmony_ci * This will affect the sum only once, as gc first finishes checking 11362306a36Sopenharmony_ci * of nodes. 11462306a36Sopenharmony_ci */ 11562306a36Sopenharmony_ci dirty = c->dirty_size + c->erasing_size - c->nr_erasing_blocks * c->sector_size + c->unchecked_size; 11662306a36Sopenharmony_ci if (dirty < c->nospc_dirty_size) { 11762306a36Sopenharmony_ci if (prio == ALLOC_DELETION && c->nr_free_blocks + c->nr_erasing_blocks >= c->resv_blocks_deletion) { 11862306a36Sopenharmony_ci jffs2_dbg(1, "%s(): Low on dirty space to GC, but it's a deletion. Allowing...\n", 11962306a36Sopenharmony_ci __func__); 12062306a36Sopenharmony_ci break; 12162306a36Sopenharmony_ci } 12262306a36Sopenharmony_ci jffs2_dbg(1, "dirty size 0x%08x + unchecked_size 0x%08x < nospc_dirty_size 0x%08x, returning -ENOSPC\n", 12362306a36Sopenharmony_ci dirty, c->unchecked_size, 12462306a36Sopenharmony_ci c->sector_size); 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci spin_unlock(&c->erase_completion_lock); 12762306a36Sopenharmony_ci mutex_unlock(&c->alloc_sem); 12862306a36Sopenharmony_ci return -ENOSPC; 12962306a36Sopenharmony_ci } 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci /* Calc possibly available space. Possibly available means that we 13262306a36Sopenharmony_ci * don't know, if unchecked size contains obsoleted nodes, which could give us some 13362306a36Sopenharmony_ci * more usable space. This will affect the sum only once, as gc first finishes checking 13462306a36Sopenharmony_ci * of nodes. 13562306a36Sopenharmony_ci + Return -ENOSPC, if the maximum possibly available space is less or equal than 13662306a36Sopenharmony_ci * blocksneeded * sector_size. 13762306a36Sopenharmony_ci * This blocks endless gc looping on a filesystem, which is nearly full, even if 13862306a36Sopenharmony_ci * the check above passes. 13962306a36Sopenharmony_ci */ 14062306a36Sopenharmony_ci avail = c->free_size + c->dirty_size + c->erasing_size + c->unchecked_size; 14162306a36Sopenharmony_ci if ( (avail / c->sector_size) <= blocksneeded) { 14262306a36Sopenharmony_ci if (prio == ALLOC_DELETION && c->nr_free_blocks + c->nr_erasing_blocks >= c->resv_blocks_deletion) { 14362306a36Sopenharmony_ci jffs2_dbg(1, "%s(): Low on possibly available space, but it's a deletion. Allowing...\n", 14462306a36Sopenharmony_ci __func__); 14562306a36Sopenharmony_ci break; 14662306a36Sopenharmony_ci } 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci jffs2_dbg(1, "max. available size 0x%08x < blocksneeded * sector_size 0x%08x, returning -ENOSPC\n", 14962306a36Sopenharmony_ci avail, blocksneeded * c->sector_size); 15062306a36Sopenharmony_ci spin_unlock(&c->erase_completion_lock); 15162306a36Sopenharmony_ci mutex_unlock(&c->alloc_sem); 15262306a36Sopenharmony_ci return -ENOSPC; 15362306a36Sopenharmony_ci } 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci mutex_unlock(&c->alloc_sem); 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_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", 15862306a36Sopenharmony_ci c->nr_free_blocks, c->nr_erasing_blocks, 15962306a36Sopenharmony_ci c->free_size, c->dirty_size, c->wasted_size, 16062306a36Sopenharmony_ci c->used_size, c->erasing_size, c->bad_size, 16162306a36Sopenharmony_ci c->free_size + c->dirty_size + 16262306a36Sopenharmony_ci c->wasted_size + c->used_size + 16362306a36Sopenharmony_ci c->erasing_size + c->bad_size, 16462306a36Sopenharmony_ci c->flash_size); 16562306a36Sopenharmony_ci spin_unlock(&c->erase_completion_lock); 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci ret = jffs2_garbage_collect_pass(c); 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci if (ret == -EAGAIN) { 17062306a36Sopenharmony_ci spin_lock(&c->erase_completion_lock); 17162306a36Sopenharmony_ci if (c->nr_erasing_blocks && 17262306a36Sopenharmony_ci list_empty(&c->erase_pending_list) && 17362306a36Sopenharmony_ci list_empty(&c->erase_complete_list)) { 17462306a36Sopenharmony_ci DECLARE_WAITQUEUE(wait, current); 17562306a36Sopenharmony_ci set_current_state(TASK_UNINTERRUPTIBLE); 17662306a36Sopenharmony_ci add_wait_queue(&c->erase_wait, &wait); 17762306a36Sopenharmony_ci jffs2_dbg(1, "%s waiting for erase to complete\n", 17862306a36Sopenharmony_ci __func__); 17962306a36Sopenharmony_ci spin_unlock(&c->erase_completion_lock); 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci schedule(); 18262306a36Sopenharmony_ci remove_wait_queue(&c->erase_wait, &wait); 18362306a36Sopenharmony_ci } else 18462306a36Sopenharmony_ci spin_unlock(&c->erase_completion_lock); 18562306a36Sopenharmony_ci } else if (ret) 18662306a36Sopenharmony_ci return ret; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci cond_resched(); 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci if (signal_pending(current)) 19162306a36Sopenharmony_ci return -EINTR; 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci mutex_lock(&c->alloc_sem); 19462306a36Sopenharmony_ci spin_lock(&c->erase_completion_lock); 19562306a36Sopenharmony_ci } 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci ret = jffs2_do_reserve_space(c, minsize, len, sumsize); 19862306a36Sopenharmony_ci if (ret) { 19962306a36Sopenharmony_ci jffs2_dbg(1, "%s(): ret is %d\n", __func__, ret); 20062306a36Sopenharmony_ci } 20162306a36Sopenharmony_ci } 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ciout: 20462306a36Sopenharmony_ci spin_unlock(&c->erase_completion_lock); 20562306a36Sopenharmony_ci if (!ret) 20662306a36Sopenharmony_ci ret = jffs2_prealloc_raw_node_refs(c, c->nextblock, 1); 20762306a36Sopenharmony_ci if (ret) 20862306a36Sopenharmony_ci mutex_unlock(&c->alloc_sem); 20962306a36Sopenharmony_ci return ret; 21062306a36Sopenharmony_ci} 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ciint jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, 21362306a36Sopenharmony_ci uint32_t *len, uint32_t sumsize) 21462306a36Sopenharmony_ci{ 21562306a36Sopenharmony_ci int ret; 21662306a36Sopenharmony_ci minsize = PAD(minsize); 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci jffs2_dbg(1, "%s(): Requested 0x%x bytes\n", __func__, minsize); 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci while (true) { 22162306a36Sopenharmony_ci spin_lock(&c->erase_completion_lock); 22262306a36Sopenharmony_ci ret = jffs2_do_reserve_space(c, minsize, len, sumsize); 22362306a36Sopenharmony_ci if (ret) { 22462306a36Sopenharmony_ci jffs2_dbg(1, "%s(): looping, ret is %d\n", 22562306a36Sopenharmony_ci __func__, ret); 22662306a36Sopenharmony_ci } 22762306a36Sopenharmony_ci spin_unlock(&c->erase_completion_lock); 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci if (ret == -EAGAIN) 23062306a36Sopenharmony_ci cond_resched(); 23162306a36Sopenharmony_ci else 23262306a36Sopenharmony_ci break; 23362306a36Sopenharmony_ci } 23462306a36Sopenharmony_ci if (!ret) 23562306a36Sopenharmony_ci ret = jffs2_prealloc_raw_node_refs(c, c->nextblock, 1); 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci return ret; 23862306a36Sopenharmony_ci} 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci/* Classify nextblock (clean, dirty of verydirty) and force to select an other one */ 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_cistatic void jffs2_close_nextblock(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) 24462306a36Sopenharmony_ci{ 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci if (c->nextblock == NULL) { 24762306a36Sopenharmony_ci jffs2_dbg(1, "%s(): Erase block at 0x%08x has already been placed in a list\n", 24862306a36Sopenharmony_ci __func__, jeb->offset); 24962306a36Sopenharmony_ci return; 25062306a36Sopenharmony_ci } 25162306a36Sopenharmony_ci /* Check, if we have a dirty block now, or if it was dirty already */ 25262306a36Sopenharmony_ci if (ISDIRTY (jeb->wasted_size + jeb->dirty_size)) { 25362306a36Sopenharmony_ci c->dirty_size += jeb->wasted_size; 25462306a36Sopenharmony_ci c->wasted_size -= jeb->wasted_size; 25562306a36Sopenharmony_ci jeb->dirty_size += jeb->wasted_size; 25662306a36Sopenharmony_ci jeb->wasted_size = 0; 25762306a36Sopenharmony_ci if (VERYDIRTY(c, jeb->dirty_size)) { 25862306a36Sopenharmony_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", 25962306a36Sopenharmony_ci jeb->offset, jeb->free_size, jeb->dirty_size, 26062306a36Sopenharmony_ci jeb->used_size); 26162306a36Sopenharmony_ci list_add_tail(&jeb->list, &c->very_dirty_list); 26262306a36Sopenharmony_ci } else { 26362306a36Sopenharmony_ci jffs2_dbg(1, "Adding full erase block at 0x%08x to dirty_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n", 26462306a36Sopenharmony_ci jeb->offset, jeb->free_size, jeb->dirty_size, 26562306a36Sopenharmony_ci jeb->used_size); 26662306a36Sopenharmony_ci list_add_tail(&jeb->list, &c->dirty_list); 26762306a36Sopenharmony_ci } 26862306a36Sopenharmony_ci } else { 26962306a36Sopenharmony_ci jffs2_dbg(1, "Adding full erase block at 0x%08x to clean_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n", 27062306a36Sopenharmony_ci jeb->offset, jeb->free_size, jeb->dirty_size, 27162306a36Sopenharmony_ci jeb->used_size); 27262306a36Sopenharmony_ci list_add_tail(&jeb->list, &c->clean_list); 27362306a36Sopenharmony_ci } 27462306a36Sopenharmony_ci c->nextblock = NULL; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci} 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci/* Select a new jeb for nextblock */ 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_cistatic int jffs2_find_nextblock(struct jffs2_sb_info *c) 28162306a36Sopenharmony_ci{ 28262306a36Sopenharmony_ci struct list_head *next; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci /* Take the next block off the 'free' list */ 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci if (list_empty(&c->free_list)) { 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci if (!c->nr_erasing_blocks && 28962306a36Sopenharmony_ci !list_empty(&c->erasable_list)) { 29062306a36Sopenharmony_ci struct jffs2_eraseblock *ejeb; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci ejeb = list_entry(c->erasable_list.next, struct jffs2_eraseblock, list); 29362306a36Sopenharmony_ci list_move_tail(&ejeb->list, &c->erase_pending_list); 29462306a36Sopenharmony_ci c->nr_erasing_blocks++; 29562306a36Sopenharmony_ci jffs2_garbage_collect_trigger(c); 29662306a36Sopenharmony_ci jffs2_dbg(1, "%s(): Triggering erase of erasable block at 0x%08x\n", 29762306a36Sopenharmony_ci __func__, ejeb->offset); 29862306a36Sopenharmony_ci } 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci if (!c->nr_erasing_blocks && 30162306a36Sopenharmony_ci !list_empty(&c->erasable_pending_wbuf_list)) { 30262306a36Sopenharmony_ci jffs2_dbg(1, "%s(): Flushing write buffer\n", 30362306a36Sopenharmony_ci __func__); 30462306a36Sopenharmony_ci /* c->nextblock is NULL, no update to c->nextblock allowed */ 30562306a36Sopenharmony_ci spin_unlock(&c->erase_completion_lock); 30662306a36Sopenharmony_ci jffs2_flush_wbuf_pad(c); 30762306a36Sopenharmony_ci spin_lock(&c->erase_completion_lock); 30862306a36Sopenharmony_ci /* Have another go. It'll be on the erasable_list now */ 30962306a36Sopenharmony_ci return -EAGAIN; 31062306a36Sopenharmony_ci } 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci if (!c->nr_erasing_blocks) { 31362306a36Sopenharmony_ci /* Ouch. We're in GC, or we wouldn't have got here. 31462306a36Sopenharmony_ci And there's no space left. At all. */ 31562306a36Sopenharmony_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", 31662306a36Sopenharmony_ci c->nr_erasing_blocks, c->nr_free_blocks, 31762306a36Sopenharmony_ci list_empty(&c->erasable_list) ? "yes" : "no", 31862306a36Sopenharmony_ci list_empty(&c->erasing_list) ? "yes" : "no", 31962306a36Sopenharmony_ci list_empty(&c->erase_pending_list) ? "yes" : "no"); 32062306a36Sopenharmony_ci return -ENOSPC; 32162306a36Sopenharmony_ci } 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci spin_unlock(&c->erase_completion_lock); 32462306a36Sopenharmony_ci /* Don't wait for it; just erase one right now */ 32562306a36Sopenharmony_ci jffs2_erase_pending_blocks(c, 1); 32662306a36Sopenharmony_ci spin_lock(&c->erase_completion_lock); 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci /* An erase may have failed, decreasing the 32962306a36Sopenharmony_ci amount of free space available. So we must 33062306a36Sopenharmony_ci restart from the beginning */ 33162306a36Sopenharmony_ci return -EAGAIN; 33262306a36Sopenharmony_ci } 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci next = c->free_list.next; 33562306a36Sopenharmony_ci list_del(next); 33662306a36Sopenharmony_ci c->nextblock = list_entry(next, struct jffs2_eraseblock, list); 33762306a36Sopenharmony_ci c->nr_free_blocks--; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci jffs2_sum_reset_collected(c->summary); /* reset collected summary */ 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci#ifdef CONFIG_JFFS2_FS_WRITEBUFFER 34262306a36Sopenharmony_ci /* adjust write buffer offset, else we get a non contiguous write bug */ 34362306a36Sopenharmony_ci if (!(c->wbuf_ofs % c->sector_size) && !c->wbuf_len) 34462306a36Sopenharmony_ci c->wbuf_ofs = 0xffffffff; 34562306a36Sopenharmony_ci#endif 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci jffs2_dbg(1, "%s(): new nextblock = 0x%08x\n", 34862306a36Sopenharmony_ci __func__, c->nextblock->offset); 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci return 0; 35162306a36Sopenharmony_ci} 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci/* Called with alloc sem _and_ erase_completion_lock */ 35462306a36Sopenharmony_cistatic int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, 35562306a36Sopenharmony_ci uint32_t *len, uint32_t sumsize) 35662306a36Sopenharmony_ci{ 35762306a36Sopenharmony_ci struct jffs2_eraseblock *jeb = c->nextblock; 35862306a36Sopenharmony_ci uint32_t reserved_size; /* for summary information at the end of the jeb */ 35962306a36Sopenharmony_ci int ret; 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci restart: 36262306a36Sopenharmony_ci reserved_size = 0; 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci if (jffs2_sum_active() && (sumsize != JFFS2_SUMMARY_NOSUM_SIZE)) { 36562306a36Sopenharmony_ci /* NOSUM_SIZE means not to generate summary */ 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci if (jeb) { 36862306a36Sopenharmony_ci reserved_size = PAD(sumsize + c->summary->sum_size + JFFS2_SUMMARY_FRAME_SIZE); 36962306a36Sopenharmony_ci dbg_summary("minsize=%d , jeb->free=%d ," 37062306a36Sopenharmony_ci "summary->size=%d , sumsize=%d\n", 37162306a36Sopenharmony_ci minsize, jeb->free_size, 37262306a36Sopenharmony_ci c->summary->sum_size, sumsize); 37362306a36Sopenharmony_ci } 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci /* Is there enough space for writing out the current node, or we have to 37662306a36Sopenharmony_ci write out summary information now, close this jeb and select new nextblock? */ 37762306a36Sopenharmony_ci if (jeb && (PAD(minsize) + PAD(c->summary->sum_size + sumsize + 37862306a36Sopenharmony_ci JFFS2_SUMMARY_FRAME_SIZE) > jeb->free_size)) { 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci /* Has summary been disabled for this jeb? */ 38162306a36Sopenharmony_ci if (jffs2_sum_is_disabled(c->summary)) { 38262306a36Sopenharmony_ci sumsize = JFFS2_SUMMARY_NOSUM_SIZE; 38362306a36Sopenharmony_ci goto restart; 38462306a36Sopenharmony_ci } 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci /* Writing out the collected summary information */ 38762306a36Sopenharmony_ci dbg_summary("generating summary for 0x%08x.\n", jeb->offset); 38862306a36Sopenharmony_ci ret = jffs2_sum_write_sumnode(c); 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci if (ret) 39162306a36Sopenharmony_ci return ret; 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci if (jffs2_sum_is_disabled(c->summary)) { 39462306a36Sopenharmony_ci /* jffs2_write_sumnode() couldn't write out the summary information 39562306a36Sopenharmony_ci diabling summary for this jeb and free the collected information 39662306a36Sopenharmony_ci */ 39762306a36Sopenharmony_ci sumsize = JFFS2_SUMMARY_NOSUM_SIZE; 39862306a36Sopenharmony_ci goto restart; 39962306a36Sopenharmony_ci } 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci jffs2_close_nextblock(c, jeb); 40262306a36Sopenharmony_ci jeb = NULL; 40362306a36Sopenharmony_ci /* keep always valid value in reserved_size */ 40462306a36Sopenharmony_ci reserved_size = PAD(sumsize + c->summary->sum_size + JFFS2_SUMMARY_FRAME_SIZE); 40562306a36Sopenharmony_ci } 40662306a36Sopenharmony_ci } else { 40762306a36Sopenharmony_ci if (jeb && minsize > jeb->free_size) { 40862306a36Sopenharmony_ci uint32_t waste; 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci /* Skip the end of this block and file it as having some dirty space */ 41162306a36Sopenharmony_ci /* If there's a pending write to it, flush now */ 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci if (jffs2_wbuf_dirty(c)) { 41462306a36Sopenharmony_ci spin_unlock(&c->erase_completion_lock); 41562306a36Sopenharmony_ci jffs2_dbg(1, "%s(): Flushing write buffer\n", 41662306a36Sopenharmony_ci __func__); 41762306a36Sopenharmony_ci jffs2_flush_wbuf_pad(c); 41862306a36Sopenharmony_ci spin_lock(&c->erase_completion_lock); 41962306a36Sopenharmony_ci jeb = c->nextblock; 42062306a36Sopenharmony_ci goto restart; 42162306a36Sopenharmony_ci } 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci spin_unlock(&c->erase_completion_lock); 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci ret = jffs2_prealloc_raw_node_refs(c, jeb, 1); 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci /* Just lock it again and continue. Nothing much can change because 42862306a36Sopenharmony_ci we hold c->alloc_sem anyway. In fact, it's not entirely clear why 42962306a36Sopenharmony_ci we hold c->erase_completion_lock in the majority of this function... 43062306a36Sopenharmony_ci but that's a question for another (more caffeine-rich) day. */ 43162306a36Sopenharmony_ci spin_lock(&c->erase_completion_lock); 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci if (ret) 43462306a36Sopenharmony_ci return ret; 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci waste = jeb->free_size; 43762306a36Sopenharmony_ci jffs2_link_node_ref(c, jeb, 43862306a36Sopenharmony_ci (jeb->offset + c->sector_size - waste) | REF_OBSOLETE, 43962306a36Sopenharmony_ci waste, NULL); 44062306a36Sopenharmony_ci /* FIXME: that made it count as dirty. Convert to wasted */ 44162306a36Sopenharmony_ci jeb->dirty_size -= waste; 44262306a36Sopenharmony_ci c->dirty_size -= waste; 44362306a36Sopenharmony_ci jeb->wasted_size += waste; 44462306a36Sopenharmony_ci c->wasted_size += waste; 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci jffs2_close_nextblock(c, jeb); 44762306a36Sopenharmony_ci jeb = NULL; 44862306a36Sopenharmony_ci } 44962306a36Sopenharmony_ci } 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci if (!jeb) { 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci ret = jffs2_find_nextblock(c); 45462306a36Sopenharmony_ci if (ret) 45562306a36Sopenharmony_ci return ret; 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci jeb = c->nextblock; 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci if (jeb->free_size != c->sector_size - c->cleanmarker_size) { 46062306a36Sopenharmony_ci pr_warn("Eep. Block 0x%08x taken from free_list had free_size of 0x%08x!!\n", 46162306a36Sopenharmony_ci jeb->offset, jeb->free_size); 46262306a36Sopenharmony_ci goto restart; 46362306a36Sopenharmony_ci } 46462306a36Sopenharmony_ci } 46562306a36Sopenharmony_ci /* OK, jeb (==c->nextblock) is now pointing at a block which definitely has 46662306a36Sopenharmony_ci enough space */ 46762306a36Sopenharmony_ci *len = jeb->free_size - reserved_size; 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci if (c->cleanmarker_size && jeb->used_size == c->cleanmarker_size && 47062306a36Sopenharmony_ci !jeb->first_node->next_in_ino) { 47162306a36Sopenharmony_ci /* Only node in it beforehand was a CLEANMARKER node (we think). 47262306a36Sopenharmony_ci So mark it obsolete now that there's going to be another node 47362306a36Sopenharmony_ci in the block. This will reduce used_size to zero but We've 47462306a36Sopenharmony_ci already set c->nextblock so that jffs2_mark_node_obsolete() 47562306a36Sopenharmony_ci won't try to refile it to the dirty_list. 47662306a36Sopenharmony_ci */ 47762306a36Sopenharmony_ci spin_unlock(&c->erase_completion_lock); 47862306a36Sopenharmony_ci jffs2_mark_node_obsolete(c, jeb->first_node); 47962306a36Sopenharmony_ci spin_lock(&c->erase_completion_lock); 48062306a36Sopenharmony_ci } 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci jffs2_dbg(1, "%s(): Giving 0x%x bytes at 0x%x\n", 48362306a36Sopenharmony_ci __func__, 48462306a36Sopenharmony_ci *len, jeb->offset + (c->sector_size - jeb->free_size)); 48562306a36Sopenharmony_ci return 0; 48662306a36Sopenharmony_ci} 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci/** 48962306a36Sopenharmony_ci * jffs2_add_physical_node_ref - add a physical node reference to the list 49062306a36Sopenharmony_ci * @c: superblock info 49162306a36Sopenharmony_ci * @new: new node reference to add 49262306a36Sopenharmony_ci * @len: length of this physical node 49362306a36Sopenharmony_ci * 49462306a36Sopenharmony_ci * Should only be used to report nodes for which space has been allocated 49562306a36Sopenharmony_ci * by jffs2_reserve_space. 49662306a36Sopenharmony_ci * 49762306a36Sopenharmony_ci * Must be called with the alloc_sem held. 49862306a36Sopenharmony_ci */ 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_cistruct jffs2_raw_node_ref *jffs2_add_physical_node_ref(struct jffs2_sb_info *c, 50162306a36Sopenharmony_ci uint32_t ofs, uint32_t len, 50262306a36Sopenharmony_ci struct jffs2_inode_cache *ic) 50362306a36Sopenharmony_ci{ 50462306a36Sopenharmony_ci struct jffs2_eraseblock *jeb; 50562306a36Sopenharmony_ci struct jffs2_raw_node_ref *new; 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci jeb = &c->blocks[ofs / c->sector_size]; 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci jffs2_dbg(1, "%s(): Node at 0x%x(%d), size 0x%x\n", 51062306a36Sopenharmony_ci __func__, ofs & ~3, ofs & 3, len); 51162306a36Sopenharmony_ci#if 1 51262306a36Sopenharmony_ci /* Allow non-obsolete nodes only to be added at the end of c->nextblock, 51362306a36Sopenharmony_ci if c->nextblock is set. Note that wbuf.c will file obsolete nodes 51462306a36Sopenharmony_ci even after refiling c->nextblock */ 51562306a36Sopenharmony_ci if ((c->nextblock || ((ofs & 3) != REF_OBSOLETE)) 51662306a36Sopenharmony_ci && (jeb != c->nextblock || (ofs & ~3) != jeb->offset + (c->sector_size - jeb->free_size))) { 51762306a36Sopenharmony_ci pr_warn("argh. node added in wrong place at 0x%08x(%d)\n", 51862306a36Sopenharmony_ci ofs & ~3, ofs & 3); 51962306a36Sopenharmony_ci if (c->nextblock) 52062306a36Sopenharmony_ci pr_warn("nextblock 0x%08x", c->nextblock->offset); 52162306a36Sopenharmony_ci else 52262306a36Sopenharmony_ci pr_warn("No nextblock"); 52362306a36Sopenharmony_ci pr_cont(", expected at %08x\n", 52462306a36Sopenharmony_ci jeb->offset + (c->sector_size - jeb->free_size)); 52562306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 52662306a36Sopenharmony_ci } 52762306a36Sopenharmony_ci#endif 52862306a36Sopenharmony_ci spin_lock(&c->erase_completion_lock); 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci new = jffs2_link_node_ref(c, jeb, ofs, len, ic); 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci if (!jeb->free_size && !jeb->dirty_size && !ISDIRTY(jeb->wasted_size)) { 53362306a36Sopenharmony_ci /* If it lives on the dirty_list, jffs2_reserve_space will put it there */ 53462306a36Sopenharmony_ci jffs2_dbg(1, "Adding full erase block at 0x%08x to clean_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n", 53562306a36Sopenharmony_ci jeb->offset, jeb->free_size, jeb->dirty_size, 53662306a36Sopenharmony_ci jeb->used_size); 53762306a36Sopenharmony_ci if (jffs2_wbuf_dirty(c)) { 53862306a36Sopenharmony_ci /* Flush the last write in the block if it's outstanding */ 53962306a36Sopenharmony_ci spin_unlock(&c->erase_completion_lock); 54062306a36Sopenharmony_ci jffs2_flush_wbuf_pad(c); 54162306a36Sopenharmony_ci spin_lock(&c->erase_completion_lock); 54262306a36Sopenharmony_ci } 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci list_add_tail(&jeb->list, &c->clean_list); 54562306a36Sopenharmony_ci c->nextblock = NULL; 54662306a36Sopenharmony_ci } 54762306a36Sopenharmony_ci jffs2_dbg_acct_sanity_check_nolock(c,jeb); 54862306a36Sopenharmony_ci jffs2_dbg_acct_paranoia_check_nolock(c, jeb); 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci spin_unlock(&c->erase_completion_lock); 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci return new; 55362306a36Sopenharmony_ci} 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_civoid jffs2_complete_reservation(struct jffs2_sb_info *c) 55762306a36Sopenharmony_ci{ 55862306a36Sopenharmony_ci jffs2_dbg(1, "jffs2_complete_reservation()\n"); 55962306a36Sopenharmony_ci spin_lock(&c->erase_completion_lock); 56062306a36Sopenharmony_ci jffs2_garbage_collect_trigger(c); 56162306a36Sopenharmony_ci spin_unlock(&c->erase_completion_lock); 56262306a36Sopenharmony_ci mutex_unlock(&c->alloc_sem); 56362306a36Sopenharmony_ci} 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_cistatic inline int on_list(struct list_head *obj, struct list_head *head) 56662306a36Sopenharmony_ci{ 56762306a36Sopenharmony_ci struct list_head *this; 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci list_for_each(this, head) { 57062306a36Sopenharmony_ci if (this == obj) { 57162306a36Sopenharmony_ci jffs2_dbg(1, "%p is on list at %p\n", obj, head); 57262306a36Sopenharmony_ci return 1; 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci } 57562306a36Sopenharmony_ci } 57662306a36Sopenharmony_ci return 0; 57762306a36Sopenharmony_ci} 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_civoid jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *ref) 58062306a36Sopenharmony_ci{ 58162306a36Sopenharmony_ci struct jffs2_eraseblock *jeb; 58262306a36Sopenharmony_ci int blocknr; 58362306a36Sopenharmony_ci struct jffs2_unknown_node n; 58462306a36Sopenharmony_ci int ret, addedsize; 58562306a36Sopenharmony_ci size_t retlen; 58662306a36Sopenharmony_ci uint32_t freed_len; 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci if(unlikely(!ref)) { 58962306a36Sopenharmony_ci pr_notice("EEEEEK. jffs2_mark_node_obsolete called with NULL node\n"); 59062306a36Sopenharmony_ci return; 59162306a36Sopenharmony_ci } 59262306a36Sopenharmony_ci if (ref_obsolete(ref)) { 59362306a36Sopenharmony_ci jffs2_dbg(1, "%s(): called with already obsolete node at 0x%08x\n", 59462306a36Sopenharmony_ci __func__, ref_offset(ref)); 59562306a36Sopenharmony_ci return; 59662306a36Sopenharmony_ci } 59762306a36Sopenharmony_ci blocknr = ref->flash_offset / c->sector_size; 59862306a36Sopenharmony_ci if (blocknr >= c->nr_blocks) { 59962306a36Sopenharmony_ci pr_notice("raw node at 0x%08x is off the end of device!\n", 60062306a36Sopenharmony_ci ref->flash_offset); 60162306a36Sopenharmony_ci BUG(); 60262306a36Sopenharmony_ci } 60362306a36Sopenharmony_ci jeb = &c->blocks[blocknr]; 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci if (jffs2_can_mark_obsolete(c) && !jffs2_is_readonly(c) && 60662306a36Sopenharmony_ci !(c->flags & (JFFS2_SB_FLAG_SCANNING | JFFS2_SB_FLAG_BUILDING))) { 60762306a36Sopenharmony_ci /* Hm. This may confuse static lock analysis. If any of the above 60862306a36Sopenharmony_ci three conditions is false, we're going to return from this 60962306a36Sopenharmony_ci function without actually obliterating any nodes or freeing 61062306a36Sopenharmony_ci any jffs2_raw_node_refs. So we don't need to stop erases from 61162306a36Sopenharmony_ci happening, or protect against people holding an obsolete 61262306a36Sopenharmony_ci jffs2_raw_node_ref without the erase_completion_lock. */ 61362306a36Sopenharmony_ci mutex_lock(&c->erase_free_sem); 61462306a36Sopenharmony_ci } 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci spin_lock(&c->erase_completion_lock); 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci freed_len = ref_totlen(c, jeb, ref); 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci if (ref_flags(ref) == REF_UNCHECKED) { 62162306a36Sopenharmony_ci D1(if (unlikely(jeb->unchecked_size < freed_len)) { 62262306a36Sopenharmony_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", 62362306a36Sopenharmony_ci freed_len, blocknr, 62462306a36Sopenharmony_ci ref->flash_offset, jeb->used_size); 62562306a36Sopenharmony_ci BUG(); 62662306a36Sopenharmony_ci }) 62762306a36Sopenharmony_ci jffs2_dbg(1, "Obsoleting previously unchecked node at 0x%08x of len %x\n", 62862306a36Sopenharmony_ci ref_offset(ref), freed_len); 62962306a36Sopenharmony_ci jeb->unchecked_size -= freed_len; 63062306a36Sopenharmony_ci c->unchecked_size -= freed_len; 63162306a36Sopenharmony_ci } else { 63262306a36Sopenharmony_ci D1(if (unlikely(jeb->used_size < freed_len)) { 63362306a36Sopenharmony_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", 63462306a36Sopenharmony_ci freed_len, blocknr, 63562306a36Sopenharmony_ci ref->flash_offset, jeb->used_size); 63662306a36Sopenharmony_ci BUG(); 63762306a36Sopenharmony_ci }) 63862306a36Sopenharmony_ci jffs2_dbg(1, "Obsoleting node at 0x%08x of len %#x: ", 63962306a36Sopenharmony_ci ref_offset(ref), freed_len); 64062306a36Sopenharmony_ci jeb->used_size -= freed_len; 64162306a36Sopenharmony_ci c->used_size -= freed_len; 64262306a36Sopenharmony_ci } 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci // Take care, that wasted size is taken into concern 64562306a36Sopenharmony_ci if ((jeb->dirty_size || ISDIRTY(jeb->wasted_size + freed_len)) && jeb != c->nextblock) { 64662306a36Sopenharmony_ci jffs2_dbg(1, "Dirtying\n"); 64762306a36Sopenharmony_ci addedsize = freed_len; 64862306a36Sopenharmony_ci jeb->dirty_size += freed_len; 64962306a36Sopenharmony_ci c->dirty_size += freed_len; 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci /* Convert wasted space to dirty, if not a bad block */ 65262306a36Sopenharmony_ci if (jeb->wasted_size) { 65362306a36Sopenharmony_ci if (on_list(&jeb->list, &c->bad_used_list)) { 65462306a36Sopenharmony_ci jffs2_dbg(1, "Leaving block at %08x on the bad_used_list\n", 65562306a36Sopenharmony_ci jeb->offset); 65662306a36Sopenharmony_ci addedsize = 0; /* To fool the refiling code later */ 65762306a36Sopenharmony_ci } else { 65862306a36Sopenharmony_ci jffs2_dbg(1, "Converting %d bytes of wasted space to dirty in block at %08x\n", 65962306a36Sopenharmony_ci jeb->wasted_size, jeb->offset); 66062306a36Sopenharmony_ci addedsize += jeb->wasted_size; 66162306a36Sopenharmony_ci jeb->dirty_size += jeb->wasted_size; 66262306a36Sopenharmony_ci c->dirty_size += jeb->wasted_size; 66362306a36Sopenharmony_ci c->wasted_size -= jeb->wasted_size; 66462306a36Sopenharmony_ci jeb->wasted_size = 0; 66562306a36Sopenharmony_ci } 66662306a36Sopenharmony_ci } 66762306a36Sopenharmony_ci } else { 66862306a36Sopenharmony_ci jffs2_dbg(1, "Wasting\n"); 66962306a36Sopenharmony_ci addedsize = 0; 67062306a36Sopenharmony_ci jeb->wasted_size += freed_len; 67162306a36Sopenharmony_ci c->wasted_size += freed_len; 67262306a36Sopenharmony_ci } 67362306a36Sopenharmony_ci ref->flash_offset = ref_offset(ref) | REF_OBSOLETE; 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci jffs2_dbg_acct_sanity_check_nolock(c, jeb); 67662306a36Sopenharmony_ci jffs2_dbg_acct_paranoia_check_nolock(c, jeb); 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci if (c->flags & JFFS2_SB_FLAG_SCANNING) { 67962306a36Sopenharmony_ci /* Flash scanning is in progress. Don't muck about with the block 68062306a36Sopenharmony_ci lists because they're not ready yet, and don't actually 68162306a36Sopenharmony_ci obliterate nodes that look obsolete. If they weren't 68262306a36Sopenharmony_ci marked obsolete on the flash at the time they _became_ 68362306a36Sopenharmony_ci obsolete, there was probably a reason for that. */ 68462306a36Sopenharmony_ci spin_unlock(&c->erase_completion_lock); 68562306a36Sopenharmony_ci /* We didn't lock the erase_free_sem */ 68662306a36Sopenharmony_ci return; 68762306a36Sopenharmony_ci } 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci if (jeb == c->nextblock) { 69062306a36Sopenharmony_ci jffs2_dbg(2, "Not moving nextblock 0x%08x to dirty/erase_pending list\n", 69162306a36Sopenharmony_ci jeb->offset); 69262306a36Sopenharmony_ci } else if (!jeb->used_size && !jeb->unchecked_size) { 69362306a36Sopenharmony_ci if (jeb == c->gcblock) { 69462306a36Sopenharmony_ci jffs2_dbg(1, "gcblock at 0x%08x completely dirtied. Clearing gcblock...\n", 69562306a36Sopenharmony_ci jeb->offset); 69662306a36Sopenharmony_ci c->gcblock = NULL; 69762306a36Sopenharmony_ci } else { 69862306a36Sopenharmony_ci jffs2_dbg(1, "Eraseblock at 0x%08x completely dirtied. Removing from (dirty?) list...\n", 69962306a36Sopenharmony_ci jeb->offset); 70062306a36Sopenharmony_ci list_del(&jeb->list); 70162306a36Sopenharmony_ci } 70262306a36Sopenharmony_ci if (jffs2_wbuf_dirty(c)) { 70362306a36Sopenharmony_ci jffs2_dbg(1, "...and adding to erasable_pending_wbuf_list\n"); 70462306a36Sopenharmony_ci list_add_tail(&jeb->list, &c->erasable_pending_wbuf_list); 70562306a36Sopenharmony_ci } else { 70662306a36Sopenharmony_ci if (jiffies & 127) { 70762306a36Sopenharmony_ci /* Most of the time, we just erase it immediately. Otherwise we 70862306a36Sopenharmony_ci spend ages scanning it on mount, etc. */ 70962306a36Sopenharmony_ci jffs2_dbg(1, "...and adding to erase_pending_list\n"); 71062306a36Sopenharmony_ci list_add_tail(&jeb->list, &c->erase_pending_list); 71162306a36Sopenharmony_ci c->nr_erasing_blocks++; 71262306a36Sopenharmony_ci jffs2_garbage_collect_trigger(c); 71362306a36Sopenharmony_ci } else { 71462306a36Sopenharmony_ci /* Sometimes, however, we leave it elsewhere so it doesn't get 71562306a36Sopenharmony_ci immediately reused, and we spread the load a bit. */ 71662306a36Sopenharmony_ci jffs2_dbg(1, "...and adding to erasable_list\n"); 71762306a36Sopenharmony_ci list_add_tail(&jeb->list, &c->erasable_list); 71862306a36Sopenharmony_ci } 71962306a36Sopenharmony_ci } 72062306a36Sopenharmony_ci jffs2_dbg(1, "Done OK\n"); 72162306a36Sopenharmony_ci } else if (jeb == c->gcblock) { 72262306a36Sopenharmony_ci jffs2_dbg(2, "Not moving gcblock 0x%08x to dirty_list\n", 72362306a36Sopenharmony_ci jeb->offset); 72462306a36Sopenharmony_ci } else if (ISDIRTY(jeb->dirty_size) && !ISDIRTY(jeb->dirty_size - addedsize)) { 72562306a36Sopenharmony_ci jffs2_dbg(1, "Eraseblock at 0x%08x is freshly dirtied. Removing from clean list...\n", 72662306a36Sopenharmony_ci jeb->offset); 72762306a36Sopenharmony_ci list_del(&jeb->list); 72862306a36Sopenharmony_ci jffs2_dbg(1, "...and adding to dirty_list\n"); 72962306a36Sopenharmony_ci list_add_tail(&jeb->list, &c->dirty_list); 73062306a36Sopenharmony_ci } else if (VERYDIRTY(c, jeb->dirty_size) && 73162306a36Sopenharmony_ci !VERYDIRTY(c, jeb->dirty_size - addedsize)) { 73262306a36Sopenharmony_ci jffs2_dbg(1, "Eraseblock at 0x%08x is now very dirty. Removing from dirty list...\n", 73362306a36Sopenharmony_ci jeb->offset); 73462306a36Sopenharmony_ci list_del(&jeb->list); 73562306a36Sopenharmony_ci jffs2_dbg(1, "...and adding to very_dirty_list\n"); 73662306a36Sopenharmony_ci list_add_tail(&jeb->list, &c->very_dirty_list); 73762306a36Sopenharmony_ci } else { 73862306a36Sopenharmony_ci jffs2_dbg(1, "Eraseblock at 0x%08x not moved anywhere. (free 0x%08x, dirty 0x%08x, used 0x%08x)\n", 73962306a36Sopenharmony_ci jeb->offset, jeb->free_size, jeb->dirty_size, 74062306a36Sopenharmony_ci jeb->used_size); 74162306a36Sopenharmony_ci } 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci spin_unlock(&c->erase_completion_lock); 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci if (!jffs2_can_mark_obsolete(c) || jffs2_is_readonly(c) || 74662306a36Sopenharmony_ci (c->flags & JFFS2_SB_FLAG_BUILDING)) { 74762306a36Sopenharmony_ci /* We didn't lock the erase_free_sem */ 74862306a36Sopenharmony_ci return; 74962306a36Sopenharmony_ci } 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci /* The erase_free_sem is locked, and has been since before we marked the node obsolete 75262306a36Sopenharmony_ci and potentially put its eraseblock onto the erase_pending_list. Thus, we know that 75362306a36Sopenharmony_ci the block hasn't _already_ been erased, and that 'ref' itself hasn't been freed yet 75462306a36Sopenharmony_ci by jffs2_free_jeb_node_refs() in erase.c. Which is nice. */ 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci jffs2_dbg(1, "obliterating obsoleted node at 0x%08x\n", 75762306a36Sopenharmony_ci ref_offset(ref)); 75862306a36Sopenharmony_ci ret = jffs2_flash_read(c, ref_offset(ref), sizeof(n), &retlen, (char *)&n); 75962306a36Sopenharmony_ci if (ret) { 76062306a36Sopenharmony_ci pr_warn("Read error reading from obsoleted node at 0x%08x: %d\n", 76162306a36Sopenharmony_ci ref_offset(ref), ret); 76262306a36Sopenharmony_ci goto out_erase_sem; 76362306a36Sopenharmony_ci } 76462306a36Sopenharmony_ci if (retlen != sizeof(n)) { 76562306a36Sopenharmony_ci pr_warn("Short read from obsoleted node at 0x%08x: %zd\n", 76662306a36Sopenharmony_ci ref_offset(ref), retlen); 76762306a36Sopenharmony_ci goto out_erase_sem; 76862306a36Sopenharmony_ci } 76962306a36Sopenharmony_ci if (PAD(je32_to_cpu(n.totlen)) != PAD(freed_len)) { 77062306a36Sopenharmony_ci pr_warn("Node totlen on flash (0x%08x) != totlen from node ref (0x%08x)\n", 77162306a36Sopenharmony_ci je32_to_cpu(n.totlen), freed_len); 77262306a36Sopenharmony_ci goto out_erase_sem; 77362306a36Sopenharmony_ci } 77462306a36Sopenharmony_ci if (!(je16_to_cpu(n.nodetype) & JFFS2_NODE_ACCURATE)) { 77562306a36Sopenharmony_ci jffs2_dbg(1, "Node at 0x%08x was already marked obsolete (nodetype 0x%04x)\n", 77662306a36Sopenharmony_ci ref_offset(ref), je16_to_cpu(n.nodetype)); 77762306a36Sopenharmony_ci goto out_erase_sem; 77862306a36Sopenharmony_ci } 77962306a36Sopenharmony_ci /* XXX FIXME: This is ugly now */ 78062306a36Sopenharmony_ci n.nodetype = cpu_to_je16(je16_to_cpu(n.nodetype) & ~JFFS2_NODE_ACCURATE); 78162306a36Sopenharmony_ci ret = jffs2_flash_write(c, ref_offset(ref), sizeof(n), &retlen, (char *)&n); 78262306a36Sopenharmony_ci if (ret) { 78362306a36Sopenharmony_ci pr_warn("Write error in obliterating obsoleted node at 0x%08x: %d\n", 78462306a36Sopenharmony_ci ref_offset(ref), ret); 78562306a36Sopenharmony_ci goto out_erase_sem; 78662306a36Sopenharmony_ci } 78762306a36Sopenharmony_ci if (retlen != sizeof(n)) { 78862306a36Sopenharmony_ci pr_warn("Short write in obliterating obsoleted node at 0x%08x: %zd\n", 78962306a36Sopenharmony_ci ref_offset(ref), retlen); 79062306a36Sopenharmony_ci goto out_erase_sem; 79162306a36Sopenharmony_ci } 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci /* Nodes which have been marked obsolete no longer need to be 79462306a36Sopenharmony_ci associated with any inode. Remove them from the per-inode list. 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci Note we can't do this for NAND at the moment because we need 79762306a36Sopenharmony_ci obsolete dirent nodes to stay on the lists, because of the 79862306a36Sopenharmony_ci horridness in jffs2_garbage_collect_deletion_dirent(). Also 79962306a36Sopenharmony_ci because we delete the inocache, and on NAND we need that to 80062306a36Sopenharmony_ci stay around until all the nodes are actually erased, in order 80162306a36Sopenharmony_ci to stop us from giving the same inode number to another newly 80262306a36Sopenharmony_ci created inode. */ 80362306a36Sopenharmony_ci if (ref->next_in_ino) { 80462306a36Sopenharmony_ci struct jffs2_inode_cache *ic; 80562306a36Sopenharmony_ci struct jffs2_raw_node_ref **p; 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci spin_lock(&c->erase_completion_lock); 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci ic = jffs2_raw_ref_to_ic(ref); 81062306a36Sopenharmony_ci for (p = &ic->nodes; (*p) != ref; p = &((*p)->next_in_ino)) 81162306a36Sopenharmony_ci ; 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci *p = ref->next_in_ino; 81462306a36Sopenharmony_ci ref->next_in_ino = NULL; 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci switch (ic->class) { 81762306a36Sopenharmony_ci#ifdef CONFIG_JFFS2_FS_XATTR 81862306a36Sopenharmony_ci case RAWNODE_CLASS_XATTR_DATUM: 81962306a36Sopenharmony_ci jffs2_release_xattr_datum(c, (struct jffs2_xattr_datum *)ic); 82062306a36Sopenharmony_ci break; 82162306a36Sopenharmony_ci case RAWNODE_CLASS_XATTR_REF: 82262306a36Sopenharmony_ci jffs2_release_xattr_ref(c, (struct jffs2_xattr_ref *)ic); 82362306a36Sopenharmony_ci break; 82462306a36Sopenharmony_ci#endif 82562306a36Sopenharmony_ci default: 82662306a36Sopenharmony_ci if (ic->nodes == (void *)ic && ic->pino_nlink == 0) 82762306a36Sopenharmony_ci jffs2_del_ino_cache(c, ic); 82862306a36Sopenharmony_ci break; 82962306a36Sopenharmony_ci } 83062306a36Sopenharmony_ci spin_unlock(&c->erase_completion_lock); 83162306a36Sopenharmony_ci } 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci out_erase_sem: 83462306a36Sopenharmony_ci mutex_unlock(&c->erase_free_sem); 83562306a36Sopenharmony_ci} 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ciint jffs2_thread_should_wake(struct jffs2_sb_info *c) 83862306a36Sopenharmony_ci{ 83962306a36Sopenharmony_ci int ret = 0; 84062306a36Sopenharmony_ci uint32_t dirty; 84162306a36Sopenharmony_ci int nr_very_dirty = 0; 84262306a36Sopenharmony_ci struct jffs2_eraseblock *jeb; 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci if (!list_empty(&c->erase_complete_list) || 84562306a36Sopenharmony_ci !list_empty(&c->erase_pending_list)) 84662306a36Sopenharmony_ci return 1; 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci if (c->unchecked_size) { 84962306a36Sopenharmony_ci jffs2_dbg(1, "jffs2_thread_should_wake(): unchecked_size %d, check_ino #%d\n", 85062306a36Sopenharmony_ci c->unchecked_size, c->check_ino); 85162306a36Sopenharmony_ci return 1; 85262306a36Sopenharmony_ci } 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci /* dirty_size contains blocks on erase_pending_list 85562306a36Sopenharmony_ci * those blocks are counted in c->nr_erasing_blocks. 85662306a36Sopenharmony_ci * If one block is actually erased, it is not longer counted as dirty_space 85762306a36Sopenharmony_ci * but it is counted in c->nr_erasing_blocks, so we add it and subtract it 85862306a36Sopenharmony_ci * with c->nr_erasing_blocks * c->sector_size again. 85962306a36Sopenharmony_ci * Blocks on erasable_list are counted as dirty_size, but not in c->nr_erasing_blocks 86062306a36Sopenharmony_ci * This helps us to force gc and pick eventually a clean block to spread the load. 86162306a36Sopenharmony_ci */ 86262306a36Sopenharmony_ci dirty = c->dirty_size + c->erasing_size - c->nr_erasing_blocks * c->sector_size; 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci if (c->nr_free_blocks + c->nr_erasing_blocks < c->resv_blocks_gctrigger && 86562306a36Sopenharmony_ci (dirty > c->nospc_dirty_size)) 86662306a36Sopenharmony_ci ret = 1; 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci list_for_each_entry(jeb, &c->very_dirty_list, list) { 86962306a36Sopenharmony_ci nr_very_dirty++; 87062306a36Sopenharmony_ci if (nr_very_dirty == c->vdirty_blocks_gctrigger) { 87162306a36Sopenharmony_ci ret = 1; 87262306a36Sopenharmony_ci /* In debug mode, actually go through and count them all */ 87362306a36Sopenharmony_ci D1(continue); 87462306a36Sopenharmony_ci break; 87562306a36Sopenharmony_ci } 87662306a36Sopenharmony_ci } 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_ci jffs2_dbg(1, "%s(): nr_free_blocks %d, nr_erasing_blocks %d, dirty_size 0x%x, vdirty_blocks %d: %s\n", 87962306a36Sopenharmony_ci __func__, c->nr_free_blocks, c->nr_erasing_blocks, 88062306a36Sopenharmony_ci c->dirty_size, nr_very_dirty, ret ? "yes" : "no"); 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci return ret; 88362306a36Sopenharmony_ci} 884