11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * JFFS2 -- Journalling Flash File System, Version 2. 31da177e4SLinus Torvalds * 4c00c310eSDavid Woodhouse * Copyright © 2001-2007 Red Hat, Inc. 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * Created by David Woodhouse <dwmw2@infradead.org> 71da177e4SLinus Torvalds * 81da177e4SLinus Torvalds * For licensing information, see the file 'LICENCE' in this directory. 91da177e4SLinus Torvalds * 101da177e4SLinus Torvalds */ 111da177e4SLinus Torvalds 121da177e4SLinus Torvalds #include <linux/kernel.h> 131da177e4SLinus Torvalds #include <linux/mtd/mtd.h> 141da177e4SLinus Torvalds #include <linux/compiler.h> 151da177e4SLinus Torvalds #include <linux/sched.h> /* For cond_resched() */ 161da177e4SLinus Torvalds #include "nodelist.h" 17e631ddbaSFerenc Havasi #include "debug.h" 181da177e4SLinus Torvalds 191da177e4SLinus Torvalds /** 201da177e4SLinus Torvalds * jffs2_reserve_space - request physical space to write nodes to flash 211da177e4SLinus Torvalds * @c: superblock info 221da177e4SLinus Torvalds * @minsize: Minimum acceptable size of allocation 231da177e4SLinus Torvalds * @len: Returned value of allocation length 241da177e4SLinus Torvalds * @prio: Allocation type - ALLOC_{NORMAL,DELETION} 251da177e4SLinus Torvalds * 261da177e4SLinus Torvalds * Requests a block of physical space on the flash. Returns zero for success 279fe4854cSDavid Woodhouse * and puts 'len' into the appropriate place, or returns -ENOSPC or other 289fe4854cSDavid Woodhouse * error if appropriate. Doesn't return len since that's 291da177e4SLinus Torvalds * 301da177e4SLinus Torvalds * If it returns zero, jffs2_reserve_space() also downs the per-filesystem 311da177e4SLinus Torvalds * allocation semaphore, to prevent more than one allocation from being 321da177e4SLinus Torvalds * active at any time. The semaphore is later released by jffs2_commit_allocation() 331da177e4SLinus Torvalds * 341da177e4SLinus Torvalds * jffs2_reserve_space() may trigger garbage collection in order to make room 351da177e4SLinus Torvalds * for the requested allocation. 361da177e4SLinus Torvalds */ 371da177e4SLinus Torvalds 38e631ddbaSFerenc Havasi static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, 399fe4854cSDavid Woodhouse uint32_t *len, uint32_t sumsize); 401da177e4SLinus Torvalds 419fe4854cSDavid Woodhouse int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, 42e631ddbaSFerenc Havasi uint32_t *len, int prio, uint32_t sumsize) 431da177e4SLinus Torvalds { 441da177e4SLinus Torvalds int ret = -EAGAIN; 451da177e4SLinus Torvalds int blocksneeded = c->resv_blocks_write; 461da177e4SLinus Torvalds /* align it */ 471da177e4SLinus Torvalds minsize = PAD(minsize); 481da177e4SLinus Torvalds 491da177e4SLinus Torvalds D1(printk(KERN_DEBUG "jffs2_reserve_space(): Requested 0x%x bytes\n", minsize)); 50ced22070SDavid Woodhouse mutex_lock(&c->alloc_sem); 511da177e4SLinus Torvalds 521da177e4SLinus Torvalds D1(printk(KERN_DEBUG "jffs2_reserve_space(): alloc sem got\n")); 531da177e4SLinus Torvalds 541da177e4SLinus Torvalds spin_lock(&c->erase_completion_lock); 551da177e4SLinus Torvalds 561da177e4SLinus Torvalds /* this needs a little more thought (true <tglx> :)) */ 571da177e4SLinus Torvalds while(ret == -EAGAIN) { 581da177e4SLinus Torvalds while(c->nr_free_blocks + c->nr_erasing_blocks < blocksneeded) { 591da177e4SLinus Torvalds uint32_t dirty, avail; 601da177e4SLinus Torvalds 611da177e4SLinus Torvalds /* calculate real dirty size 621da177e4SLinus Torvalds * dirty_size contains blocks on erase_pending_list 631da177e4SLinus Torvalds * those blocks are counted in c->nr_erasing_blocks. 641da177e4SLinus Torvalds * If one block is actually erased, it is not longer counted as dirty_space 651da177e4SLinus Torvalds * but it is counted in c->nr_erasing_blocks, so we add it and subtract it 661da177e4SLinus Torvalds * with c->nr_erasing_blocks * c->sector_size again. 671da177e4SLinus Torvalds * Blocks on erasable_list are counted as dirty_size, but not in c->nr_erasing_blocks 681da177e4SLinus Torvalds * This helps us to force gc and pick eventually a clean block to spread the load. 691da177e4SLinus Torvalds * We add unchecked_size here, as we hopefully will find some space to use. 701da177e4SLinus Torvalds * This will affect the sum only once, as gc first finishes checking 711da177e4SLinus Torvalds * of nodes. 721da177e4SLinus Torvalds */ 731da177e4SLinus Torvalds dirty = c->dirty_size + c->erasing_size - c->nr_erasing_blocks * c->sector_size + c->unchecked_size; 741da177e4SLinus Torvalds if (dirty < c->nospc_dirty_size) { 751da177e4SLinus Torvalds if (prio == ALLOC_DELETION && c->nr_free_blocks + c->nr_erasing_blocks >= c->resv_blocks_deletion) { 764132ace8SArtem B. Bityuckiy D1(printk(KERN_NOTICE "jffs2_reserve_space(): Low on dirty space to GC, but it's a deletion. Allowing...\n")); 771da177e4SLinus Torvalds break; 781da177e4SLinus Torvalds } 791da177e4SLinus Torvalds D1(printk(KERN_DEBUG "dirty size 0x%08x + unchecked_size 0x%08x < nospc_dirty_size 0x%08x, returning -ENOSPC\n", 801da177e4SLinus Torvalds dirty, c->unchecked_size, c->sector_size)); 811da177e4SLinus Torvalds 821da177e4SLinus Torvalds spin_unlock(&c->erase_completion_lock); 83ced22070SDavid Woodhouse mutex_unlock(&c->alloc_sem); 841da177e4SLinus Torvalds return -ENOSPC; 851da177e4SLinus Torvalds } 861da177e4SLinus Torvalds 871da177e4SLinus Torvalds /* Calc possibly available space. Possibly available means that we 881da177e4SLinus Torvalds * don't know, if unchecked size contains obsoleted nodes, which could give us some 891da177e4SLinus Torvalds * more usable space. This will affect the sum only once, as gc first finishes checking 901da177e4SLinus Torvalds * of nodes. 911da177e4SLinus Torvalds + Return -ENOSPC, if the maximum possibly available space is less or equal than 921da177e4SLinus Torvalds * blocksneeded * sector_size. 931da177e4SLinus Torvalds * This blocks endless gc looping on a filesystem, which is nearly full, even if 941da177e4SLinus Torvalds * the check above passes. 951da177e4SLinus Torvalds */ 961da177e4SLinus Torvalds avail = c->free_size + c->dirty_size + c->erasing_size + c->unchecked_size; 971da177e4SLinus Torvalds if ( (avail / c->sector_size) <= blocksneeded) { 981da177e4SLinus Torvalds if (prio == ALLOC_DELETION && c->nr_free_blocks + c->nr_erasing_blocks >= c->resv_blocks_deletion) { 994132ace8SArtem B. Bityuckiy D1(printk(KERN_NOTICE "jffs2_reserve_space(): Low on possibly available space, but it's a deletion. Allowing...\n")); 1001da177e4SLinus Torvalds break; 1011da177e4SLinus Torvalds } 1021da177e4SLinus Torvalds 1031da177e4SLinus Torvalds D1(printk(KERN_DEBUG "max. available size 0x%08x < blocksneeded * sector_size 0x%08x, returning -ENOSPC\n", 1041da177e4SLinus Torvalds avail, blocksneeded * c->sector_size)); 1051da177e4SLinus Torvalds spin_unlock(&c->erase_completion_lock); 106ced22070SDavid Woodhouse mutex_unlock(&c->alloc_sem); 1071da177e4SLinus Torvalds return -ENOSPC; 1081da177e4SLinus Torvalds } 1091da177e4SLinus Torvalds 110ced22070SDavid Woodhouse mutex_unlock(&c->alloc_sem); 1111da177e4SLinus Torvalds 1121da177e4SLinus Torvalds D1(printk(KERN_DEBUG "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", 1131da177e4SLinus Torvalds c->nr_free_blocks, c->nr_erasing_blocks, c->free_size, c->dirty_size, c->wasted_size, c->used_size, c->erasing_size, c->bad_size, 1141da177e4SLinus Torvalds c->free_size + c->dirty_size + c->wasted_size + c->used_size + c->erasing_size + c->bad_size, c->flash_size)); 1151da177e4SLinus Torvalds spin_unlock(&c->erase_completion_lock); 1161da177e4SLinus Torvalds 1171da177e4SLinus Torvalds ret = jffs2_garbage_collect_pass(c); 118422b1202SDavid Woodhouse 1190717bf84SDavid Woodhouse if (ret == -EAGAIN) { 1200717bf84SDavid Woodhouse spin_lock(&c->erase_completion_lock); 1210717bf84SDavid Woodhouse if (c->nr_erasing_blocks && 1220717bf84SDavid Woodhouse list_empty(&c->erase_pending_list) && 1230717bf84SDavid Woodhouse list_empty(&c->erase_complete_list)) { 1240717bf84SDavid Woodhouse DECLARE_WAITQUEUE(wait, current); 1250717bf84SDavid Woodhouse set_current_state(TASK_UNINTERRUPTIBLE); 1260717bf84SDavid Woodhouse add_wait_queue(&c->erase_wait, &wait); 1270717bf84SDavid Woodhouse D1(printk(KERN_DEBUG "%s waiting for erase to complete\n", __func__)); 1280717bf84SDavid Woodhouse spin_unlock(&c->erase_completion_lock); 1290717bf84SDavid Woodhouse 1300717bf84SDavid Woodhouse schedule(); 1310717bf84SDavid Woodhouse } else 1320717bf84SDavid Woodhouse spin_unlock(&c->erase_completion_lock); 1330717bf84SDavid Woodhouse } else if (ret) 1341da177e4SLinus Torvalds return ret; 1351da177e4SLinus Torvalds 1361da177e4SLinus Torvalds cond_resched(); 1371da177e4SLinus Torvalds 1381da177e4SLinus Torvalds if (signal_pending(current)) 1391da177e4SLinus Torvalds return -EINTR; 1401da177e4SLinus Torvalds 141ced22070SDavid Woodhouse mutex_lock(&c->alloc_sem); 1421da177e4SLinus Torvalds spin_lock(&c->erase_completion_lock); 1431da177e4SLinus Torvalds } 1441da177e4SLinus Torvalds 1459fe4854cSDavid Woodhouse ret = jffs2_do_reserve_space(c, minsize, len, sumsize); 1461da177e4SLinus Torvalds if (ret) { 1471da177e4SLinus Torvalds D1(printk(KERN_DEBUG "jffs2_reserve_space: ret is %d\n", ret)); 1481da177e4SLinus Torvalds } 1491da177e4SLinus Torvalds } 1501da177e4SLinus Torvalds spin_unlock(&c->erase_completion_lock); 1512f785402SDavid Woodhouse if (!ret) 152046b8b98SDavid Woodhouse ret = jffs2_prealloc_raw_node_refs(c, c->nextblock, 1); 1531da177e4SLinus Torvalds if (ret) 154ced22070SDavid Woodhouse mutex_unlock(&c->alloc_sem); 1551da177e4SLinus Torvalds return ret; 1561da177e4SLinus Torvalds } 1571da177e4SLinus Torvalds 1589fe4854cSDavid Woodhouse int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, 159e631ddbaSFerenc Havasi uint32_t *len, uint32_t sumsize) 1601da177e4SLinus Torvalds { 1611da177e4SLinus Torvalds int ret = -EAGAIN; 1621da177e4SLinus Torvalds minsize = PAD(minsize); 1631da177e4SLinus Torvalds 1641da177e4SLinus Torvalds D1(printk(KERN_DEBUG "jffs2_reserve_space_gc(): Requested 0x%x bytes\n", minsize)); 1651da177e4SLinus Torvalds 1661da177e4SLinus Torvalds spin_lock(&c->erase_completion_lock); 1671da177e4SLinus Torvalds while(ret == -EAGAIN) { 1689fe4854cSDavid Woodhouse ret = jffs2_do_reserve_space(c, minsize, len, sumsize); 1691da177e4SLinus Torvalds if (ret) { 1701da177e4SLinus Torvalds D1(printk(KERN_DEBUG "jffs2_reserve_space_gc: looping, ret is %d\n", ret)); 1711da177e4SLinus Torvalds } 1721da177e4SLinus Torvalds } 1731da177e4SLinus Torvalds spin_unlock(&c->erase_completion_lock); 1742f785402SDavid Woodhouse if (!ret) 175046b8b98SDavid Woodhouse ret = jffs2_prealloc_raw_node_refs(c, c->nextblock, 1); 1762f785402SDavid Woodhouse 1771da177e4SLinus Torvalds return ret; 1781da177e4SLinus Torvalds } 1791da177e4SLinus Torvalds 1801da177e4SLinus Torvalds 181e631ddbaSFerenc Havasi /* Classify nextblock (clean, dirty of verydirty) and force to select an other one */ 182e631ddbaSFerenc Havasi 183e631ddbaSFerenc Havasi static void jffs2_close_nextblock(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) 184e631ddbaSFerenc Havasi { 1851da177e4SLinus Torvalds 18699c2594fSAdrian Hunter if (c->nextblock == NULL) { 18799c2594fSAdrian Hunter D1(printk(KERN_DEBUG "jffs2_close_nextblock: Erase block at 0x%08x has already been placed in a list\n", 18899c2594fSAdrian Hunter jeb->offset)); 18999c2594fSAdrian Hunter return; 19099c2594fSAdrian Hunter } 1911da177e4SLinus Torvalds /* Check, if we have a dirty block now, or if it was dirty already */ 1921da177e4SLinus Torvalds if (ISDIRTY (jeb->wasted_size + jeb->dirty_size)) { 1931da177e4SLinus Torvalds c->dirty_size += jeb->wasted_size; 1941da177e4SLinus Torvalds c->wasted_size -= jeb->wasted_size; 1951da177e4SLinus Torvalds jeb->dirty_size += jeb->wasted_size; 1961da177e4SLinus Torvalds jeb->wasted_size = 0; 1971da177e4SLinus Torvalds if (VERYDIRTY(c, jeb->dirty_size)) { 1981da177e4SLinus Torvalds D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to very_dirty_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n", 1991da177e4SLinus Torvalds jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size)); 2001da177e4SLinus Torvalds list_add_tail(&jeb->list, &c->very_dirty_list); 2011da177e4SLinus Torvalds } else { 2021da177e4SLinus Torvalds D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to dirty_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n", 2031da177e4SLinus Torvalds jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size)); 2041da177e4SLinus Torvalds list_add_tail(&jeb->list, &c->dirty_list); 2051da177e4SLinus Torvalds } 2061da177e4SLinus Torvalds } else { 2071da177e4SLinus Torvalds D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to clean_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n", 2081da177e4SLinus Torvalds jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size)); 2091da177e4SLinus Torvalds list_add_tail(&jeb->list, &c->clean_list); 2101da177e4SLinus Torvalds } 211e631ddbaSFerenc Havasi c->nextblock = NULL; 212e631ddbaSFerenc Havasi 2131da177e4SLinus Torvalds } 2141da177e4SLinus Torvalds 215e631ddbaSFerenc Havasi /* Select a new jeb for nextblock */ 216e631ddbaSFerenc Havasi 217e631ddbaSFerenc Havasi static int jffs2_find_nextblock(struct jffs2_sb_info *c) 218e631ddbaSFerenc Havasi { 2191da177e4SLinus Torvalds struct list_head *next; 220e631ddbaSFerenc Havasi 2211da177e4SLinus Torvalds /* Take the next block off the 'free' list */ 2221da177e4SLinus Torvalds 2231da177e4SLinus Torvalds if (list_empty(&c->free_list)) { 2241da177e4SLinus Torvalds 2251da177e4SLinus Torvalds if (!c->nr_erasing_blocks && 2261da177e4SLinus Torvalds !list_empty(&c->erasable_list)) { 2271da177e4SLinus Torvalds struct jffs2_eraseblock *ejeb; 2281da177e4SLinus Torvalds 2291da177e4SLinus Torvalds ejeb = list_entry(c->erasable_list.next, struct jffs2_eraseblock, list); 230f116629dSAkinobu Mita list_move_tail(&ejeb->list, &c->erase_pending_list); 2311da177e4SLinus Torvalds c->nr_erasing_blocks++; 232ae3b6ba0SDavid Woodhouse jffs2_garbage_collect_trigger(c); 233e631ddbaSFerenc Havasi D1(printk(KERN_DEBUG "jffs2_find_nextblock: Triggering erase of erasable block at 0x%08x\n", 2341da177e4SLinus Torvalds ejeb->offset)); 2351da177e4SLinus Torvalds } 2361da177e4SLinus Torvalds 2371da177e4SLinus Torvalds if (!c->nr_erasing_blocks && 2381da177e4SLinus Torvalds !list_empty(&c->erasable_pending_wbuf_list)) { 239e631ddbaSFerenc Havasi D1(printk(KERN_DEBUG "jffs2_find_nextblock: Flushing write buffer\n")); 2401da177e4SLinus Torvalds /* c->nextblock is NULL, no update to c->nextblock allowed */ 2411da177e4SLinus Torvalds spin_unlock(&c->erase_completion_lock); 2421da177e4SLinus Torvalds jffs2_flush_wbuf_pad(c); 2431da177e4SLinus Torvalds spin_lock(&c->erase_completion_lock); 2441da177e4SLinus Torvalds /* Have another go. It'll be on the erasable_list now */ 2451da177e4SLinus Torvalds return -EAGAIN; 2461da177e4SLinus Torvalds } 2471da177e4SLinus Torvalds 2481da177e4SLinus Torvalds if (!c->nr_erasing_blocks) { 2491da177e4SLinus Torvalds /* Ouch. We're in GC, or we wouldn't have got here. 2501da177e4SLinus Torvalds And there's no space left. At all. */ 2511da177e4SLinus Torvalds printk(KERN_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", 2521da177e4SLinus Torvalds c->nr_erasing_blocks, c->nr_free_blocks, list_empty(&c->erasable_list)?"yes":"no", 2531da177e4SLinus Torvalds list_empty(&c->erasing_list)?"yes":"no", list_empty(&c->erase_pending_list)?"yes":"no"); 2541da177e4SLinus Torvalds return -ENOSPC; 2551da177e4SLinus Torvalds } 2561da177e4SLinus Torvalds 2571da177e4SLinus Torvalds spin_unlock(&c->erase_completion_lock); 2581da177e4SLinus Torvalds /* Don't wait for it; just erase one right now */ 2591da177e4SLinus Torvalds jffs2_erase_pending_blocks(c, 1); 2601da177e4SLinus Torvalds spin_lock(&c->erase_completion_lock); 2611da177e4SLinus Torvalds 2621da177e4SLinus Torvalds /* An erase may have failed, decreasing the 2631da177e4SLinus Torvalds amount of free space available. So we must 2641da177e4SLinus Torvalds restart from the beginning */ 2651da177e4SLinus Torvalds return -EAGAIN; 2661da177e4SLinus Torvalds } 2671da177e4SLinus Torvalds 2681da177e4SLinus Torvalds next = c->free_list.next; 2691da177e4SLinus Torvalds list_del(next); 270e631ddbaSFerenc Havasi c->nextblock = list_entry(next, struct jffs2_eraseblock, list); 2711da177e4SLinus Torvalds c->nr_free_blocks--; 2721da177e4SLinus Torvalds 273e631ddbaSFerenc Havasi jffs2_sum_reset_collected(c->summary); /* reset collected summary */ 274e631ddbaSFerenc Havasi 275f04de505SSteve Glendinning #ifdef CONFIG_JFFS2_FS_WRITEBUFFER 2765bf17237SAlexander Belyakov /* adjust write buffer offset, else we get a non contiguous write bug */ 2775bf17237SAlexander Belyakov if (!(c->wbuf_ofs % c->sector_size) && !c->wbuf_len) 2785bf17237SAlexander Belyakov c->wbuf_ofs = 0xffffffff; 279f04de505SSteve Glendinning #endif 2805bf17237SAlexander Belyakov 281e631ddbaSFerenc Havasi D1(printk(KERN_DEBUG "jffs2_find_nextblock(): new nextblock = 0x%08x\n", c->nextblock->offset)); 282e631ddbaSFerenc Havasi 283e631ddbaSFerenc Havasi return 0; 284e631ddbaSFerenc Havasi } 285e631ddbaSFerenc Havasi 286e631ddbaSFerenc Havasi /* Called with alloc sem _and_ erase_completion_lock */ 2879fe4854cSDavid Woodhouse static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, 2889fe4854cSDavid Woodhouse uint32_t *len, uint32_t sumsize) 289e631ddbaSFerenc Havasi { 290e631ddbaSFerenc Havasi struct jffs2_eraseblock *jeb = c->nextblock; 291e631ddbaSFerenc Havasi uint32_t reserved_size; /* for summary information at the end of the jeb */ 292e631ddbaSFerenc Havasi int ret; 293e631ddbaSFerenc Havasi 294e631ddbaSFerenc Havasi restart: 295e631ddbaSFerenc Havasi reserved_size = 0; 296e631ddbaSFerenc Havasi 297e631ddbaSFerenc Havasi if (jffs2_sum_active() && (sumsize != JFFS2_SUMMARY_NOSUM_SIZE)) { 298e631ddbaSFerenc Havasi /* NOSUM_SIZE means not to generate summary */ 299e631ddbaSFerenc Havasi 300e631ddbaSFerenc Havasi if (jeb) { 301e631ddbaSFerenc Havasi reserved_size = PAD(sumsize + c->summary->sum_size + JFFS2_SUMMARY_FRAME_SIZE); 302733802d9SArtem B. Bityutskiy dbg_summary("minsize=%d , jeb->free=%d ," 303e631ddbaSFerenc Havasi "summary->size=%d , sumsize=%d\n", 304e631ddbaSFerenc Havasi minsize, jeb->free_size, 305e631ddbaSFerenc Havasi c->summary->sum_size, sumsize); 306e631ddbaSFerenc Havasi } 307e631ddbaSFerenc Havasi 308e631ddbaSFerenc Havasi /* Is there enough space for writing out the current node, or we have to 309e631ddbaSFerenc Havasi write out summary information now, close this jeb and select new nextblock? */ 310e631ddbaSFerenc Havasi if (jeb && (PAD(minsize) + PAD(c->summary->sum_size + sumsize + 311e631ddbaSFerenc Havasi JFFS2_SUMMARY_FRAME_SIZE) > jeb->free_size)) { 312e631ddbaSFerenc Havasi 313e631ddbaSFerenc Havasi /* Has summary been disabled for this jeb? */ 314e631ddbaSFerenc Havasi if (jffs2_sum_is_disabled(c->summary)) { 315e631ddbaSFerenc Havasi sumsize = JFFS2_SUMMARY_NOSUM_SIZE; 316e631ddbaSFerenc Havasi goto restart; 317e631ddbaSFerenc Havasi } 318e631ddbaSFerenc Havasi 319e631ddbaSFerenc Havasi /* Writing out the collected summary information */ 320733802d9SArtem B. Bityutskiy dbg_summary("generating summary for 0x%08x.\n", jeb->offset); 321e631ddbaSFerenc Havasi ret = jffs2_sum_write_sumnode(c); 322e631ddbaSFerenc Havasi 323e631ddbaSFerenc Havasi if (ret) 324e631ddbaSFerenc Havasi return ret; 325e631ddbaSFerenc Havasi 326e631ddbaSFerenc Havasi if (jffs2_sum_is_disabled(c->summary)) { 327e631ddbaSFerenc Havasi /* jffs2_write_sumnode() couldn't write out the summary information 328e631ddbaSFerenc Havasi diabling summary for this jeb and free the collected information 329e631ddbaSFerenc Havasi */ 330e631ddbaSFerenc Havasi sumsize = JFFS2_SUMMARY_NOSUM_SIZE; 331e631ddbaSFerenc Havasi goto restart; 332e631ddbaSFerenc Havasi } 333e631ddbaSFerenc Havasi 334e631ddbaSFerenc Havasi jffs2_close_nextblock(c, jeb); 335e631ddbaSFerenc Havasi jeb = NULL; 33634c0e906SFerenc Havasi /* keep always valid value in reserved_size */ 33734c0e906SFerenc Havasi reserved_size = PAD(sumsize + c->summary->sum_size + JFFS2_SUMMARY_FRAME_SIZE); 338e631ddbaSFerenc Havasi } 339e631ddbaSFerenc Havasi } else { 340e631ddbaSFerenc Havasi if (jeb && minsize > jeb->free_size) { 341fc6612f6SDavid Woodhouse uint32_t waste; 342fc6612f6SDavid Woodhouse 343e631ddbaSFerenc Havasi /* Skip the end of this block and file it as having some dirty space */ 344e631ddbaSFerenc Havasi /* If there's a pending write to it, flush now */ 345e631ddbaSFerenc Havasi 346e631ddbaSFerenc Havasi if (jffs2_wbuf_dirty(c)) { 347e631ddbaSFerenc Havasi spin_unlock(&c->erase_completion_lock); 348e631ddbaSFerenc Havasi D1(printk(KERN_DEBUG "jffs2_do_reserve_space: Flushing write buffer\n")); 349e631ddbaSFerenc Havasi jffs2_flush_wbuf_pad(c); 350e631ddbaSFerenc Havasi spin_lock(&c->erase_completion_lock); 351e631ddbaSFerenc Havasi jeb = c->nextblock; 352e631ddbaSFerenc Havasi goto restart; 353e631ddbaSFerenc Havasi } 354e631ddbaSFerenc Havasi 355fc6612f6SDavid Woodhouse spin_unlock(&c->erase_completion_lock); 356fc6612f6SDavid Woodhouse 357fc6612f6SDavid Woodhouse ret = jffs2_prealloc_raw_node_refs(c, jeb, 1); 358fc6612f6SDavid Woodhouse if (ret) 359fc6612f6SDavid Woodhouse return ret; 360fc6612f6SDavid Woodhouse /* Just lock it again and continue. Nothing much can change because 361fc6612f6SDavid Woodhouse we hold c->alloc_sem anyway. In fact, it's not entirely clear why 362fc6612f6SDavid Woodhouse we hold c->erase_completion_lock in the majority of this function... 363fc6612f6SDavid Woodhouse but that's a question for another (more caffeine-rich) day. */ 364fc6612f6SDavid Woodhouse spin_lock(&c->erase_completion_lock); 365fc6612f6SDavid Woodhouse 366fc6612f6SDavid Woodhouse waste = jeb->free_size; 367fc6612f6SDavid Woodhouse jffs2_link_node_ref(c, jeb, 368fc6612f6SDavid Woodhouse (jeb->offset + c->sector_size - waste) | REF_OBSOLETE, 369fc6612f6SDavid Woodhouse waste, NULL); 370fc6612f6SDavid Woodhouse /* FIXME: that made it count as dirty. Convert to wasted */ 371fc6612f6SDavid Woodhouse jeb->dirty_size -= waste; 372fc6612f6SDavid Woodhouse c->dirty_size -= waste; 373fc6612f6SDavid Woodhouse jeb->wasted_size += waste; 374fc6612f6SDavid Woodhouse c->wasted_size += waste; 375e631ddbaSFerenc Havasi 376e631ddbaSFerenc Havasi jffs2_close_nextblock(c, jeb); 377e631ddbaSFerenc Havasi jeb = NULL; 378e631ddbaSFerenc Havasi } 379e631ddbaSFerenc Havasi } 380e631ddbaSFerenc Havasi 381e631ddbaSFerenc Havasi if (!jeb) { 382e631ddbaSFerenc Havasi 383e631ddbaSFerenc Havasi ret = jffs2_find_nextblock(c); 384e631ddbaSFerenc Havasi if (ret) 385e631ddbaSFerenc Havasi return ret; 386e631ddbaSFerenc Havasi 387e631ddbaSFerenc Havasi jeb = c->nextblock; 388e631ddbaSFerenc Havasi 3891da177e4SLinus Torvalds if (jeb->free_size != c->sector_size - c->cleanmarker_size) { 3901da177e4SLinus Torvalds printk(KERN_WARNING "Eep. Block 0x%08x taken from free_list had free_size of 0x%08x!!\n", jeb->offset, jeb->free_size); 3911da177e4SLinus Torvalds goto restart; 3921da177e4SLinus Torvalds } 3931da177e4SLinus Torvalds } 3941da177e4SLinus Torvalds /* OK, jeb (==c->nextblock) is now pointing at a block which definitely has 3951da177e4SLinus Torvalds enough space */ 396e631ddbaSFerenc Havasi *len = jeb->free_size - reserved_size; 3971da177e4SLinus Torvalds 3981da177e4SLinus Torvalds if (c->cleanmarker_size && jeb->used_size == c->cleanmarker_size && 3991da177e4SLinus Torvalds !jeb->first_node->next_in_ino) { 4001da177e4SLinus Torvalds /* Only node in it beforehand was a CLEANMARKER node (we think). 4011da177e4SLinus Torvalds So mark it obsolete now that there's going to be another node 4021da177e4SLinus Torvalds in the block. This will reduce used_size to zero but We've 4031da177e4SLinus Torvalds already set c->nextblock so that jffs2_mark_node_obsolete() 4041da177e4SLinus Torvalds won't try to refile it to the dirty_list. 4051da177e4SLinus Torvalds */ 4061da177e4SLinus Torvalds spin_unlock(&c->erase_completion_lock); 4071da177e4SLinus Torvalds jffs2_mark_node_obsolete(c, jeb->first_node); 4081da177e4SLinus Torvalds spin_lock(&c->erase_completion_lock); 4091da177e4SLinus Torvalds } 4101da177e4SLinus Torvalds 4119fe4854cSDavid Woodhouse D1(printk(KERN_DEBUG "jffs2_do_reserve_space(): Giving 0x%x bytes at 0x%x\n", 4129fe4854cSDavid Woodhouse *len, jeb->offset + (c->sector_size - jeb->free_size))); 4131da177e4SLinus Torvalds return 0; 4141da177e4SLinus Torvalds } 4151da177e4SLinus Torvalds 4161da177e4SLinus Torvalds /** 4171da177e4SLinus Torvalds * jffs2_add_physical_node_ref - add a physical node reference to the list 4181da177e4SLinus Torvalds * @c: superblock info 4191da177e4SLinus Torvalds * @new: new node reference to add 4201da177e4SLinus Torvalds * @len: length of this physical node 4211da177e4SLinus Torvalds * 4221da177e4SLinus Torvalds * Should only be used to report nodes for which space has been allocated 4231da177e4SLinus Torvalds * by jffs2_reserve_space. 4241da177e4SLinus Torvalds * 4251da177e4SLinus Torvalds * Must be called with the alloc_sem held. 4261da177e4SLinus Torvalds */ 4271da177e4SLinus Torvalds 4282f785402SDavid Woodhouse struct jffs2_raw_node_ref *jffs2_add_physical_node_ref(struct jffs2_sb_info *c, 4292f785402SDavid Woodhouse uint32_t ofs, uint32_t len, 4302f785402SDavid Woodhouse struct jffs2_inode_cache *ic) 4311da177e4SLinus Torvalds { 4321da177e4SLinus Torvalds struct jffs2_eraseblock *jeb; 4332f785402SDavid Woodhouse struct jffs2_raw_node_ref *new; 4341da177e4SLinus Torvalds 4352f785402SDavid Woodhouse jeb = &c->blocks[ofs / c->sector_size]; 4361da177e4SLinus Torvalds 4372f785402SDavid Woodhouse D1(printk(KERN_DEBUG "jffs2_add_physical_node_ref(): Node at 0x%x(%d), size 0x%x\n", 4382f785402SDavid Woodhouse ofs & ~3, ofs & 3, len)); 4391da177e4SLinus Torvalds #if 1 4402f785402SDavid Woodhouse /* Allow non-obsolete nodes only to be added at the end of c->nextblock, 4412f785402SDavid Woodhouse if c->nextblock is set. Note that wbuf.c will file obsolete nodes 4422f785402SDavid Woodhouse even after refiling c->nextblock */ 4432f785402SDavid Woodhouse if ((c->nextblock || ((ofs & 3) != REF_OBSOLETE)) 4442f785402SDavid Woodhouse && (jeb != c->nextblock || (ofs & ~3) != jeb->offset + (c->sector_size - jeb->free_size))) { 44566bfaeaaSDavid Woodhouse printk(KERN_WARNING "argh. node added in wrong place at 0x%08x(%d)\n", ofs & ~3, ofs & 3); 44666bfaeaaSDavid Woodhouse if (c->nextblock) 44766bfaeaaSDavid Woodhouse printk(KERN_WARNING "nextblock 0x%08x", c->nextblock->offset); 44866bfaeaaSDavid Woodhouse else 44966bfaeaaSDavid Woodhouse printk(KERN_WARNING "No nextblock"); 45066bfaeaaSDavid Woodhouse printk(", expected at %08x\n", jeb->offset + (c->sector_size - jeb->free_size)); 4512f785402SDavid Woodhouse return ERR_PTR(-EINVAL); 4521da177e4SLinus Torvalds } 4531da177e4SLinus Torvalds #endif 4541da177e4SLinus Torvalds spin_lock(&c->erase_completion_lock); 4551da177e4SLinus Torvalds 4562f785402SDavid Woodhouse new = jffs2_link_node_ref(c, jeb, ofs, len, ic); 4571da177e4SLinus Torvalds 4589b88f473SEstelle Hammache if (!jeb->free_size && !jeb->dirty_size && !ISDIRTY(jeb->wasted_size)) { 4591da177e4SLinus Torvalds /* If it lives on the dirty_list, jffs2_reserve_space will put it there */ 4601da177e4SLinus Torvalds D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to clean_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n", 4611da177e4SLinus Torvalds jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size)); 4621da177e4SLinus Torvalds if (jffs2_wbuf_dirty(c)) { 4631da177e4SLinus Torvalds /* Flush the last write in the block if it's outstanding */ 4641da177e4SLinus Torvalds spin_unlock(&c->erase_completion_lock); 4651da177e4SLinus Torvalds jffs2_flush_wbuf_pad(c); 4661da177e4SLinus Torvalds spin_lock(&c->erase_completion_lock); 4671da177e4SLinus Torvalds } 4681da177e4SLinus Torvalds 4691da177e4SLinus Torvalds list_add_tail(&jeb->list, &c->clean_list); 4701da177e4SLinus Torvalds c->nextblock = NULL; 4711da177e4SLinus Torvalds } 472e0c8e42fSArtem B. Bityutskiy jffs2_dbg_acct_sanity_check_nolock(c,jeb); 473e0c8e42fSArtem B. Bityutskiy jffs2_dbg_acct_paranoia_check_nolock(c, jeb); 4741da177e4SLinus Torvalds 4751da177e4SLinus Torvalds spin_unlock(&c->erase_completion_lock); 4761da177e4SLinus Torvalds 4772f785402SDavid Woodhouse return new; 4781da177e4SLinus Torvalds } 4791da177e4SLinus Torvalds 4801da177e4SLinus Torvalds 4811da177e4SLinus Torvalds void jffs2_complete_reservation(struct jffs2_sb_info *c) 4821da177e4SLinus Torvalds { 4831da177e4SLinus Torvalds D1(printk(KERN_DEBUG "jffs2_complete_reservation()\n")); 484acb64a43SDavid Woodhouse spin_lock(&c->erase_completion_lock); 4851da177e4SLinus Torvalds jffs2_garbage_collect_trigger(c); 486acb64a43SDavid Woodhouse spin_unlock(&c->erase_completion_lock); 487ced22070SDavid Woodhouse mutex_unlock(&c->alloc_sem); 4881da177e4SLinus Torvalds } 4891da177e4SLinus Torvalds 4901da177e4SLinus Torvalds static inline int on_list(struct list_head *obj, struct list_head *head) 4911da177e4SLinus Torvalds { 4921da177e4SLinus Torvalds struct list_head *this; 4931da177e4SLinus Torvalds 4941da177e4SLinus Torvalds list_for_each(this, head) { 4951da177e4SLinus Torvalds if (this == obj) { 4961da177e4SLinus Torvalds D1(printk("%p is on list at %p\n", obj, head)); 4971da177e4SLinus Torvalds return 1; 4981da177e4SLinus Torvalds 4991da177e4SLinus Torvalds } 5001da177e4SLinus Torvalds } 5011da177e4SLinus Torvalds return 0; 5021da177e4SLinus Torvalds } 5031da177e4SLinus Torvalds 5041da177e4SLinus Torvalds void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *ref) 5051da177e4SLinus Torvalds { 5061da177e4SLinus Torvalds struct jffs2_eraseblock *jeb; 5071da177e4SLinus Torvalds int blocknr; 5081da177e4SLinus Torvalds struct jffs2_unknown_node n; 5091da177e4SLinus Torvalds int ret, addedsize; 5101da177e4SLinus Torvalds size_t retlen; 5111417fc44SDavid Woodhouse uint32_t freed_len; 5121da177e4SLinus Torvalds 5139bfeb691SDavid Woodhouse if(unlikely(!ref)) { 5141da177e4SLinus Torvalds printk(KERN_NOTICE "EEEEEK. jffs2_mark_node_obsolete called with NULL node\n"); 5151da177e4SLinus Torvalds return; 5161da177e4SLinus Torvalds } 5171da177e4SLinus Torvalds if (ref_obsolete(ref)) { 5181da177e4SLinus Torvalds D1(printk(KERN_DEBUG "jffs2_mark_node_obsolete called with already obsolete node at 0x%08x\n", ref_offset(ref))); 5191da177e4SLinus Torvalds return; 5201da177e4SLinus Torvalds } 5211da177e4SLinus Torvalds blocknr = ref->flash_offset / c->sector_size; 5221da177e4SLinus Torvalds if (blocknr >= c->nr_blocks) { 5231da177e4SLinus Torvalds printk(KERN_NOTICE "raw node at 0x%08x is off the end of device!\n", ref->flash_offset); 5241da177e4SLinus Torvalds BUG(); 5251da177e4SLinus Torvalds } 5261da177e4SLinus Torvalds jeb = &c->blocks[blocknr]; 5271da177e4SLinus Torvalds 5281da177e4SLinus Torvalds if (jffs2_can_mark_obsolete(c) && !jffs2_is_readonly(c) && 52931fbdf7aSArtem B. Bityuckiy !(c->flags & (JFFS2_SB_FLAG_SCANNING | JFFS2_SB_FLAG_BUILDING))) { 5301da177e4SLinus Torvalds /* Hm. This may confuse static lock analysis. If any of the above 5311da177e4SLinus Torvalds three conditions is false, we're going to return from this 5321da177e4SLinus Torvalds function without actually obliterating any nodes or freeing 5331da177e4SLinus Torvalds any jffs2_raw_node_refs. So we don't need to stop erases from 5341da177e4SLinus Torvalds happening, or protect against people holding an obsolete 5351da177e4SLinus Torvalds jffs2_raw_node_ref without the erase_completion_lock. */ 536ced22070SDavid Woodhouse mutex_lock(&c->erase_free_sem); 5371da177e4SLinus Torvalds } 5381da177e4SLinus Torvalds 5391da177e4SLinus Torvalds spin_lock(&c->erase_completion_lock); 5401da177e4SLinus Torvalds 5411417fc44SDavid Woodhouse freed_len = ref_totlen(c, jeb, ref); 5421417fc44SDavid Woodhouse 5431da177e4SLinus Torvalds if (ref_flags(ref) == REF_UNCHECKED) { 5441417fc44SDavid Woodhouse D1(if (unlikely(jeb->unchecked_size < freed_len)) { 5451da177e4SLinus Torvalds printk(KERN_NOTICE "raw unchecked node of size 0x%08x freed from erase block %d at 0x%08x, but unchecked_size was already 0x%08x\n", 5461417fc44SDavid Woodhouse freed_len, blocknr, ref->flash_offset, jeb->used_size); 5471da177e4SLinus Torvalds BUG(); 5481da177e4SLinus Torvalds }) 5491417fc44SDavid Woodhouse D1(printk(KERN_DEBUG "Obsoleting previously unchecked node at 0x%08x of len %x: ", ref_offset(ref), freed_len)); 5501417fc44SDavid Woodhouse jeb->unchecked_size -= freed_len; 5511417fc44SDavid Woodhouse c->unchecked_size -= freed_len; 5521da177e4SLinus Torvalds } else { 5531417fc44SDavid Woodhouse D1(if (unlikely(jeb->used_size < freed_len)) { 5541da177e4SLinus Torvalds printk(KERN_NOTICE "raw node of size 0x%08x freed from erase block %d at 0x%08x, but used_size was already 0x%08x\n", 5551417fc44SDavid Woodhouse freed_len, blocknr, ref->flash_offset, jeb->used_size); 5561da177e4SLinus Torvalds BUG(); 5571da177e4SLinus Torvalds }) 5581417fc44SDavid Woodhouse D1(printk(KERN_DEBUG "Obsoleting node at 0x%08x of len %#x: ", ref_offset(ref), freed_len)); 5591417fc44SDavid Woodhouse jeb->used_size -= freed_len; 5601417fc44SDavid Woodhouse c->used_size -= freed_len; 5611da177e4SLinus Torvalds } 5621da177e4SLinus Torvalds 5631da177e4SLinus Torvalds // Take care, that wasted size is taken into concern 5641417fc44SDavid Woodhouse if ((jeb->dirty_size || ISDIRTY(jeb->wasted_size + freed_len)) && jeb != c->nextblock) { 565c7c16c8eSDavid Woodhouse D1(printk("Dirtying\n")); 5661417fc44SDavid Woodhouse addedsize = freed_len; 5671417fc44SDavid Woodhouse jeb->dirty_size += freed_len; 5681417fc44SDavid Woodhouse c->dirty_size += freed_len; 5691da177e4SLinus Torvalds 5701da177e4SLinus Torvalds /* Convert wasted space to dirty, if not a bad block */ 5711da177e4SLinus Torvalds if (jeb->wasted_size) { 5721da177e4SLinus Torvalds if (on_list(&jeb->list, &c->bad_used_list)) { 5731da177e4SLinus Torvalds D1(printk(KERN_DEBUG "Leaving block at %08x on the bad_used_list\n", 5741da177e4SLinus Torvalds jeb->offset)); 5751da177e4SLinus Torvalds addedsize = 0; /* To fool the refiling code later */ 5761da177e4SLinus Torvalds } else { 5771da177e4SLinus Torvalds D1(printk(KERN_DEBUG "Converting %d bytes of wasted space to dirty in block at %08x\n", 5781da177e4SLinus Torvalds jeb->wasted_size, jeb->offset)); 5791da177e4SLinus Torvalds addedsize += jeb->wasted_size; 5801da177e4SLinus Torvalds jeb->dirty_size += jeb->wasted_size; 5811da177e4SLinus Torvalds c->dirty_size += jeb->wasted_size; 5821da177e4SLinus Torvalds c->wasted_size -= jeb->wasted_size; 5831da177e4SLinus Torvalds jeb->wasted_size = 0; 5841da177e4SLinus Torvalds } 5851da177e4SLinus Torvalds } 5861da177e4SLinus Torvalds } else { 587c7c16c8eSDavid Woodhouse D1(printk("Wasting\n")); 5881da177e4SLinus Torvalds addedsize = 0; 5891417fc44SDavid Woodhouse jeb->wasted_size += freed_len; 5901417fc44SDavid Woodhouse c->wasted_size += freed_len; 5911da177e4SLinus Torvalds } 5921da177e4SLinus Torvalds ref->flash_offset = ref_offset(ref) | REF_OBSOLETE; 5931da177e4SLinus Torvalds 594e0c8e42fSArtem B. Bityutskiy jffs2_dbg_acct_sanity_check_nolock(c, jeb); 595e0c8e42fSArtem B. Bityutskiy jffs2_dbg_acct_paranoia_check_nolock(c, jeb); 5961da177e4SLinus Torvalds 59731fbdf7aSArtem B. Bityuckiy if (c->flags & JFFS2_SB_FLAG_SCANNING) { 59831fbdf7aSArtem B. Bityuckiy /* Flash scanning is in progress. Don't muck about with the block 5991da177e4SLinus Torvalds lists because they're not ready yet, and don't actually 6001da177e4SLinus Torvalds obliterate nodes that look obsolete. If they weren't 6011da177e4SLinus Torvalds marked obsolete on the flash at the time they _became_ 6021da177e4SLinus Torvalds obsolete, there was probably a reason for that. */ 6031da177e4SLinus Torvalds spin_unlock(&c->erase_completion_lock); 6041da177e4SLinus Torvalds /* We didn't lock the erase_free_sem */ 6051da177e4SLinus Torvalds return; 6061da177e4SLinus Torvalds } 6071da177e4SLinus Torvalds 6081da177e4SLinus Torvalds if (jeb == c->nextblock) { 6091da177e4SLinus Torvalds D2(printk(KERN_DEBUG "Not moving nextblock 0x%08x to dirty/erase_pending list\n", jeb->offset)); 6101da177e4SLinus Torvalds } else if (!jeb->used_size && !jeb->unchecked_size) { 6111da177e4SLinus Torvalds if (jeb == c->gcblock) { 6121da177e4SLinus Torvalds D1(printk(KERN_DEBUG "gcblock at 0x%08x completely dirtied. Clearing gcblock...\n", jeb->offset)); 6131da177e4SLinus Torvalds c->gcblock = NULL; 6141da177e4SLinus Torvalds } else { 6151da177e4SLinus Torvalds D1(printk(KERN_DEBUG "Eraseblock at 0x%08x completely dirtied. Removing from (dirty?) list...\n", jeb->offset)); 6161da177e4SLinus Torvalds list_del(&jeb->list); 6171da177e4SLinus Torvalds } 6181da177e4SLinus Torvalds if (jffs2_wbuf_dirty(c)) { 6191da177e4SLinus Torvalds D1(printk(KERN_DEBUG "...and adding to erasable_pending_wbuf_list\n")); 6201da177e4SLinus Torvalds list_add_tail(&jeb->list, &c->erasable_pending_wbuf_list); 6211da177e4SLinus Torvalds } else { 6221da177e4SLinus Torvalds if (jiffies & 127) { 6231da177e4SLinus Torvalds /* Most of the time, we just erase it immediately. Otherwise we 6241da177e4SLinus Torvalds spend ages scanning it on mount, etc. */ 6251da177e4SLinus Torvalds D1(printk(KERN_DEBUG "...and adding to erase_pending_list\n")); 6261da177e4SLinus Torvalds list_add_tail(&jeb->list, &c->erase_pending_list); 6271da177e4SLinus Torvalds c->nr_erasing_blocks++; 628ae3b6ba0SDavid Woodhouse jffs2_garbage_collect_trigger(c); 6291da177e4SLinus Torvalds } else { 6301da177e4SLinus Torvalds /* Sometimes, however, we leave it elsewhere so it doesn't get 6311da177e4SLinus Torvalds immediately reused, and we spread the load a bit. */ 6321da177e4SLinus Torvalds D1(printk(KERN_DEBUG "...and adding to erasable_list\n")); 6331da177e4SLinus Torvalds list_add_tail(&jeb->list, &c->erasable_list); 6341da177e4SLinus Torvalds } 6351da177e4SLinus Torvalds } 6361da177e4SLinus Torvalds D1(printk(KERN_DEBUG "Done OK\n")); 6371da177e4SLinus Torvalds } else if (jeb == c->gcblock) { 6381da177e4SLinus Torvalds D2(printk(KERN_DEBUG "Not moving gcblock 0x%08x to dirty_list\n", jeb->offset)); 6391da177e4SLinus Torvalds } else if (ISDIRTY(jeb->dirty_size) && !ISDIRTY(jeb->dirty_size - addedsize)) { 6401da177e4SLinus Torvalds D1(printk(KERN_DEBUG "Eraseblock at 0x%08x is freshly dirtied. Removing from clean list...\n", jeb->offset)); 6411da177e4SLinus Torvalds list_del(&jeb->list); 6421da177e4SLinus Torvalds D1(printk(KERN_DEBUG "...and adding to dirty_list\n")); 6431da177e4SLinus Torvalds list_add_tail(&jeb->list, &c->dirty_list); 6441da177e4SLinus Torvalds } else if (VERYDIRTY(c, jeb->dirty_size) && 6451da177e4SLinus Torvalds !VERYDIRTY(c, jeb->dirty_size - addedsize)) { 6461da177e4SLinus Torvalds D1(printk(KERN_DEBUG "Eraseblock at 0x%08x is now very dirty. Removing from dirty list...\n", jeb->offset)); 6471da177e4SLinus Torvalds list_del(&jeb->list); 6481da177e4SLinus Torvalds D1(printk(KERN_DEBUG "...and adding to very_dirty_list\n")); 6491da177e4SLinus Torvalds list_add_tail(&jeb->list, &c->very_dirty_list); 6501da177e4SLinus Torvalds } else { 6511da177e4SLinus Torvalds D1(printk(KERN_DEBUG "Eraseblock at 0x%08x not moved anywhere. (free 0x%08x, dirty 0x%08x, used 0x%08x)\n", 6521da177e4SLinus Torvalds jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size)); 6531da177e4SLinus Torvalds } 6541da177e4SLinus Torvalds 6551da177e4SLinus Torvalds spin_unlock(&c->erase_completion_lock); 6561da177e4SLinus Torvalds 65731fbdf7aSArtem B. Bityuckiy if (!jffs2_can_mark_obsolete(c) || jffs2_is_readonly(c) || 65831fbdf7aSArtem B. Bityuckiy (c->flags & JFFS2_SB_FLAG_BUILDING)) { 6591da177e4SLinus Torvalds /* We didn't lock the erase_free_sem */ 6601da177e4SLinus Torvalds return; 6611da177e4SLinus Torvalds } 6621da177e4SLinus Torvalds 6631da177e4SLinus Torvalds /* The erase_free_sem is locked, and has been since before we marked the node obsolete 6641da177e4SLinus Torvalds and potentially put its eraseblock onto the erase_pending_list. Thus, we know that 6651da177e4SLinus Torvalds the block hasn't _already_ been erased, and that 'ref' itself hasn't been freed yet 666c38c1b61SDavid Woodhouse by jffs2_free_jeb_node_refs() in erase.c. Which is nice. */ 6671da177e4SLinus Torvalds 6681da177e4SLinus Torvalds D1(printk(KERN_DEBUG "obliterating obsoleted node at 0x%08x\n", ref_offset(ref))); 6691da177e4SLinus Torvalds ret = jffs2_flash_read(c, ref_offset(ref), sizeof(n), &retlen, (char *)&n); 6701da177e4SLinus Torvalds if (ret) { 6711da177e4SLinus Torvalds printk(KERN_WARNING "Read error reading from obsoleted node at 0x%08x: %d\n", ref_offset(ref), ret); 6721da177e4SLinus Torvalds goto out_erase_sem; 6731da177e4SLinus Torvalds } 6741da177e4SLinus Torvalds if (retlen != sizeof(n)) { 6751da177e4SLinus Torvalds printk(KERN_WARNING "Short read from obsoleted node at 0x%08x: %zd\n", ref_offset(ref), retlen); 6761da177e4SLinus Torvalds goto out_erase_sem; 6771da177e4SLinus Torvalds } 6781417fc44SDavid Woodhouse if (PAD(je32_to_cpu(n.totlen)) != PAD(freed_len)) { 6791417fc44SDavid Woodhouse printk(KERN_WARNING "Node totlen on flash (0x%08x) != totlen from node ref (0x%08x)\n", je32_to_cpu(n.totlen), freed_len); 6801da177e4SLinus Torvalds goto out_erase_sem; 6811da177e4SLinus Torvalds } 6821da177e4SLinus Torvalds if (!(je16_to_cpu(n.nodetype) & JFFS2_NODE_ACCURATE)) { 6831da177e4SLinus Torvalds D1(printk(KERN_DEBUG "Node at 0x%08x was already marked obsolete (nodetype 0x%04x)\n", ref_offset(ref), je16_to_cpu(n.nodetype))); 6841da177e4SLinus Torvalds goto out_erase_sem; 6851da177e4SLinus Torvalds } 6861da177e4SLinus Torvalds /* XXX FIXME: This is ugly now */ 6871da177e4SLinus Torvalds n.nodetype = cpu_to_je16(je16_to_cpu(n.nodetype) & ~JFFS2_NODE_ACCURATE); 6881da177e4SLinus Torvalds ret = jffs2_flash_write(c, ref_offset(ref), sizeof(n), &retlen, (char *)&n); 6891da177e4SLinus Torvalds if (ret) { 6901da177e4SLinus Torvalds printk(KERN_WARNING "Write error in obliterating obsoleted node at 0x%08x: %d\n", ref_offset(ref), ret); 6911da177e4SLinus Torvalds goto out_erase_sem; 6921da177e4SLinus Torvalds } 6931da177e4SLinus Torvalds if (retlen != sizeof(n)) { 6941da177e4SLinus Torvalds printk(KERN_WARNING "Short write in obliterating obsoleted node at 0x%08x: %zd\n", ref_offset(ref), retlen); 6951da177e4SLinus Torvalds goto out_erase_sem; 6961da177e4SLinus Torvalds } 6971da177e4SLinus Torvalds 6981da177e4SLinus Torvalds /* Nodes which have been marked obsolete no longer need to be 6991da177e4SLinus Torvalds associated with any inode. Remove them from the per-inode list. 7001da177e4SLinus Torvalds 7011da177e4SLinus Torvalds Note we can't do this for NAND at the moment because we need 7021da177e4SLinus Torvalds obsolete dirent nodes to stay on the lists, because of the 7031da177e4SLinus Torvalds horridness in jffs2_garbage_collect_deletion_dirent(). Also 7041da177e4SLinus Torvalds because we delete the inocache, and on NAND we need that to 7051da177e4SLinus Torvalds stay around until all the nodes are actually erased, in order 7061da177e4SLinus Torvalds to stop us from giving the same inode number to another newly 7071da177e4SLinus Torvalds created inode. */ 7081da177e4SLinus Torvalds if (ref->next_in_ino) { 7091da177e4SLinus Torvalds struct jffs2_inode_cache *ic; 7101da177e4SLinus Torvalds struct jffs2_raw_node_ref **p; 7111da177e4SLinus Torvalds 7121da177e4SLinus Torvalds spin_lock(&c->erase_completion_lock); 7131da177e4SLinus Torvalds 7141da177e4SLinus Torvalds ic = jffs2_raw_ref_to_ic(ref); 7151da177e4SLinus Torvalds for (p = &ic->nodes; (*p) != ref; p = &((*p)->next_in_ino)) 7161da177e4SLinus Torvalds ; 7171da177e4SLinus Torvalds 7181da177e4SLinus Torvalds *p = ref->next_in_ino; 7191da177e4SLinus Torvalds ref->next_in_ino = NULL; 7201da177e4SLinus Torvalds 721c9f700f8SKaiGai Kohei switch (ic->class) { 722c9f700f8SKaiGai Kohei #ifdef CONFIG_JFFS2_FS_XATTR 723c9f700f8SKaiGai Kohei case RAWNODE_CLASS_XATTR_DATUM: 724c9f700f8SKaiGai Kohei jffs2_release_xattr_datum(c, (struct jffs2_xattr_datum *)ic); 725c9f700f8SKaiGai Kohei break; 726c9f700f8SKaiGai Kohei case RAWNODE_CLASS_XATTR_REF: 727c9f700f8SKaiGai Kohei jffs2_release_xattr_ref(c, (struct jffs2_xattr_ref *)ic); 728c9f700f8SKaiGai Kohei break; 729c9f700f8SKaiGai Kohei #endif 730c9f700f8SKaiGai Kohei default: 73127c72b04SDavid Woodhouse if (ic->nodes == (void *)ic && ic->pino_nlink == 0) 7321da177e4SLinus Torvalds jffs2_del_ino_cache(c, ic); 733c9f700f8SKaiGai Kohei break; 734c9f700f8SKaiGai Kohei } 7351da177e4SLinus Torvalds spin_unlock(&c->erase_completion_lock); 7361da177e4SLinus Torvalds } 7371da177e4SLinus Torvalds 7381da177e4SLinus Torvalds out_erase_sem: 739ced22070SDavid Woodhouse mutex_unlock(&c->erase_free_sem); 7401da177e4SLinus Torvalds } 7411da177e4SLinus Torvalds 7421da177e4SLinus Torvalds int jffs2_thread_should_wake(struct jffs2_sb_info *c) 7431da177e4SLinus Torvalds { 7441da177e4SLinus Torvalds int ret = 0; 7451da177e4SLinus Torvalds uint32_t dirty; 7468fb870dfSDavid Woodhouse int nr_very_dirty = 0; 7478fb870dfSDavid Woodhouse struct jffs2_eraseblock *jeb; 7481da177e4SLinus Torvalds 749d6ce1710SJoakim Tjernlund if (!list_empty(&c->erase_complete_list) || 750d6ce1710SJoakim Tjernlund !list_empty(&c->erase_pending_list)) 751d6ce1710SJoakim Tjernlund return 1; 752d6ce1710SJoakim Tjernlund 7531da177e4SLinus Torvalds if (c->unchecked_size) { 7541da177e4SLinus Torvalds D1(printk(KERN_DEBUG "jffs2_thread_should_wake(): unchecked_size %d, checked_ino #%d\n", 7551da177e4SLinus Torvalds c->unchecked_size, c->checked_ino)); 7561da177e4SLinus Torvalds return 1; 7571da177e4SLinus Torvalds } 7581da177e4SLinus Torvalds 7591da177e4SLinus Torvalds /* dirty_size contains blocks on erase_pending_list 7601da177e4SLinus Torvalds * those blocks are counted in c->nr_erasing_blocks. 7611da177e4SLinus Torvalds * If one block is actually erased, it is not longer counted as dirty_space 7621da177e4SLinus Torvalds * but it is counted in c->nr_erasing_blocks, so we add it and subtract it 7631da177e4SLinus Torvalds * with c->nr_erasing_blocks * c->sector_size again. 7641da177e4SLinus Torvalds * Blocks on erasable_list are counted as dirty_size, but not in c->nr_erasing_blocks 7651da177e4SLinus Torvalds * This helps us to force gc and pick eventually a clean block to spread the load. 7661da177e4SLinus Torvalds */ 7671da177e4SLinus Torvalds dirty = c->dirty_size + c->erasing_size - c->nr_erasing_blocks * c->sector_size; 7681da177e4SLinus Torvalds 7691da177e4SLinus Torvalds if (c->nr_free_blocks + c->nr_erasing_blocks < c->resv_blocks_gctrigger && 7701da177e4SLinus Torvalds (dirty > c->nospc_dirty_size)) 7711da177e4SLinus Torvalds ret = 1; 7721da177e4SLinus Torvalds 7738fb870dfSDavid Woodhouse list_for_each_entry(jeb, &c->very_dirty_list, list) { 7748fb870dfSDavid Woodhouse nr_very_dirty++; 7758fb870dfSDavid Woodhouse if (nr_very_dirty == c->vdirty_blocks_gctrigger) { 7768fb870dfSDavid Woodhouse ret = 1; 777a8c68f32SDavid Woodhouse /* In debug mode, actually go through and count them all */ 778a8c68f32SDavid Woodhouse D1(continue); 779a8c68f32SDavid Woodhouse break; 7808fb870dfSDavid Woodhouse } 7818fb870dfSDavid Woodhouse } 7828fb870dfSDavid Woodhouse 7838fb870dfSDavid Woodhouse D1(printk(KERN_DEBUG "jffs2_thread_should_wake(): nr_free_blocks %d, nr_erasing_blocks %d, dirty_size 0x%x, vdirty_blocks %d: %s\n", 7848fb870dfSDavid Woodhouse c->nr_free_blocks, c->nr_erasing_blocks, c->dirty_size, nr_very_dirty, ret?"yes":"no")); 7851da177e4SLinus Torvalds 7861da177e4SLinus Torvalds return ret; 7871da177e4SLinus Torvalds } 788