11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * JFFS2 -- Journalling Flash File System, Version 2. 31da177e4SLinus Torvalds * 4c00c310eSDavid Woodhouse * Copyright © 2001-2007 Red Hat, Inc. 56088c058SDavid Woodhouse * Copyright © 2004-2010 David Woodhouse <dwmw2@infradead.org> 61da177e4SLinus Torvalds * 71da177e4SLinus Torvalds * Created by David Woodhouse <dwmw2@infradead.org> 81da177e4SLinus Torvalds * 91da177e4SLinus Torvalds * For licensing information, see the file 'LICENCE' in this directory. 101da177e4SLinus Torvalds * 111da177e4SLinus Torvalds */ 121da177e4SLinus Torvalds 135a528957SJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 145a528957SJoe Perches 151da177e4SLinus Torvalds #include <linux/kernel.h> 161da177e4SLinus Torvalds #include <linux/mtd/mtd.h> 171da177e4SLinus Torvalds #include <linux/slab.h> 181da177e4SLinus Torvalds #include <linux/pagemap.h> 191da177e4SLinus Torvalds #include <linux/crc32.h> 201da177e4SLinus Torvalds #include <linux/compiler.h> 211da177e4SLinus Torvalds #include <linux/stat.h> 221da177e4SLinus Torvalds #include "nodelist.h" 231da177e4SLinus Torvalds #include "compr.h" 241da177e4SLinus Torvalds 251da177e4SLinus Torvalds static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, 261da177e4SLinus Torvalds struct jffs2_inode_cache *ic, 271da177e4SLinus Torvalds struct jffs2_raw_node_ref *raw); 281da177e4SLinus Torvalds static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, 291da177e4SLinus Torvalds struct jffs2_inode_info *f, struct jffs2_full_dnode *fd); 301da177e4SLinus Torvalds static int jffs2_garbage_collect_dirent(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, 311da177e4SLinus Torvalds struct jffs2_inode_info *f, struct jffs2_full_dirent *fd); 321da177e4SLinus Torvalds static int jffs2_garbage_collect_deletion_dirent(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, 331da177e4SLinus Torvalds struct jffs2_inode_info *f, struct jffs2_full_dirent *fd); 341da177e4SLinus Torvalds static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, 351da177e4SLinus Torvalds struct jffs2_inode_info *f, struct jffs2_full_dnode *fn, 361da177e4SLinus Torvalds uint32_t start, uint32_t end); 371da177e4SLinus Torvalds static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, 381da177e4SLinus Torvalds struct jffs2_inode_info *f, struct jffs2_full_dnode *fn, 391da177e4SLinus Torvalds uint32_t start, uint32_t end); 401da177e4SLinus Torvalds static int jffs2_garbage_collect_live(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, 411da177e4SLinus Torvalds struct jffs2_raw_node_ref *raw, struct jffs2_inode_info *f); 421da177e4SLinus Torvalds 431da177e4SLinus Torvalds /* Called with erase_completion_lock held */ 441da177e4SLinus Torvalds static struct jffs2_eraseblock *jffs2_find_gc_block(struct jffs2_sb_info *c) 451da177e4SLinus Torvalds { 461da177e4SLinus Torvalds struct jffs2_eraseblock *ret; 471da177e4SLinus Torvalds struct list_head *nextlist = NULL; 481da177e4SLinus Torvalds int n = jiffies % 128; 491da177e4SLinus Torvalds 501da177e4SLinus Torvalds /* Pick an eraseblock to garbage collect next. This is where we'll 511da177e4SLinus Torvalds put the clever wear-levelling algorithms. Eventually. */ 521da177e4SLinus Torvalds /* We possibly want to favour the dirtier blocks more when the 531da177e4SLinus Torvalds number of free blocks is low. */ 54a42163d7SArtem B. Bityuckiy again: 551da177e4SLinus Torvalds if (!list_empty(&c->bad_used_list) && c->nr_free_blocks > c->resv_blocks_gcbad) { 569c261b33SJoe Perches jffs2_dbg(1, "Picking block from bad_used_list to GC next\n"); 571da177e4SLinus Torvalds nextlist = &c->bad_used_list; 581da177e4SLinus Torvalds } else if (n < 50 && !list_empty(&c->erasable_list)) { 591da177e4SLinus Torvalds /* Note that most of them will have gone directly to be erased. 601da177e4SLinus Torvalds So don't favour the erasable_list _too_ much. */ 619c261b33SJoe Perches jffs2_dbg(1, "Picking block from erasable_list to GC next\n"); 621da177e4SLinus Torvalds nextlist = &c->erasable_list; 631da177e4SLinus Torvalds } else if (n < 110 && !list_empty(&c->very_dirty_list)) { 641da177e4SLinus Torvalds /* Most of the time, pick one off the very_dirty list */ 659c261b33SJoe Perches jffs2_dbg(1, "Picking block from very_dirty_list to GC next\n"); 661da177e4SLinus Torvalds nextlist = &c->very_dirty_list; 671da177e4SLinus Torvalds } else if (n < 126 && !list_empty(&c->dirty_list)) { 689c261b33SJoe Perches jffs2_dbg(1, "Picking block from dirty_list to GC next\n"); 691da177e4SLinus Torvalds nextlist = &c->dirty_list; 701da177e4SLinus Torvalds } else if (!list_empty(&c->clean_list)) { 719c261b33SJoe Perches jffs2_dbg(1, "Picking block from clean_list to GC next\n"); 721da177e4SLinus Torvalds nextlist = &c->clean_list; 731da177e4SLinus Torvalds } else if (!list_empty(&c->dirty_list)) { 749c261b33SJoe Perches jffs2_dbg(1, "Picking block from dirty_list to GC next (clean_list was empty)\n"); 751da177e4SLinus Torvalds 761da177e4SLinus Torvalds nextlist = &c->dirty_list; 771da177e4SLinus Torvalds } else if (!list_empty(&c->very_dirty_list)) { 789c261b33SJoe Perches jffs2_dbg(1, "Picking block from very_dirty_list to GC next (clean_list and dirty_list were empty)\n"); 791da177e4SLinus Torvalds nextlist = &c->very_dirty_list; 801da177e4SLinus Torvalds } else if (!list_empty(&c->erasable_list)) { 819c261b33SJoe Perches jffs2_dbg(1, "Picking block from erasable_list to GC next (clean_list and {very_,}dirty_list were empty)\n"); 821da177e4SLinus Torvalds 831da177e4SLinus Torvalds nextlist = &c->erasable_list; 84a42163d7SArtem B. Bityuckiy } else if (!list_empty(&c->erasable_pending_wbuf_list)) { 85a42163d7SArtem B. Bityuckiy /* There are blocks are wating for the wbuf sync */ 869c261b33SJoe Perches jffs2_dbg(1, "Synching wbuf in order to reuse erasable_pending_wbuf_list blocks\n"); 873cceb9f6SArtem B. Bityuckiy spin_unlock(&c->erase_completion_lock); 88a42163d7SArtem B. Bityuckiy jffs2_flush_wbuf_pad(c); 893cceb9f6SArtem B. Bityuckiy spin_lock(&c->erase_completion_lock); 90a42163d7SArtem B. Bityuckiy goto again; 911da177e4SLinus Torvalds } else { 921da177e4SLinus Torvalds /* Eep. All were empty */ 935a528957SJoe Perches jffs2_dbg(1, "No clean, dirty _or_ erasable blocks to GC from! Where are they all?\n"); 941da177e4SLinus Torvalds return NULL; 951da177e4SLinus Torvalds } 961da177e4SLinus Torvalds 971da177e4SLinus Torvalds ret = list_entry(nextlist->next, struct jffs2_eraseblock, list); 981da177e4SLinus Torvalds list_del(&ret->list); 991da177e4SLinus Torvalds c->gcblock = ret; 1001da177e4SLinus Torvalds ret->gc_node = ret->first_node; 1011da177e4SLinus Torvalds if (!ret->gc_node) { 102da320f05SJoe Perches pr_warn("Eep. ret->gc_node for block at 0x%08x is NULL\n", 103da320f05SJoe Perches ret->offset); 1041da177e4SLinus Torvalds BUG(); 1051da177e4SLinus Torvalds } 1061da177e4SLinus Torvalds 1071da177e4SLinus Torvalds /* Have we accidentally picked a clean block with wasted space ? */ 1081da177e4SLinus Torvalds if (ret->wasted_size) { 1099c261b33SJoe Perches jffs2_dbg(1, "Converting wasted_size %08x to dirty_size\n", 1109c261b33SJoe Perches ret->wasted_size); 1111da177e4SLinus Torvalds ret->dirty_size += ret->wasted_size; 1121da177e4SLinus Torvalds c->wasted_size -= ret->wasted_size; 1131da177e4SLinus Torvalds c->dirty_size += ret->wasted_size; 1141da177e4SLinus Torvalds ret->wasted_size = 0; 1151da177e4SLinus Torvalds } 1161da177e4SLinus Torvalds 1171da177e4SLinus Torvalds return ret; 1181da177e4SLinus Torvalds } 1191da177e4SLinus Torvalds 1201da177e4SLinus Torvalds /* jffs2_garbage_collect_pass 1211da177e4SLinus Torvalds * Make a single attempt to progress GC. Move one node, and possibly 1221da177e4SLinus Torvalds * start erasing one eraseblock. 1231da177e4SLinus Torvalds */ 1241da177e4SLinus Torvalds int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) 1251da177e4SLinus Torvalds { 1261da177e4SLinus Torvalds struct jffs2_inode_info *f; 1271da177e4SLinus Torvalds struct jffs2_inode_cache *ic; 1281da177e4SLinus Torvalds struct jffs2_eraseblock *jeb; 1291da177e4SLinus Torvalds struct jffs2_raw_node_ref *raw; 1302665ea84SDavid Woodhouse uint32_t gcblock_dirty; 1311da177e4SLinus Torvalds int ret = 0, inum, nlink; 132aa98d7cfSKaiGai Kohei int xattr = 0; 1331da177e4SLinus Torvalds 134ced22070SDavid Woodhouse if (mutex_lock_interruptible(&c->alloc_sem)) 1351da177e4SLinus Torvalds return -EINTR; 1361da177e4SLinus Torvalds 137*5817b9dcSDavid Woodhouse 1381da177e4SLinus Torvalds for (;;) { 139*5817b9dcSDavid Woodhouse /* We can't start doing GC until we've finished checking 140*5817b9dcSDavid Woodhouse the node CRCs etc. */ 141*5817b9dcSDavid Woodhouse int bucket, want_ino; 142*5817b9dcSDavid Woodhouse 1431da177e4SLinus Torvalds spin_lock(&c->erase_completion_lock); 1441da177e4SLinus Torvalds if (!c->unchecked_size) 1451da177e4SLinus Torvalds break; 1461da177e4SLinus Torvalds spin_unlock(&c->erase_completion_lock); 1471da177e4SLinus Torvalds 148aa98d7cfSKaiGai Kohei if (!xattr) 149aa98d7cfSKaiGai Kohei xattr = jffs2_verify_xattr(c); 150aa98d7cfSKaiGai Kohei 1511da177e4SLinus Torvalds spin_lock(&c->inocache_lock); 152*5817b9dcSDavid Woodhouse /* Instead of doing the inodes in numeric order, doing a lookup 153*5817b9dcSDavid Woodhouse * in the hash for each possible number, just walk the hash 154*5817b9dcSDavid Woodhouse * buckets of *existing* inodes. This means that we process 155*5817b9dcSDavid Woodhouse * them out-of-order, but it can be a lot faster if there's 156*5817b9dcSDavid Woodhouse * a sparse inode# space. Which there often is. */ 157*5817b9dcSDavid Woodhouse want_ino = c->check_ino; 158*5817b9dcSDavid Woodhouse for (bucket = c->check_ino % c->inocache_hashsize ; bucket < c->inocache_hashsize; bucket++) { 159*5817b9dcSDavid Woodhouse for (ic = c->inocache_list[bucket]; ic; ic = ic->next) { 160*5817b9dcSDavid Woodhouse if (ic->ino < want_ino) 1611da177e4SLinus Torvalds continue; 162*5817b9dcSDavid Woodhouse 163*5817b9dcSDavid Woodhouse if (ic->state != INO_STATE_CHECKEDABSENT && 164*5817b9dcSDavid Woodhouse ic->state != INO_STATE_PRESENT) 165*5817b9dcSDavid Woodhouse goto got_next; /* with inocache_lock held */ 166*5817b9dcSDavid Woodhouse 167*5817b9dcSDavid Woodhouse jffs2_dbg(1, "Skipping ino #%u already checked\n", 168*5817b9dcSDavid Woodhouse ic->ino); 1691da177e4SLinus Torvalds } 170*5817b9dcSDavid Woodhouse want_ino = 0; 171*5817b9dcSDavid Woodhouse } 172*5817b9dcSDavid Woodhouse 173*5817b9dcSDavid Woodhouse /* Point c->check_ino past the end of the last bucket. */ 174*5817b9dcSDavid Woodhouse c->check_ino = ((c->highest_ino + c->inocache_hashsize + 1) & 175*5817b9dcSDavid Woodhouse ~c->inocache_hashsize) - 1; 176*5817b9dcSDavid Woodhouse 177*5817b9dcSDavid Woodhouse spin_unlock(&c->inocache_lock); 178*5817b9dcSDavid Woodhouse 179*5817b9dcSDavid Woodhouse pr_crit("Checked all inodes but still 0x%x bytes of unchecked space?\n", 180*5817b9dcSDavid Woodhouse c->unchecked_size); 181*5817b9dcSDavid Woodhouse jffs2_dbg_dump_block_lists_nolock(c); 182*5817b9dcSDavid Woodhouse mutex_unlock(&c->alloc_sem); 183*5817b9dcSDavid Woodhouse return -ENOSPC; 184*5817b9dcSDavid Woodhouse 185*5817b9dcSDavid Woodhouse got_next: 186*5817b9dcSDavid Woodhouse /* For next time round the loop, we want c->checked_ino to indicate 187*5817b9dcSDavid Woodhouse * the *next* one we want to check. And since we're walking the 188*5817b9dcSDavid Woodhouse * buckets rather than doing it sequentially, it's: */ 189*5817b9dcSDavid Woodhouse c->check_ino = ic->ino + c->inocache_hashsize; 1901da177e4SLinus Torvalds 19127c72b04SDavid Woodhouse if (!ic->pino_nlink) { 1929c261b33SJoe Perches jffs2_dbg(1, "Skipping check of ino #%d with nlink/pino zero\n", 1939c261b33SJoe Perches ic->ino); 1941da177e4SLinus Torvalds spin_unlock(&c->inocache_lock); 195355ed4e1SKaiGai Kohei jffs2_xattr_delete_inode(c, ic); 1961da177e4SLinus Torvalds continue; 1971da177e4SLinus Torvalds } 1981da177e4SLinus Torvalds switch(ic->state) { 1991da177e4SLinus Torvalds case INO_STATE_CHECKEDABSENT: 2001da177e4SLinus Torvalds case INO_STATE_PRESENT: 2011da177e4SLinus Torvalds spin_unlock(&c->inocache_lock); 2021da177e4SLinus Torvalds continue; 2031da177e4SLinus Torvalds 2041da177e4SLinus Torvalds case INO_STATE_GC: 2051da177e4SLinus Torvalds case INO_STATE_CHECKING: 206da320f05SJoe Perches pr_warn("Inode #%u is in state %d during CRC check phase!\n", 207da320f05SJoe Perches ic->ino, ic->state); 2081da177e4SLinus Torvalds spin_unlock(&c->inocache_lock); 2091da177e4SLinus Torvalds BUG(); 2101da177e4SLinus Torvalds 2111da177e4SLinus Torvalds case INO_STATE_READING: 2121da177e4SLinus Torvalds /* We need to wait for it to finish, lest we move on 2131da177e4SLinus Torvalds and trigger the BUG() above while we haven't yet 2141da177e4SLinus Torvalds finished checking all its nodes */ 2159c261b33SJoe Perches jffs2_dbg(1, "Waiting for ino #%u to finish reading\n", 2169c261b33SJoe Perches ic->ino); 217d96fb997SDavid Woodhouse /* We need to come back again for the _same_ inode. We've 218d96fb997SDavid Woodhouse made no progress in this case, but that should be OK */ 219*5817b9dcSDavid Woodhouse c->check_ino = ic->ino; 220d96fb997SDavid Woodhouse 221ced22070SDavid Woodhouse mutex_unlock(&c->alloc_sem); 2221da177e4SLinus Torvalds sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock); 2231da177e4SLinus Torvalds return 0; 2241da177e4SLinus Torvalds 2251da177e4SLinus Torvalds default: 2261da177e4SLinus Torvalds BUG(); 2271da177e4SLinus Torvalds 2281da177e4SLinus Torvalds case INO_STATE_UNCHECKED: 2291da177e4SLinus Torvalds ; 2301da177e4SLinus Torvalds } 2311da177e4SLinus Torvalds ic->state = INO_STATE_CHECKING; 2321da177e4SLinus Torvalds spin_unlock(&c->inocache_lock); 2331da177e4SLinus Torvalds 2349c261b33SJoe Perches jffs2_dbg(1, "%s(): triggering inode scan of ino#%u\n", 2359c261b33SJoe Perches __func__, ic->ino); 2361da177e4SLinus Torvalds 2371da177e4SLinus Torvalds ret = jffs2_do_crccheck_inode(c, ic); 2381da177e4SLinus Torvalds if (ret) 239da320f05SJoe Perches pr_warn("Returned error for crccheck of ino #%u. Expect badness...\n", 240da320f05SJoe Perches ic->ino); 2411da177e4SLinus Torvalds 2421da177e4SLinus Torvalds jffs2_set_inocache_state(c, ic, INO_STATE_CHECKEDABSENT); 243ced22070SDavid Woodhouse mutex_unlock(&c->alloc_sem); 2441da177e4SLinus Torvalds return ret; 2451da177e4SLinus Torvalds } 2461da177e4SLinus Torvalds 2470717bf84SDavid Woodhouse /* If there are any blocks which need erasing, erase them now */ 2480717bf84SDavid Woodhouse if (!list_empty(&c->erase_complete_list) || 2490717bf84SDavid Woodhouse !list_empty(&c->erase_pending_list)) { 2500717bf84SDavid Woodhouse spin_unlock(&c->erase_completion_lock); 2510717bf84SDavid Woodhouse mutex_unlock(&c->alloc_sem); 2529c261b33SJoe Perches jffs2_dbg(1, "%s(): erasing pending blocks\n", __func__); 25381cfc9f1SJoakim Tjernlund if (jffs2_erase_pending_blocks(c, 1)) 2540717bf84SDavid Woodhouse return 0; 25581cfc9f1SJoakim Tjernlund 2569c261b33SJoe Perches jffs2_dbg(1, "No progress from erasing block; doing GC anyway\n"); 25781cfc9f1SJoakim Tjernlund mutex_lock(&c->alloc_sem); 258226bb7dfSJosh Cartwright spin_lock(&c->erase_completion_lock); 2590717bf84SDavid Woodhouse } 2600717bf84SDavid Woodhouse 2611da177e4SLinus Torvalds /* First, work out which block we're garbage-collecting */ 2621da177e4SLinus Torvalds jeb = c->gcblock; 2631da177e4SLinus Torvalds 2641da177e4SLinus Torvalds if (!jeb) 2651da177e4SLinus Torvalds jeb = jffs2_find_gc_block(c); 2661da177e4SLinus Torvalds 2671da177e4SLinus Torvalds if (!jeb) { 268422b1202SDavid Woodhouse /* Couldn't find a free block. But maybe we can just erase one and make 'progress'? */ 2690717bf84SDavid Woodhouse if (c->nr_erasing_blocks) { 270422b1202SDavid Woodhouse spin_unlock(&c->erase_completion_lock); 271422b1202SDavid Woodhouse mutex_unlock(&c->alloc_sem); 272422b1202SDavid Woodhouse return -EAGAIN; 273422b1202SDavid Woodhouse } 2745a528957SJoe Perches jffs2_dbg(1, "Couldn't find erase block to garbage collect!\n"); 2751da177e4SLinus Torvalds spin_unlock(&c->erase_completion_lock); 276ced22070SDavid Woodhouse mutex_unlock(&c->alloc_sem); 2771da177e4SLinus Torvalds return -EIO; 2781da177e4SLinus Torvalds } 2791da177e4SLinus Torvalds 2809c261b33SJoe Perches jffs2_dbg(1, "GC from block %08x, used_size %08x, dirty_size %08x, free_size %08x\n", 2819c261b33SJoe Perches jeb->offset, jeb->used_size, jeb->dirty_size, jeb->free_size); 2821da177e4SLinus Torvalds D1(if (c->nextblock) 2831da177e4SLinus Torvalds printk(KERN_DEBUG "Nextblock at %08x, used_size %08x, dirty_size %08x, wasted_size %08x, free_size %08x\n", c->nextblock->offset, c->nextblock->used_size, c->nextblock->dirty_size, c->nextblock->wasted_size, c->nextblock->free_size)); 2841da177e4SLinus Torvalds 2851da177e4SLinus Torvalds if (!jeb->used_size) { 286ced22070SDavid Woodhouse mutex_unlock(&c->alloc_sem); 2871da177e4SLinus Torvalds goto eraseit; 2881da177e4SLinus Torvalds } 2891da177e4SLinus Torvalds 2901da177e4SLinus Torvalds raw = jeb->gc_node; 2912665ea84SDavid Woodhouse gcblock_dirty = jeb->dirty_size; 2921da177e4SLinus Torvalds 2931da177e4SLinus Torvalds while(ref_obsolete(raw)) { 2949c261b33SJoe Perches jffs2_dbg(1, "Node at 0x%08x is obsolete... skipping\n", 2959c261b33SJoe Perches ref_offset(raw)); 29699988f7bSDavid Woodhouse raw = ref_next(raw); 2971da177e4SLinus Torvalds if (unlikely(!raw)) { 298da320f05SJoe Perches pr_warn("eep. End of raw list while still supposedly nodes to GC\n"); 299da320f05SJoe Perches pr_warn("erase block at 0x%08x. free_size 0x%08x, dirty_size 0x%08x, used_size 0x%08x\n", 300da320f05SJoe Perches jeb->offset, jeb->free_size, 301da320f05SJoe Perches jeb->dirty_size, jeb->used_size); 3021da177e4SLinus Torvalds jeb->gc_node = raw; 3031da177e4SLinus Torvalds spin_unlock(&c->erase_completion_lock); 304ced22070SDavid Woodhouse mutex_unlock(&c->alloc_sem); 3051da177e4SLinus Torvalds BUG(); 3061da177e4SLinus Torvalds } 3071da177e4SLinus Torvalds } 3081da177e4SLinus Torvalds jeb->gc_node = raw; 3091da177e4SLinus Torvalds 3109c261b33SJoe Perches jffs2_dbg(1, "Going to garbage collect node at 0x%08x\n", 3119c261b33SJoe Perches ref_offset(raw)); 3121da177e4SLinus Torvalds 3131da177e4SLinus Torvalds if (!raw->next_in_ino) { 3141da177e4SLinus Torvalds /* Inode-less node. Clean marker, snapshot or something like that */ 3151da177e4SLinus Torvalds spin_unlock(&c->erase_completion_lock); 3166171586aSDavid Woodhouse if (ref_flags(raw) == REF_PRISTINE) { 3176171586aSDavid Woodhouse /* It's an unknown node with JFFS2_FEATURE_RWCOMPAT_COPY */ 3186171586aSDavid Woodhouse jffs2_garbage_collect_pristine(c, NULL, raw); 3196171586aSDavid Woodhouse } else { 3206171586aSDavid Woodhouse /* Just mark it obsolete */ 3211da177e4SLinus Torvalds jffs2_mark_node_obsolete(c, raw); 3226171586aSDavid Woodhouse } 323ced22070SDavid Woodhouse mutex_unlock(&c->alloc_sem); 3241da177e4SLinus Torvalds goto eraseit_lock; 3251da177e4SLinus Torvalds } 3261da177e4SLinus Torvalds 3271da177e4SLinus Torvalds ic = jffs2_raw_ref_to_ic(raw); 3281da177e4SLinus Torvalds 329084702e0SKaiGai Kohei #ifdef CONFIG_JFFS2_FS_XATTR 330aa98d7cfSKaiGai Kohei /* When 'ic' refers xattr_datum/xattr_ref, this node is GCed as xattr. 331084702e0SKaiGai Kohei * We can decide whether this node is inode or xattr by ic->class. */ 332084702e0SKaiGai Kohei if (ic->class == RAWNODE_CLASS_XATTR_DATUM 333084702e0SKaiGai Kohei || ic->class == RAWNODE_CLASS_XATTR_REF) { 334084702e0SKaiGai Kohei spin_unlock(&c->erase_completion_lock); 335084702e0SKaiGai Kohei 336084702e0SKaiGai Kohei if (ic->class == RAWNODE_CLASS_XATTR_DATUM) { 337c9f700f8SKaiGai Kohei ret = jffs2_garbage_collect_xattr_datum(c, (struct jffs2_xattr_datum *)ic, raw); 338084702e0SKaiGai Kohei } else { 339c9f700f8SKaiGai Kohei ret = jffs2_garbage_collect_xattr_ref(c, (struct jffs2_xattr_ref *)ic, raw); 340084702e0SKaiGai Kohei } 3412665ea84SDavid Woodhouse goto test_gcnode; 342084702e0SKaiGai Kohei } 343084702e0SKaiGai Kohei #endif 344aa98d7cfSKaiGai Kohei 3451da177e4SLinus Torvalds /* We need to hold the inocache. Either the erase_completion_lock or 3461da177e4SLinus Torvalds the inocache_lock are sufficient; we trade down since the inocache_lock 3471da177e4SLinus Torvalds causes less contention. */ 3481da177e4SLinus Torvalds spin_lock(&c->inocache_lock); 3491da177e4SLinus Torvalds 3501da177e4SLinus Torvalds spin_unlock(&c->erase_completion_lock); 3511da177e4SLinus Torvalds 3529c261b33SJoe Perches jffs2_dbg(1, "%s(): collecting from block @0x%08x. Node @0x%08x(%d), ino #%u\n", 3539c261b33SJoe Perches __func__, jeb->offset, ref_offset(raw), ref_flags(raw), 3549c261b33SJoe Perches ic->ino); 3551da177e4SLinus Torvalds 3561da177e4SLinus Torvalds /* Three possibilities: 3571da177e4SLinus Torvalds 1. Inode is already in-core. We must iget it and do proper 3581da177e4SLinus Torvalds updating to its fragtree, etc. 3591da177e4SLinus Torvalds 2. Inode is not in-core, node is REF_PRISTINE. We lock the 3601da177e4SLinus Torvalds inocache to prevent a read_inode(), copy the node intact. 3611da177e4SLinus Torvalds 3. Inode is not in-core, node is not pristine. We must iget() 3621da177e4SLinus Torvalds and take the slow path. 3631da177e4SLinus Torvalds */ 3641da177e4SLinus Torvalds 3651da177e4SLinus Torvalds switch(ic->state) { 3661da177e4SLinus Torvalds case INO_STATE_CHECKEDABSENT: 3671da177e4SLinus Torvalds /* It's been checked, but it's not currently in-core. 3681da177e4SLinus Torvalds We can just copy any pristine nodes, but have 3691da177e4SLinus Torvalds to prevent anyone else from doing read_inode() while 3701da177e4SLinus Torvalds we're at it, so we set the state accordingly */ 3711da177e4SLinus Torvalds if (ref_flags(raw) == REF_PRISTINE) 3721da177e4SLinus Torvalds ic->state = INO_STATE_GC; 3731da177e4SLinus Torvalds else { 3749c261b33SJoe Perches jffs2_dbg(1, "Ino #%u is absent but node not REF_PRISTINE. Reading.\n", 3759c261b33SJoe Perches ic->ino); 3761da177e4SLinus Torvalds } 3771da177e4SLinus Torvalds break; 3781da177e4SLinus Torvalds 3791da177e4SLinus Torvalds case INO_STATE_PRESENT: 3801da177e4SLinus Torvalds /* It's in-core. GC must iget() it. */ 3811da177e4SLinus Torvalds break; 3821da177e4SLinus Torvalds 3831da177e4SLinus Torvalds case INO_STATE_UNCHECKED: 3841da177e4SLinus Torvalds case INO_STATE_CHECKING: 3851da177e4SLinus Torvalds case INO_STATE_GC: 3861da177e4SLinus Torvalds /* Should never happen. We should have finished checking 3871da177e4SLinus Torvalds by the time we actually start doing any GC, and since 3881da177e4SLinus Torvalds we're holding the alloc_sem, no other garbage collection 3891da177e4SLinus Torvalds can happen. 3901da177e4SLinus Torvalds */ 391da320f05SJoe Perches pr_crit("Inode #%u already in state %d in jffs2_garbage_collect_pass()!\n", 3921da177e4SLinus Torvalds ic->ino, ic->state); 393ced22070SDavid Woodhouse mutex_unlock(&c->alloc_sem); 3941da177e4SLinus Torvalds spin_unlock(&c->inocache_lock); 3951da177e4SLinus Torvalds BUG(); 3961da177e4SLinus Torvalds 3971da177e4SLinus Torvalds case INO_STATE_READING: 3981da177e4SLinus Torvalds /* Someone's currently trying to read it. We must wait for 3991da177e4SLinus Torvalds them to finish and then go through the full iget() route 4001da177e4SLinus Torvalds to do the GC. However, sometimes read_inode() needs to get 4011da177e4SLinus Torvalds the alloc_sem() (for marking nodes invalid) so we must 4021da177e4SLinus Torvalds drop the alloc_sem before sleeping. */ 4031da177e4SLinus Torvalds 404ced22070SDavid Woodhouse mutex_unlock(&c->alloc_sem); 4059c261b33SJoe Perches jffs2_dbg(1, "%s(): waiting for ino #%u in state %d\n", 4069c261b33SJoe Perches __func__, ic->ino, ic->state); 4071da177e4SLinus Torvalds sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock); 4081da177e4SLinus Torvalds /* And because we dropped the alloc_sem we must start again from the 4091da177e4SLinus Torvalds beginning. Ponder chance of livelock here -- we're returning success 4101da177e4SLinus Torvalds without actually making any progress. 4111da177e4SLinus Torvalds 4121da177e4SLinus Torvalds Q: What are the chances that the inode is back in INO_STATE_READING 4131da177e4SLinus Torvalds again by the time we next enter this function? And that this happens 4141da177e4SLinus Torvalds enough times to cause a real delay? 4151da177e4SLinus Torvalds 4161da177e4SLinus Torvalds A: Small enough that I don't care :) 4171da177e4SLinus Torvalds */ 4181da177e4SLinus Torvalds return 0; 4191da177e4SLinus Torvalds } 4201da177e4SLinus Torvalds 4211da177e4SLinus Torvalds /* OK. Now if the inode is in state INO_STATE_GC, we are going to copy the 4221da177e4SLinus Torvalds node intact, and we don't have to muck about with the fragtree etc. 4231da177e4SLinus Torvalds because we know it's not in-core. If it _was_ in-core, we go through 4241da177e4SLinus Torvalds all the iget() crap anyway */ 4251da177e4SLinus Torvalds 4261da177e4SLinus Torvalds if (ic->state == INO_STATE_GC) { 4271da177e4SLinus Torvalds spin_unlock(&c->inocache_lock); 4281da177e4SLinus Torvalds 4291da177e4SLinus Torvalds ret = jffs2_garbage_collect_pristine(c, ic, raw); 4301da177e4SLinus Torvalds 4311da177e4SLinus Torvalds spin_lock(&c->inocache_lock); 4321da177e4SLinus Torvalds ic->state = INO_STATE_CHECKEDABSENT; 4331da177e4SLinus Torvalds wake_up(&c->inocache_wq); 4341da177e4SLinus Torvalds 4351da177e4SLinus Torvalds if (ret != -EBADFD) { 4361da177e4SLinus Torvalds spin_unlock(&c->inocache_lock); 4372665ea84SDavid Woodhouse goto test_gcnode; 4381da177e4SLinus Torvalds } 4391da177e4SLinus Torvalds 4401da177e4SLinus Torvalds /* Fall through if it wanted us to, with inocache_lock held */ 4411da177e4SLinus Torvalds } 4421da177e4SLinus Torvalds 4431da177e4SLinus Torvalds /* Prevent the fairly unlikely race where the gcblock is 4441da177e4SLinus Torvalds entirely obsoleted by the final close of a file which had 4451da177e4SLinus Torvalds the only valid nodes in the block, followed by erasure, 4461da177e4SLinus Torvalds followed by freeing of the ic because the erased block(s) 4471da177e4SLinus Torvalds held _all_ the nodes of that inode.... never been seen but 4481da177e4SLinus Torvalds it's vaguely possible. */ 4491da177e4SLinus Torvalds 4501da177e4SLinus Torvalds inum = ic->ino; 45127c72b04SDavid Woodhouse nlink = ic->pino_nlink; 4521da177e4SLinus Torvalds spin_unlock(&c->inocache_lock); 4531da177e4SLinus Torvalds 4541b690b48SDavid Woodhouse f = jffs2_gc_fetch_inode(c, inum, !nlink); 4551da177e4SLinus Torvalds if (IS_ERR(f)) { 4561da177e4SLinus Torvalds ret = PTR_ERR(f); 4571da177e4SLinus Torvalds goto release_sem; 4581da177e4SLinus Torvalds } 4591da177e4SLinus Torvalds if (!f) { 4601da177e4SLinus Torvalds ret = 0; 4611da177e4SLinus Torvalds goto release_sem; 4621da177e4SLinus Torvalds } 4631da177e4SLinus Torvalds 4641da177e4SLinus Torvalds ret = jffs2_garbage_collect_live(c, jeb, raw, f); 4651da177e4SLinus Torvalds 4661da177e4SLinus Torvalds jffs2_gc_release_inode(c, f); 4671da177e4SLinus Torvalds 4682665ea84SDavid Woodhouse test_gcnode: 4692665ea84SDavid Woodhouse if (jeb->dirty_size == gcblock_dirty && !ref_obsolete(jeb->gc_node)) { 4702665ea84SDavid Woodhouse /* Eep. This really should never happen. GC is broken */ 471da320f05SJoe Perches pr_err("Error garbage collecting node at %08x!\n", 472da320f05SJoe Perches ref_offset(jeb->gc_node)); 4732665ea84SDavid Woodhouse ret = -ENOSPC; 4744fc8a607SDavid Woodhouse } 4751da177e4SLinus Torvalds release_sem: 476ced22070SDavid Woodhouse mutex_unlock(&c->alloc_sem); 4771da177e4SLinus Torvalds 4781da177e4SLinus Torvalds eraseit_lock: 4791da177e4SLinus Torvalds /* If we've finished this block, start it erasing */ 4801da177e4SLinus Torvalds spin_lock(&c->erase_completion_lock); 4811da177e4SLinus Torvalds 4821da177e4SLinus Torvalds eraseit: 4831da177e4SLinus Torvalds if (c->gcblock && !c->gcblock->used_size) { 4849c261b33SJoe Perches jffs2_dbg(1, "Block at 0x%08x completely obsoleted by GC. Moving to erase_pending_list\n", 4859c261b33SJoe Perches c->gcblock->offset); 4861da177e4SLinus Torvalds /* We're GC'ing an empty block? */ 4871da177e4SLinus Torvalds list_add_tail(&c->gcblock->list, &c->erase_pending_list); 4881da177e4SLinus Torvalds c->gcblock = NULL; 4891da177e4SLinus Torvalds c->nr_erasing_blocks++; 490ae3b6ba0SDavid Woodhouse jffs2_garbage_collect_trigger(c); 4911da177e4SLinus Torvalds } 4921da177e4SLinus Torvalds spin_unlock(&c->erase_completion_lock); 4931da177e4SLinus Torvalds 4941da177e4SLinus Torvalds return ret; 4951da177e4SLinus Torvalds } 4961da177e4SLinus Torvalds 4971da177e4SLinus Torvalds static int jffs2_garbage_collect_live(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, 4981da177e4SLinus Torvalds struct jffs2_raw_node_ref *raw, struct jffs2_inode_info *f) 4991da177e4SLinus Torvalds { 5001da177e4SLinus Torvalds struct jffs2_node_frag *frag; 5011da177e4SLinus Torvalds struct jffs2_full_dnode *fn = NULL; 5021da177e4SLinus Torvalds struct jffs2_full_dirent *fd; 5031da177e4SLinus Torvalds uint32_t start = 0, end = 0, nrfrags = 0; 5041da177e4SLinus Torvalds int ret = 0; 5051da177e4SLinus Torvalds 506ced22070SDavid Woodhouse mutex_lock(&f->sem); 5071da177e4SLinus Torvalds 5081da177e4SLinus Torvalds /* Now we have the lock for this inode. Check that it's still the one at the head 5091da177e4SLinus Torvalds of the list. */ 5101da177e4SLinus Torvalds 5111da177e4SLinus Torvalds spin_lock(&c->erase_completion_lock); 5121da177e4SLinus Torvalds 5131da177e4SLinus Torvalds if (c->gcblock != jeb) { 5141da177e4SLinus Torvalds spin_unlock(&c->erase_completion_lock); 5159c261b33SJoe Perches jffs2_dbg(1, "GC block is no longer gcblock. Restart\n"); 5161da177e4SLinus Torvalds goto upnout; 5171da177e4SLinus Torvalds } 5181da177e4SLinus Torvalds if (ref_obsolete(raw)) { 5191da177e4SLinus Torvalds spin_unlock(&c->erase_completion_lock); 5209c261b33SJoe Perches jffs2_dbg(1, "node to be GC'd was obsoleted in the meantime.\n"); 5211da177e4SLinus Torvalds /* They'll call again */ 5221da177e4SLinus Torvalds goto upnout; 5231da177e4SLinus Torvalds } 5241da177e4SLinus Torvalds spin_unlock(&c->erase_completion_lock); 5251da177e4SLinus Torvalds 5261da177e4SLinus Torvalds /* OK. Looks safe. And nobody can get us now because we have the semaphore. Move the block */ 5271da177e4SLinus Torvalds if (f->metadata && f->metadata->raw == raw) { 5281da177e4SLinus Torvalds fn = f->metadata; 5291da177e4SLinus Torvalds ret = jffs2_garbage_collect_metadata(c, jeb, f, fn); 5301da177e4SLinus Torvalds goto upnout; 5311da177e4SLinus Torvalds } 5321da177e4SLinus Torvalds 5331da177e4SLinus Torvalds /* FIXME. Read node and do lookup? */ 5341da177e4SLinus Torvalds for (frag = frag_first(&f->fragtree); frag; frag = frag_next(frag)) { 5351da177e4SLinus Torvalds if (frag->node && frag->node->raw == raw) { 5361da177e4SLinus Torvalds fn = frag->node; 5371da177e4SLinus Torvalds end = frag->ofs + frag->size; 5381da177e4SLinus Torvalds if (!nrfrags++) 5391da177e4SLinus Torvalds start = frag->ofs; 5401da177e4SLinus Torvalds if (nrfrags == frag->node->frags) 5411da177e4SLinus Torvalds break; /* We've found them all */ 5421da177e4SLinus Torvalds } 5431da177e4SLinus Torvalds } 5441da177e4SLinus Torvalds if (fn) { 5451da177e4SLinus Torvalds if (ref_flags(raw) == REF_PRISTINE) { 5461da177e4SLinus Torvalds ret = jffs2_garbage_collect_pristine(c, f->inocache, raw); 5471da177e4SLinus Torvalds if (!ret) { 5481da177e4SLinus Torvalds /* Urgh. Return it sensibly. */ 5491da177e4SLinus Torvalds frag->node->raw = f->inocache->nodes; 5501da177e4SLinus Torvalds } 5511da177e4SLinus Torvalds if (ret != -EBADFD) 5521da177e4SLinus Torvalds goto upnout; 5531da177e4SLinus Torvalds } 5541da177e4SLinus Torvalds /* We found a datanode. Do the GC */ 5551da177e4SLinus Torvalds if((start >> PAGE_CACHE_SHIFT) < ((end-1) >> PAGE_CACHE_SHIFT)) { 5561da177e4SLinus Torvalds /* It crosses a page boundary. Therefore, it must be a hole. */ 5571da177e4SLinus Torvalds ret = jffs2_garbage_collect_hole(c, jeb, f, fn, start, end); 5581da177e4SLinus Torvalds } else { 5591da177e4SLinus Torvalds /* It could still be a hole. But we GC the page this way anyway */ 5601da177e4SLinus Torvalds ret = jffs2_garbage_collect_dnode(c, jeb, f, fn, start, end); 5611da177e4SLinus Torvalds } 5621da177e4SLinus Torvalds goto upnout; 5631da177e4SLinus Torvalds } 5641da177e4SLinus Torvalds 5651da177e4SLinus Torvalds /* Wasn't a dnode. Try dirent */ 5661da177e4SLinus Torvalds for (fd = f->dents; fd; fd=fd->next) { 5671da177e4SLinus Torvalds if (fd->raw == raw) 5681da177e4SLinus Torvalds break; 5691da177e4SLinus Torvalds } 5701da177e4SLinus Torvalds 5711da177e4SLinus Torvalds if (fd && fd->ino) { 5721da177e4SLinus Torvalds ret = jffs2_garbage_collect_dirent(c, jeb, f, fd); 5731da177e4SLinus Torvalds } else if (fd) { 5741da177e4SLinus Torvalds ret = jffs2_garbage_collect_deletion_dirent(c, jeb, f, fd); 5751da177e4SLinus Torvalds } else { 576da320f05SJoe Perches pr_warn("Raw node at 0x%08x wasn't in node lists for ino #%u\n", 5771da177e4SLinus Torvalds ref_offset(raw), f->inocache->ino); 5781da177e4SLinus Torvalds if (ref_obsolete(raw)) { 579da320f05SJoe Perches pr_warn("But it's obsolete so we don't mind too much\n"); 5801da177e4SLinus Torvalds } else { 581e0c8e42fSArtem B. Bityutskiy jffs2_dbg_dump_node(c, ref_offset(raw)); 582e0c8e42fSArtem B. Bityutskiy BUG(); 5831da177e4SLinus Torvalds } 5841da177e4SLinus Torvalds } 5851da177e4SLinus Torvalds upnout: 586ced22070SDavid Woodhouse mutex_unlock(&f->sem); 5871da177e4SLinus Torvalds 5881da177e4SLinus Torvalds return ret; 5891da177e4SLinus Torvalds } 5901da177e4SLinus Torvalds 5911da177e4SLinus Torvalds static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, 5921da177e4SLinus Torvalds struct jffs2_inode_cache *ic, 5931da177e4SLinus Torvalds struct jffs2_raw_node_ref *raw) 5941da177e4SLinus Torvalds { 5951da177e4SLinus Torvalds union jffs2_node_union *node; 5961da177e4SLinus Torvalds size_t retlen; 5971da177e4SLinus Torvalds int ret; 5981da177e4SLinus Torvalds uint32_t phys_ofs, alloclen; 5991da177e4SLinus Torvalds uint32_t crc, rawlen; 6001da177e4SLinus Torvalds int retried = 0; 6011da177e4SLinus Torvalds 6029c261b33SJoe Perches jffs2_dbg(1, "Going to GC REF_PRISTINE node at 0x%08x\n", 6039c261b33SJoe Perches ref_offset(raw)); 6041da177e4SLinus Torvalds 6056171586aSDavid Woodhouse alloclen = rawlen = ref_totlen(c, c->gcblock, raw); 6061da177e4SLinus Torvalds 6071da177e4SLinus Torvalds /* Ask for a small amount of space (or the totlen if smaller) because we 6081da177e4SLinus Torvalds don't want to force wastage of the end of a block if splitting would 6091da177e4SLinus Torvalds work. */ 6106171586aSDavid Woodhouse if (ic && alloclen > sizeof(struct jffs2_raw_inode) + JFFS2_MIN_DATA_LEN) 6116171586aSDavid Woodhouse alloclen = sizeof(struct jffs2_raw_inode) + JFFS2_MIN_DATA_LEN; 6126171586aSDavid Woodhouse 6139fe4854cSDavid Woodhouse ret = jffs2_reserve_space_gc(c, alloclen, &alloclen, rawlen); 6146171586aSDavid Woodhouse /* 'rawlen' is not the exact summary size; it is only an upper estimation */ 615e631ddbaSFerenc Havasi 6161da177e4SLinus Torvalds if (ret) 6171da177e4SLinus Torvalds return ret; 6181da177e4SLinus Torvalds 6191da177e4SLinus Torvalds if (alloclen < rawlen) { 6201da177e4SLinus Torvalds /* Doesn't fit untouched. We'll go the old route and split it */ 6211da177e4SLinus Torvalds return -EBADFD; 6221da177e4SLinus Torvalds } 6231da177e4SLinus Torvalds 6241da177e4SLinus Torvalds node = kmalloc(rawlen, GFP_KERNEL); 6251da177e4SLinus Torvalds if (!node) 6261da177e4SLinus Torvalds return -ENOMEM; 6271da177e4SLinus Torvalds 6281da177e4SLinus Torvalds ret = jffs2_flash_read(c, ref_offset(raw), rawlen, &retlen, (char *)node); 6291da177e4SLinus Torvalds if (!ret && retlen != rawlen) 6301da177e4SLinus Torvalds ret = -EIO; 6311da177e4SLinus Torvalds if (ret) 6321da177e4SLinus Torvalds goto out_node; 6331da177e4SLinus Torvalds 6341da177e4SLinus Torvalds crc = crc32(0, node, sizeof(struct jffs2_unknown_node)-4); 6351da177e4SLinus Torvalds if (je32_to_cpu(node->u.hdr_crc) != crc) { 636da320f05SJoe Perches pr_warn("Header CRC failed on REF_PRISTINE node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", 6371da177e4SLinus Torvalds ref_offset(raw), je32_to_cpu(node->u.hdr_crc), crc); 6381da177e4SLinus Torvalds goto bail; 6391da177e4SLinus Torvalds } 6401da177e4SLinus Torvalds 6411da177e4SLinus Torvalds switch(je16_to_cpu(node->u.nodetype)) { 6421da177e4SLinus Torvalds case JFFS2_NODETYPE_INODE: 6431da177e4SLinus Torvalds crc = crc32(0, node, sizeof(node->i)-8); 6441da177e4SLinus Torvalds if (je32_to_cpu(node->i.node_crc) != crc) { 645da320f05SJoe Perches pr_warn("Node CRC failed on REF_PRISTINE data node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", 646da320f05SJoe Perches ref_offset(raw), je32_to_cpu(node->i.node_crc), 647da320f05SJoe Perches crc); 6481da177e4SLinus Torvalds goto bail; 6491da177e4SLinus Torvalds } 6501da177e4SLinus Torvalds 6511da177e4SLinus Torvalds if (je32_to_cpu(node->i.dsize)) { 6521da177e4SLinus Torvalds crc = crc32(0, node->i.data, je32_to_cpu(node->i.csize)); 6531da177e4SLinus Torvalds if (je32_to_cpu(node->i.data_crc) != crc) { 654da320f05SJoe Perches pr_warn("Data CRC failed on REF_PRISTINE data node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", 655da320f05SJoe Perches ref_offset(raw), 656da320f05SJoe Perches je32_to_cpu(node->i.data_crc), crc); 6571da177e4SLinus Torvalds goto bail; 6581da177e4SLinus Torvalds } 6591da177e4SLinus Torvalds } 6601da177e4SLinus Torvalds break; 6611da177e4SLinus Torvalds 6621da177e4SLinus Torvalds case JFFS2_NODETYPE_DIRENT: 6631da177e4SLinus Torvalds crc = crc32(0, node, sizeof(node->d)-8); 6641da177e4SLinus Torvalds if (je32_to_cpu(node->d.node_crc) != crc) { 665da320f05SJoe Perches pr_warn("Node CRC failed on REF_PRISTINE dirent node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", 666da320f05SJoe Perches ref_offset(raw), 667da320f05SJoe Perches je32_to_cpu(node->d.node_crc), crc); 6681da177e4SLinus Torvalds goto bail; 6691da177e4SLinus Torvalds } 6701da177e4SLinus Torvalds 671b534e70cSDavid Woodhouse if (strnlen(node->d.name, node->d.nsize) != node->d.nsize) { 672da320f05SJoe Perches pr_warn("Name in dirent node at 0x%08x contains zeroes\n", 673da320f05SJoe Perches ref_offset(raw)); 674b534e70cSDavid Woodhouse goto bail; 675b534e70cSDavid Woodhouse } 676b534e70cSDavid Woodhouse 6771da177e4SLinus Torvalds if (node->d.nsize) { 6781da177e4SLinus Torvalds crc = crc32(0, node->d.name, node->d.nsize); 6791da177e4SLinus Torvalds if (je32_to_cpu(node->d.name_crc) != crc) { 680da320f05SJoe Perches pr_warn("Name CRC failed on REF_PRISTINE dirent node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", 681da320f05SJoe Perches ref_offset(raw), 682da320f05SJoe Perches je32_to_cpu(node->d.name_crc), crc); 6831da177e4SLinus Torvalds goto bail; 6841da177e4SLinus Torvalds } 6851da177e4SLinus Torvalds } 6861da177e4SLinus Torvalds break; 6871da177e4SLinus Torvalds default: 6886171586aSDavid Woodhouse /* If it's inode-less, we don't _know_ what it is. Just copy it intact */ 6896171586aSDavid Woodhouse if (ic) { 690da320f05SJoe Perches pr_warn("Unknown node type for REF_PRISTINE node at 0x%08x: 0x%04x\n", 6911da177e4SLinus Torvalds ref_offset(raw), je16_to_cpu(node->u.nodetype)); 6921da177e4SLinus Torvalds goto bail; 6931da177e4SLinus Torvalds } 6946171586aSDavid Woodhouse } 6951da177e4SLinus Torvalds 6961da177e4SLinus Torvalds /* OK, all the CRCs are good; this node can just be copied as-is. */ 6971da177e4SLinus Torvalds retry: 6982f785402SDavid Woodhouse phys_ofs = write_ofs(c); 6991da177e4SLinus Torvalds 7001da177e4SLinus Torvalds ret = jffs2_flash_write(c, phys_ofs, rawlen, &retlen, (char *)node); 7011da177e4SLinus Torvalds 7021da177e4SLinus Torvalds if (ret || (retlen != rawlen)) { 703da320f05SJoe Perches pr_notice("Write of %d bytes at 0x%08x failed. returned %d, retlen %zd\n", 7042f785402SDavid Woodhouse rawlen, phys_ofs, ret, retlen); 7051da177e4SLinus Torvalds if (retlen) { 7062f785402SDavid Woodhouse jffs2_add_physical_node_ref(c, phys_ofs | REF_OBSOLETE, rawlen, NULL); 7071da177e4SLinus Torvalds } else { 708da320f05SJoe Perches pr_notice("Not marking the space at 0x%08x as dirty because the flash driver returned retlen zero\n", 709da320f05SJoe Perches phys_ofs); 7101da177e4SLinus Torvalds } 7112f785402SDavid Woodhouse if (!retried) { 7121da177e4SLinus Torvalds /* Try to reallocate space and retry */ 7131da177e4SLinus Torvalds uint32_t dummy; 7141da177e4SLinus Torvalds struct jffs2_eraseblock *jeb = &c->blocks[phys_ofs / c->sector_size]; 7151da177e4SLinus Torvalds 7161da177e4SLinus Torvalds retried = 1; 7171da177e4SLinus Torvalds 7189c261b33SJoe Perches jffs2_dbg(1, "Retrying failed write of REF_PRISTINE node.\n"); 7191da177e4SLinus Torvalds 720730554d9SArtem B. Bityutskiy jffs2_dbg_acct_sanity_check(c,jeb); 721730554d9SArtem B. Bityutskiy jffs2_dbg_acct_paranoia_check(c, jeb); 7221da177e4SLinus Torvalds 7239fe4854cSDavid Woodhouse ret = jffs2_reserve_space_gc(c, rawlen, &dummy, rawlen); 724e631ddbaSFerenc Havasi /* this is not the exact summary size of it, 725e631ddbaSFerenc Havasi it is only an upper estimation */ 7261da177e4SLinus Torvalds 7271da177e4SLinus Torvalds if (!ret) { 7289c261b33SJoe Perches jffs2_dbg(1, "Allocated space at 0x%08x to retry failed write.\n", 7299c261b33SJoe Perches phys_ofs); 7301da177e4SLinus Torvalds 731730554d9SArtem B. Bityutskiy jffs2_dbg_acct_sanity_check(c,jeb); 732730554d9SArtem B. Bityutskiy jffs2_dbg_acct_paranoia_check(c, jeb); 7331da177e4SLinus Torvalds 7341da177e4SLinus Torvalds goto retry; 7351da177e4SLinus Torvalds } 7369c261b33SJoe Perches jffs2_dbg(1, "Failed to allocate space to retry failed write: %d!\n", 7379c261b33SJoe Perches ret); 7381da177e4SLinus Torvalds } 7391da177e4SLinus Torvalds 7401da177e4SLinus Torvalds if (!ret) 7411da177e4SLinus Torvalds ret = -EIO; 7421da177e4SLinus Torvalds goto out_node; 7431da177e4SLinus Torvalds } 7442f785402SDavid Woodhouse jffs2_add_physical_node_ref(c, phys_ofs | REF_PRISTINE, rawlen, ic); 7451da177e4SLinus Torvalds 7461da177e4SLinus Torvalds jffs2_mark_node_obsolete(c, raw); 7479c261b33SJoe Perches jffs2_dbg(1, "WHEEE! GC REF_PRISTINE node at 0x%08x succeeded\n", 7489c261b33SJoe Perches ref_offset(raw)); 7491da177e4SLinus Torvalds 7501da177e4SLinus Torvalds out_node: 7511da177e4SLinus Torvalds kfree(node); 7521da177e4SLinus Torvalds return ret; 7531da177e4SLinus Torvalds bail: 7541da177e4SLinus Torvalds ret = -EBADFD; 7551da177e4SLinus Torvalds goto out_node; 7561da177e4SLinus Torvalds } 7571da177e4SLinus Torvalds 7581da177e4SLinus Torvalds static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, 7591da177e4SLinus Torvalds struct jffs2_inode_info *f, struct jffs2_full_dnode *fn) 7601da177e4SLinus Torvalds { 7611da177e4SLinus Torvalds struct jffs2_full_dnode *new_fn; 7621da177e4SLinus Torvalds struct jffs2_raw_inode ri; 7638557fd51SArtem B. Bityuckiy struct jffs2_node_frag *last_frag; 764aef9ab47SDavid Woodhouse union jffs2_device_node dev; 7652e16cfcaSDavid Woodhouse char *mdata = NULL; 7662e16cfcaSDavid Woodhouse int mdatalen = 0; 7679fe4854cSDavid Woodhouse uint32_t alloclen, ilen; 7681da177e4SLinus Torvalds int ret; 7691da177e4SLinus Torvalds 7701da177e4SLinus Torvalds if (S_ISBLK(JFFS2_F_I_MODE(f)) || 7711da177e4SLinus Torvalds S_ISCHR(JFFS2_F_I_MODE(f)) ) { 7721da177e4SLinus Torvalds /* For these, we don't actually need to read the old node */ 773aef9ab47SDavid Woodhouse mdatalen = jffs2_encode_dev(&dev, JFFS2_F_I_RDEV(f)); 7741da177e4SLinus Torvalds mdata = (char *)&dev; 7759c261b33SJoe Perches jffs2_dbg(1, "%s(): Writing %d bytes of kdev_t\n", 7769c261b33SJoe Perches __func__, mdatalen); 7771da177e4SLinus Torvalds } else if (S_ISLNK(JFFS2_F_I_MODE(f))) { 7781da177e4SLinus Torvalds mdatalen = fn->size; 7791da177e4SLinus Torvalds mdata = kmalloc(fn->size, GFP_KERNEL); 7801da177e4SLinus Torvalds if (!mdata) { 781da320f05SJoe Perches pr_warn("kmalloc of mdata failed in jffs2_garbage_collect_metadata()\n"); 7821da177e4SLinus Torvalds return -ENOMEM; 7831da177e4SLinus Torvalds } 7841da177e4SLinus Torvalds ret = jffs2_read_dnode(c, f, fn, mdata, 0, mdatalen); 7851da177e4SLinus Torvalds if (ret) { 786da320f05SJoe Perches pr_warn("read of old metadata failed in jffs2_garbage_collect_metadata(): %d\n", 787da320f05SJoe Perches ret); 7881da177e4SLinus Torvalds kfree(mdata); 7891da177e4SLinus Torvalds return ret; 7901da177e4SLinus Torvalds } 7919c261b33SJoe Perches jffs2_dbg(1, "%s(): Writing %d bites of symlink target\n", 7929c261b33SJoe Perches __func__, mdatalen); 7931da177e4SLinus Torvalds 7941da177e4SLinus Torvalds } 7951da177e4SLinus Torvalds 7969fe4854cSDavid Woodhouse ret = jffs2_reserve_space_gc(c, sizeof(ri) + mdatalen, &alloclen, 797e631ddbaSFerenc Havasi JFFS2_SUMMARY_INODE_SIZE); 7981da177e4SLinus Torvalds if (ret) { 799da320f05SJoe Perches pr_warn("jffs2_reserve_space_gc of %zd bytes for garbage_collect_metadata failed: %d\n", 8001da177e4SLinus Torvalds sizeof(ri) + mdatalen, ret); 8011da177e4SLinus Torvalds goto out; 8021da177e4SLinus Torvalds } 8031da177e4SLinus Torvalds 8048557fd51SArtem B. Bityuckiy last_frag = frag_last(&f->fragtree); 8058557fd51SArtem B. Bityuckiy if (last_frag) 8068557fd51SArtem B. Bityuckiy /* Fetch the inode length from the fragtree rather then 8078557fd51SArtem B. Bityuckiy * from i_size since i_size may have not been updated yet */ 8088557fd51SArtem B. Bityuckiy ilen = last_frag->ofs + last_frag->size; 8098557fd51SArtem B. Bityuckiy else 8108557fd51SArtem B. Bityuckiy ilen = JFFS2_F_I_SIZE(f); 8118557fd51SArtem B. Bityuckiy 8121da177e4SLinus Torvalds memset(&ri, 0, sizeof(ri)); 8131da177e4SLinus Torvalds ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); 8141da177e4SLinus Torvalds ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE); 8151da177e4SLinus Torvalds ri.totlen = cpu_to_je32(sizeof(ri) + mdatalen); 8161da177e4SLinus Torvalds ri.hdr_crc = cpu_to_je32(crc32(0, &ri, sizeof(struct jffs2_unknown_node)-4)); 8171da177e4SLinus Torvalds 8181da177e4SLinus Torvalds ri.ino = cpu_to_je32(f->inocache->ino); 8191da177e4SLinus Torvalds ri.version = cpu_to_je32(++f->highest_version); 8201da177e4SLinus Torvalds ri.mode = cpu_to_jemode(JFFS2_F_I_MODE(f)); 8211da177e4SLinus Torvalds ri.uid = cpu_to_je16(JFFS2_F_I_UID(f)); 8221da177e4SLinus Torvalds ri.gid = cpu_to_je16(JFFS2_F_I_GID(f)); 8238557fd51SArtem B. Bityuckiy ri.isize = cpu_to_je32(ilen); 8241da177e4SLinus Torvalds ri.atime = cpu_to_je32(JFFS2_F_I_ATIME(f)); 8251da177e4SLinus Torvalds ri.ctime = cpu_to_je32(JFFS2_F_I_CTIME(f)); 8261da177e4SLinus Torvalds ri.mtime = cpu_to_je32(JFFS2_F_I_MTIME(f)); 8271da177e4SLinus Torvalds ri.offset = cpu_to_je32(0); 8281da177e4SLinus Torvalds ri.csize = cpu_to_je32(mdatalen); 8291da177e4SLinus Torvalds ri.dsize = cpu_to_je32(mdatalen); 8301da177e4SLinus Torvalds ri.compr = JFFS2_COMPR_NONE; 8311da177e4SLinus Torvalds ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri)-8)); 8321da177e4SLinus Torvalds ri.data_crc = cpu_to_je32(crc32(0, mdata, mdatalen)); 8331da177e4SLinus Torvalds 8349fe4854cSDavid Woodhouse new_fn = jffs2_write_dnode(c, f, &ri, mdata, mdatalen, ALLOC_GC); 8351da177e4SLinus Torvalds 8361da177e4SLinus Torvalds if (IS_ERR(new_fn)) { 837da320f05SJoe Perches pr_warn("Error writing new dnode: %ld\n", PTR_ERR(new_fn)); 8381da177e4SLinus Torvalds ret = PTR_ERR(new_fn); 8391da177e4SLinus Torvalds goto out; 8401da177e4SLinus Torvalds } 8411da177e4SLinus Torvalds jffs2_mark_node_obsolete(c, fn->raw); 8421da177e4SLinus Torvalds jffs2_free_full_dnode(fn); 8431da177e4SLinus Torvalds f->metadata = new_fn; 8441da177e4SLinus Torvalds out: 8451da177e4SLinus Torvalds if (S_ISLNK(JFFS2_F_I_MODE(f))) 8461da177e4SLinus Torvalds kfree(mdata); 8471da177e4SLinus Torvalds return ret; 8481da177e4SLinus Torvalds } 8491da177e4SLinus Torvalds 8501da177e4SLinus Torvalds static int jffs2_garbage_collect_dirent(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, 8511da177e4SLinus Torvalds struct jffs2_inode_info *f, struct jffs2_full_dirent *fd) 8521da177e4SLinus Torvalds { 8531da177e4SLinus Torvalds struct jffs2_full_dirent *new_fd; 8541da177e4SLinus Torvalds struct jffs2_raw_dirent rd; 8559fe4854cSDavid Woodhouse uint32_t alloclen; 8561da177e4SLinus Torvalds int ret; 8571da177e4SLinus Torvalds 8581da177e4SLinus Torvalds rd.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); 8591da177e4SLinus Torvalds rd.nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT); 8601da177e4SLinus Torvalds rd.nsize = strlen(fd->name); 8611da177e4SLinus Torvalds rd.totlen = cpu_to_je32(sizeof(rd) + rd.nsize); 8621da177e4SLinus Torvalds rd.hdr_crc = cpu_to_je32(crc32(0, &rd, sizeof(struct jffs2_unknown_node)-4)); 8631da177e4SLinus Torvalds 8641da177e4SLinus Torvalds rd.pino = cpu_to_je32(f->inocache->ino); 8651da177e4SLinus Torvalds rd.version = cpu_to_je32(++f->highest_version); 8661da177e4SLinus Torvalds rd.ino = cpu_to_je32(fd->ino); 8673a69e0cdSArtem B. Bityutskiy /* If the times on this inode were set by explicit utime() they can be different, 8683a69e0cdSArtem B. Bityutskiy so refrain from splatting them. */ 8693a69e0cdSArtem B. Bityutskiy if (JFFS2_F_I_MTIME(f) == JFFS2_F_I_CTIME(f)) 8703a69e0cdSArtem B. Bityutskiy rd.mctime = cpu_to_je32(JFFS2_F_I_MTIME(f)); 8713a69e0cdSArtem B. Bityutskiy else 8723a69e0cdSArtem B. Bityutskiy rd.mctime = cpu_to_je32(0); 8731da177e4SLinus Torvalds rd.type = fd->type; 8741da177e4SLinus Torvalds rd.node_crc = cpu_to_je32(crc32(0, &rd, sizeof(rd)-8)); 8751da177e4SLinus Torvalds rd.name_crc = cpu_to_je32(crc32(0, fd->name, rd.nsize)); 8761da177e4SLinus Torvalds 8779fe4854cSDavid Woodhouse ret = jffs2_reserve_space_gc(c, sizeof(rd)+rd.nsize, &alloclen, 878e631ddbaSFerenc Havasi JFFS2_SUMMARY_DIRENT_SIZE(rd.nsize)); 8791da177e4SLinus Torvalds if (ret) { 880da320f05SJoe Perches pr_warn("jffs2_reserve_space_gc of %zd bytes for garbage_collect_dirent failed: %d\n", 8811da177e4SLinus Torvalds sizeof(rd)+rd.nsize, ret); 8821da177e4SLinus Torvalds return ret; 8831da177e4SLinus Torvalds } 8849fe4854cSDavid Woodhouse new_fd = jffs2_write_dirent(c, f, &rd, fd->name, rd.nsize, ALLOC_GC); 8851da177e4SLinus Torvalds 8861da177e4SLinus Torvalds if (IS_ERR(new_fd)) { 887da320f05SJoe Perches pr_warn("jffs2_write_dirent in garbage_collect_dirent failed: %ld\n", 888da320f05SJoe Perches PTR_ERR(new_fd)); 8891da177e4SLinus Torvalds return PTR_ERR(new_fd); 8901da177e4SLinus Torvalds } 8911da177e4SLinus Torvalds jffs2_add_fd_to_list(c, new_fd, &f->dents); 8921da177e4SLinus Torvalds return 0; 8931da177e4SLinus Torvalds } 8941da177e4SLinus Torvalds 8951da177e4SLinus Torvalds static int jffs2_garbage_collect_deletion_dirent(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, 8961da177e4SLinus Torvalds struct jffs2_inode_info *f, struct jffs2_full_dirent *fd) 8971da177e4SLinus Torvalds { 8981da177e4SLinus Torvalds struct jffs2_full_dirent **fdp = &f->dents; 8991da177e4SLinus Torvalds int found = 0; 9001da177e4SLinus Torvalds 9011da177e4SLinus Torvalds /* On a medium where we can't actually mark nodes obsolete 9021da177e4SLinus Torvalds pernamently, such as NAND flash, we need to work out 9031da177e4SLinus Torvalds whether this deletion dirent is still needed to actively 9041da177e4SLinus Torvalds delete a 'real' dirent with the same name that's still 9051da177e4SLinus Torvalds somewhere else on the flash. */ 9061da177e4SLinus Torvalds if (!jffs2_can_mark_obsolete(c)) { 9071da177e4SLinus Torvalds struct jffs2_raw_dirent *rd; 9081da177e4SLinus Torvalds struct jffs2_raw_node_ref *raw; 9091da177e4SLinus Torvalds int ret; 9101da177e4SLinus Torvalds size_t retlen; 9111da177e4SLinus Torvalds int name_len = strlen(fd->name); 9121da177e4SLinus Torvalds uint32_t name_crc = crc32(0, fd->name, name_len); 9131da177e4SLinus Torvalds uint32_t rawlen = ref_totlen(c, jeb, fd->raw); 9141da177e4SLinus Torvalds 9151da177e4SLinus Torvalds rd = kmalloc(rawlen, GFP_KERNEL); 9161da177e4SLinus Torvalds if (!rd) 9171da177e4SLinus Torvalds return -ENOMEM; 9181da177e4SLinus Torvalds 9191da177e4SLinus Torvalds /* Prevent the erase code from nicking the obsolete node refs while 9201da177e4SLinus Torvalds we're looking at them. I really don't like this extra lock but 9211da177e4SLinus Torvalds can't see any alternative. Suggestions on a postcard to... */ 922ced22070SDavid Woodhouse mutex_lock(&c->erase_free_sem); 9231da177e4SLinus Torvalds 9241da177e4SLinus Torvalds for (raw = f->inocache->nodes; raw != (void *)f->inocache; raw = raw->next_in_ino) { 9251da177e4SLinus Torvalds 926aba54da3SArtem Bityutskiy cond_resched(); 927aba54da3SArtem Bityutskiy 9281da177e4SLinus Torvalds /* We only care about obsolete ones */ 9291da177e4SLinus Torvalds if (!(ref_obsolete(raw))) 9301da177e4SLinus Torvalds continue; 9311da177e4SLinus Torvalds 9321da177e4SLinus Torvalds /* Any dirent with the same name is going to have the same length... */ 9331da177e4SLinus Torvalds if (ref_totlen(c, NULL, raw) != rawlen) 9341da177e4SLinus Torvalds continue; 9351da177e4SLinus Torvalds 9361da177e4SLinus Torvalds /* Doesn't matter if there's one in the same erase block. We're going to 9371da177e4SLinus Torvalds delete it too at the same time. */ 9383be36675SAndrew Victor if (SECTOR_ADDR(raw->flash_offset) == SECTOR_ADDR(fd->raw->flash_offset)) 9391da177e4SLinus Torvalds continue; 9401da177e4SLinus Torvalds 9419c261b33SJoe Perches jffs2_dbg(1, "Check potential deletion dirent at %08x\n", 9429c261b33SJoe Perches ref_offset(raw)); 9431da177e4SLinus Torvalds 9441da177e4SLinus Torvalds /* This is an obsolete node belonging to the same directory, and it's of the right 9451da177e4SLinus Torvalds length. We need to take a closer look...*/ 9461da177e4SLinus Torvalds ret = jffs2_flash_read(c, ref_offset(raw), rawlen, &retlen, (char *)rd); 9471da177e4SLinus Torvalds if (ret) { 948da320f05SJoe Perches pr_warn("%s(): Read error (%d) reading obsolete node at %08x\n", 949da320f05SJoe Perches __func__, ret, ref_offset(raw)); 9501da177e4SLinus Torvalds /* If we can't read it, we don't need to continue to obsolete it. Continue */ 9511da177e4SLinus Torvalds continue; 9521da177e4SLinus Torvalds } 9531da177e4SLinus Torvalds if (retlen != rawlen) { 954da320f05SJoe Perches pr_warn("%s(): Short read (%zd not %u) reading header from obsolete node at %08x\n", 955da320f05SJoe Perches __func__, retlen, rawlen, 956da320f05SJoe Perches ref_offset(raw)); 9571da177e4SLinus Torvalds continue; 9581da177e4SLinus Torvalds } 9591da177e4SLinus Torvalds 9601da177e4SLinus Torvalds if (je16_to_cpu(rd->nodetype) != JFFS2_NODETYPE_DIRENT) 9611da177e4SLinus Torvalds continue; 9621da177e4SLinus Torvalds 9631da177e4SLinus Torvalds /* If the name CRC doesn't match, skip */ 9641da177e4SLinus Torvalds if (je32_to_cpu(rd->name_crc) != name_crc) 9651da177e4SLinus Torvalds continue; 9661da177e4SLinus Torvalds 9671da177e4SLinus Torvalds /* If the name length doesn't match, or it's another deletion dirent, skip */ 9681da177e4SLinus Torvalds if (rd->nsize != name_len || !je32_to_cpu(rd->ino)) 9691da177e4SLinus Torvalds continue; 9701da177e4SLinus Torvalds 9711da177e4SLinus Torvalds /* OK, check the actual name now */ 9721da177e4SLinus Torvalds if (memcmp(rd->name, fd->name, name_len)) 9731da177e4SLinus Torvalds continue; 9741da177e4SLinus Torvalds 9751da177e4SLinus Torvalds /* OK. The name really does match. There really is still an older node on 9761da177e4SLinus Torvalds the flash which our deletion dirent obsoletes. So we have to write out 9771da177e4SLinus Torvalds a new deletion dirent to replace it */ 978ced22070SDavid Woodhouse mutex_unlock(&c->erase_free_sem); 9791da177e4SLinus Torvalds 9809c261b33SJoe Perches jffs2_dbg(1, "Deletion dirent at %08x still obsoletes real dirent \"%s\" at %08x for ino #%u\n", 9819c261b33SJoe Perches ref_offset(fd->raw), fd->name, 9829c261b33SJoe Perches ref_offset(raw), je32_to_cpu(rd->ino)); 9831da177e4SLinus Torvalds kfree(rd); 9841da177e4SLinus Torvalds 9851da177e4SLinus Torvalds return jffs2_garbage_collect_dirent(c, jeb, f, fd); 9861da177e4SLinus Torvalds } 9871da177e4SLinus Torvalds 988ced22070SDavid Woodhouse mutex_unlock(&c->erase_free_sem); 9891da177e4SLinus Torvalds kfree(rd); 9901da177e4SLinus Torvalds } 9911da177e4SLinus Torvalds 9923a69e0cdSArtem B. Bityutskiy /* FIXME: If we're deleting a dirent which contains the current mtime and ctime, 9933a69e0cdSArtem B. Bityutskiy we should update the metadata node with those times accordingly */ 9943a69e0cdSArtem B. Bityutskiy 9951da177e4SLinus Torvalds /* No need for it any more. Just mark it obsolete and remove it from the list */ 9961da177e4SLinus Torvalds while (*fdp) { 9971da177e4SLinus Torvalds if ((*fdp) == fd) { 9981da177e4SLinus Torvalds found = 1; 9991da177e4SLinus Torvalds *fdp = fd->next; 10001da177e4SLinus Torvalds break; 10011da177e4SLinus Torvalds } 10021da177e4SLinus Torvalds fdp = &(*fdp)->next; 10031da177e4SLinus Torvalds } 10041da177e4SLinus Torvalds if (!found) { 1005da320f05SJoe Perches pr_warn("Deletion dirent \"%s\" not found in list for ino #%u\n", 1006da320f05SJoe Perches fd->name, f->inocache->ino); 10071da177e4SLinus Torvalds } 10081da177e4SLinus Torvalds jffs2_mark_node_obsolete(c, fd->raw); 10091da177e4SLinus Torvalds jffs2_free_full_dirent(fd); 10101da177e4SLinus Torvalds return 0; 10111da177e4SLinus Torvalds } 10121da177e4SLinus Torvalds 10131da177e4SLinus Torvalds static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, 10141da177e4SLinus Torvalds struct jffs2_inode_info *f, struct jffs2_full_dnode *fn, 10151da177e4SLinus Torvalds uint32_t start, uint32_t end) 10161da177e4SLinus Torvalds { 10171da177e4SLinus Torvalds struct jffs2_raw_inode ri; 10181da177e4SLinus Torvalds struct jffs2_node_frag *frag; 10191da177e4SLinus Torvalds struct jffs2_full_dnode *new_fn; 10209fe4854cSDavid Woodhouse uint32_t alloclen, ilen; 10211da177e4SLinus Torvalds int ret; 10221da177e4SLinus Torvalds 10239c261b33SJoe Perches jffs2_dbg(1, "Writing replacement hole node for ino #%u from offset 0x%x to 0x%x\n", 10249c261b33SJoe Perches f->inocache->ino, start, end); 10251da177e4SLinus Torvalds 10261da177e4SLinus Torvalds memset(&ri, 0, sizeof(ri)); 10271da177e4SLinus Torvalds 10281da177e4SLinus Torvalds if(fn->frags > 1) { 10291da177e4SLinus Torvalds size_t readlen; 10301da177e4SLinus Torvalds uint32_t crc; 10311da177e4SLinus Torvalds /* It's partially obsoleted by a later write. So we have to 10321da177e4SLinus Torvalds write it out again with the _same_ version as before */ 10331da177e4SLinus Torvalds ret = jffs2_flash_read(c, ref_offset(fn->raw), sizeof(ri), &readlen, (char *)&ri); 10341da177e4SLinus Torvalds if (readlen != sizeof(ri) || ret) { 1035da320f05SJoe Perches pr_warn("Node read failed in jffs2_garbage_collect_hole. Ret %d, retlen %zd. Data will be lost by writing new hole node\n", 1036da320f05SJoe Perches ret, readlen); 10371da177e4SLinus Torvalds goto fill; 10381da177e4SLinus Torvalds } 10391da177e4SLinus Torvalds if (je16_to_cpu(ri.nodetype) != JFFS2_NODETYPE_INODE) { 1040da320f05SJoe Perches pr_warn("%s(): Node at 0x%08x had node type 0x%04x instead of JFFS2_NODETYPE_INODE(0x%04x)\n", 1041da320f05SJoe Perches __func__, ref_offset(fn->raw), 10421da177e4SLinus Torvalds je16_to_cpu(ri.nodetype), JFFS2_NODETYPE_INODE); 10431da177e4SLinus Torvalds return -EIO; 10441da177e4SLinus Torvalds } 10451da177e4SLinus Torvalds if (je32_to_cpu(ri.totlen) != sizeof(ri)) { 1046da320f05SJoe Perches pr_warn("%s(): Node at 0x%08x had totlen 0x%x instead of expected 0x%zx\n", 1047da320f05SJoe Perches __func__, ref_offset(fn->raw), 10481da177e4SLinus Torvalds je32_to_cpu(ri.totlen), sizeof(ri)); 10491da177e4SLinus Torvalds return -EIO; 10501da177e4SLinus Torvalds } 10511da177e4SLinus Torvalds crc = crc32(0, &ri, sizeof(ri)-8); 10521da177e4SLinus Torvalds if (crc != je32_to_cpu(ri.node_crc)) { 1053da320f05SJoe Perches pr_warn("%s: Node at 0x%08x had CRC 0x%08x which doesn't match calculated CRC 0x%08x\n", 1054da320f05SJoe Perches __func__, ref_offset(fn->raw), 10551da177e4SLinus Torvalds je32_to_cpu(ri.node_crc), crc); 10561da177e4SLinus Torvalds /* FIXME: We could possibly deal with this by writing new holes for each frag */ 1057da320f05SJoe Perches pr_warn("Data in the range 0x%08x to 0x%08x of inode #%u will be lost\n", 10581da177e4SLinus Torvalds start, end, f->inocache->ino); 10591da177e4SLinus Torvalds goto fill; 10601da177e4SLinus Torvalds } 10611da177e4SLinus Torvalds if (ri.compr != JFFS2_COMPR_ZERO) { 1062da320f05SJoe Perches pr_warn("%s(): Node 0x%08x wasn't a hole node!\n", 1063da320f05SJoe Perches __func__, ref_offset(fn->raw)); 1064da320f05SJoe Perches pr_warn("Data in the range 0x%08x to 0x%08x of inode #%u will be lost\n", 10651da177e4SLinus Torvalds start, end, f->inocache->ino); 10661da177e4SLinus Torvalds goto fill; 10671da177e4SLinus Torvalds } 10681da177e4SLinus Torvalds } else { 10691da177e4SLinus Torvalds fill: 10701da177e4SLinus Torvalds ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); 10711da177e4SLinus Torvalds ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE); 10721da177e4SLinus Torvalds ri.totlen = cpu_to_je32(sizeof(ri)); 10731da177e4SLinus Torvalds ri.hdr_crc = cpu_to_je32(crc32(0, &ri, sizeof(struct jffs2_unknown_node)-4)); 10741da177e4SLinus Torvalds 10751da177e4SLinus Torvalds ri.ino = cpu_to_je32(f->inocache->ino); 10761da177e4SLinus Torvalds ri.version = cpu_to_je32(++f->highest_version); 10771da177e4SLinus Torvalds ri.offset = cpu_to_je32(start); 10781da177e4SLinus Torvalds ri.dsize = cpu_to_je32(end - start); 10791da177e4SLinus Torvalds ri.csize = cpu_to_je32(0); 10801da177e4SLinus Torvalds ri.compr = JFFS2_COMPR_ZERO; 10811da177e4SLinus Torvalds } 10828557fd51SArtem B. Bityuckiy 10838557fd51SArtem B. Bityuckiy frag = frag_last(&f->fragtree); 10848557fd51SArtem B. Bityuckiy if (frag) 10858557fd51SArtem B. Bityuckiy /* Fetch the inode length from the fragtree rather then 10868557fd51SArtem B. Bityuckiy * from i_size since i_size may have not been updated yet */ 10878557fd51SArtem B. Bityuckiy ilen = frag->ofs + frag->size; 10888557fd51SArtem B. Bityuckiy else 10898557fd51SArtem B. Bityuckiy ilen = JFFS2_F_I_SIZE(f); 10908557fd51SArtem B. Bityuckiy 10911da177e4SLinus Torvalds ri.mode = cpu_to_jemode(JFFS2_F_I_MODE(f)); 10921da177e4SLinus Torvalds ri.uid = cpu_to_je16(JFFS2_F_I_UID(f)); 10931da177e4SLinus Torvalds ri.gid = cpu_to_je16(JFFS2_F_I_GID(f)); 10948557fd51SArtem B. Bityuckiy ri.isize = cpu_to_je32(ilen); 10951da177e4SLinus Torvalds ri.atime = cpu_to_je32(JFFS2_F_I_ATIME(f)); 10961da177e4SLinus Torvalds ri.ctime = cpu_to_je32(JFFS2_F_I_CTIME(f)); 10971da177e4SLinus Torvalds ri.mtime = cpu_to_je32(JFFS2_F_I_MTIME(f)); 10981da177e4SLinus Torvalds ri.data_crc = cpu_to_je32(0); 10991da177e4SLinus Torvalds ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri)-8)); 11001da177e4SLinus Torvalds 11019fe4854cSDavid Woodhouse ret = jffs2_reserve_space_gc(c, sizeof(ri), &alloclen, 1102e631ddbaSFerenc Havasi JFFS2_SUMMARY_INODE_SIZE); 11031da177e4SLinus Torvalds if (ret) { 1104da320f05SJoe Perches pr_warn("jffs2_reserve_space_gc of %zd bytes for garbage_collect_hole failed: %d\n", 11051da177e4SLinus Torvalds sizeof(ri), ret); 11061da177e4SLinus Torvalds return ret; 11071da177e4SLinus Torvalds } 11089fe4854cSDavid Woodhouse new_fn = jffs2_write_dnode(c, f, &ri, NULL, 0, ALLOC_GC); 11091da177e4SLinus Torvalds 11101da177e4SLinus Torvalds if (IS_ERR(new_fn)) { 1111da320f05SJoe Perches pr_warn("Error writing new hole node: %ld\n", PTR_ERR(new_fn)); 11121da177e4SLinus Torvalds return PTR_ERR(new_fn); 11131da177e4SLinus Torvalds } 11141da177e4SLinus Torvalds if (je32_to_cpu(ri.version) == f->highest_version) { 11151da177e4SLinus Torvalds jffs2_add_full_dnode_to_inode(c, f, new_fn); 11161da177e4SLinus Torvalds if (f->metadata) { 11171da177e4SLinus Torvalds jffs2_mark_node_obsolete(c, f->metadata->raw); 11181da177e4SLinus Torvalds jffs2_free_full_dnode(f->metadata); 11191da177e4SLinus Torvalds f->metadata = NULL; 11201da177e4SLinus Torvalds } 11211da177e4SLinus Torvalds return 0; 11221da177e4SLinus Torvalds } 11231da177e4SLinus Torvalds 11241da177e4SLinus Torvalds /* 11251da177e4SLinus Torvalds * We should only get here in the case where the node we are 11261da177e4SLinus Torvalds * replacing had more than one frag, so we kept the same version 11271da177e4SLinus Torvalds * number as before. (Except in case of error -- see 'goto fill;' 11281da177e4SLinus Torvalds * above.) 11291da177e4SLinus Torvalds */ 11301da177e4SLinus Torvalds D1(if(unlikely(fn->frags <= 1)) { 1131da320f05SJoe Perches pr_warn("%s(): Replacing fn with %d frag(s) but new ver %d != highest_version %d of ino #%d\n", 1132da320f05SJoe Perches __func__, fn->frags, je32_to_cpu(ri.version), 1133da320f05SJoe Perches f->highest_version, je32_to_cpu(ri.ino)); 11341da177e4SLinus Torvalds }); 11351da177e4SLinus Torvalds 11361da177e4SLinus Torvalds /* This is a partially-overlapped hole node. Mark it REF_NORMAL not REF_PRISTINE */ 11371da177e4SLinus Torvalds mark_ref_normal(new_fn->raw); 11381da177e4SLinus Torvalds 11391da177e4SLinus Torvalds for (frag = jffs2_lookup_node_frag(&f->fragtree, fn->ofs); 11401da177e4SLinus Torvalds frag; frag = frag_next(frag)) { 11411da177e4SLinus Torvalds if (frag->ofs > fn->size + fn->ofs) 11421da177e4SLinus Torvalds break; 11431da177e4SLinus Torvalds if (frag->node == fn) { 11441da177e4SLinus Torvalds frag->node = new_fn; 11451da177e4SLinus Torvalds new_fn->frags++; 11461da177e4SLinus Torvalds fn->frags--; 11471da177e4SLinus Torvalds } 11481da177e4SLinus Torvalds } 11491da177e4SLinus Torvalds if (fn->frags) { 1150da320f05SJoe Perches pr_warn("%s(): Old node still has frags!\n", __func__); 11511da177e4SLinus Torvalds BUG(); 11521da177e4SLinus Torvalds } 11531da177e4SLinus Torvalds if (!new_fn->frags) { 1154da320f05SJoe Perches pr_warn("%s(): New node has no frags!\n", __func__); 11551da177e4SLinus Torvalds BUG(); 11561da177e4SLinus Torvalds } 11571da177e4SLinus Torvalds 11581da177e4SLinus Torvalds jffs2_mark_node_obsolete(c, fn->raw); 11591da177e4SLinus Torvalds jffs2_free_full_dnode(fn); 11601da177e4SLinus Torvalds 11611da177e4SLinus Torvalds return 0; 11621da177e4SLinus Torvalds } 11631da177e4SLinus Torvalds 116425dc30b4SDavid Woodhouse static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *orig_jeb, 11651da177e4SLinus Torvalds struct jffs2_inode_info *f, struct jffs2_full_dnode *fn, 11661da177e4SLinus Torvalds uint32_t start, uint32_t end) 11671da177e4SLinus Torvalds { 11681da177e4SLinus Torvalds struct jffs2_full_dnode *new_fn; 11691da177e4SLinus Torvalds struct jffs2_raw_inode ri; 11709fe4854cSDavid Woodhouse uint32_t alloclen, offset, orig_end, orig_start; 11711da177e4SLinus Torvalds int ret = 0; 11721da177e4SLinus Torvalds unsigned char *comprbuf = NULL, *writebuf; 11731da177e4SLinus Torvalds unsigned long pg; 11741da177e4SLinus Torvalds unsigned char *pg_ptr; 11751da177e4SLinus Torvalds 11761da177e4SLinus Torvalds memset(&ri, 0, sizeof(ri)); 11771da177e4SLinus Torvalds 11789c261b33SJoe Perches jffs2_dbg(1, "Writing replacement dnode for ino #%u from offset 0x%x to 0x%x\n", 11799c261b33SJoe Perches f->inocache->ino, start, end); 11801da177e4SLinus Torvalds 11811da177e4SLinus Torvalds orig_end = end; 11821da177e4SLinus Torvalds orig_start = start; 11831da177e4SLinus Torvalds 11841da177e4SLinus Torvalds if (c->nr_free_blocks + c->nr_erasing_blocks > c->resv_blocks_gcmerge) { 11851da177e4SLinus Torvalds /* Attempt to do some merging. But only expand to cover logically 11861da177e4SLinus Torvalds adjacent frags if the block containing them is already considered 11871da177e4SLinus Torvalds to be dirty. Otherwise we end up with GC just going round in 11881da177e4SLinus Torvalds circles dirtying the nodes it already wrote out, especially 11891da177e4SLinus Torvalds on NAND where we have small eraseblocks and hence a much higher 11901da177e4SLinus Torvalds chance of nodes having to be split to cross boundaries. */ 11911da177e4SLinus Torvalds 11921da177e4SLinus Torvalds struct jffs2_node_frag *frag; 11931da177e4SLinus Torvalds uint32_t min, max; 11941da177e4SLinus Torvalds 11951da177e4SLinus Torvalds min = start & ~(PAGE_CACHE_SIZE-1); 11961da177e4SLinus Torvalds max = min + PAGE_CACHE_SIZE; 11971da177e4SLinus Torvalds 11981da177e4SLinus Torvalds frag = jffs2_lookup_node_frag(&f->fragtree, start); 11991da177e4SLinus Torvalds 12001da177e4SLinus Torvalds /* BUG_ON(!frag) but that'll happen anyway... */ 12011da177e4SLinus Torvalds 12021da177e4SLinus Torvalds BUG_ON(frag->ofs != start); 12031da177e4SLinus Torvalds 12041da177e4SLinus Torvalds /* First grow down... */ 12051da177e4SLinus Torvalds while((frag = frag_prev(frag)) && frag->ofs >= min) { 12061da177e4SLinus Torvalds 12071da177e4SLinus Torvalds /* If the previous frag doesn't even reach the beginning, there's 12081da177e4SLinus Torvalds excessive fragmentation. Just merge. */ 12091da177e4SLinus Torvalds if (frag->ofs > min) { 12109c261b33SJoe Perches jffs2_dbg(1, "Expanding down to cover partial frag (0x%x-0x%x)\n", 12119c261b33SJoe Perches frag->ofs, frag->ofs+frag->size); 12121da177e4SLinus Torvalds start = frag->ofs; 12131da177e4SLinus Torvalds continue; 12141da177e4SLinus Torvalds } 12151da177e4SLinus Torvalds /* OK. This frag holds the first byte of the page. */ 12161da177e4SLinus Torvalds if (!frag->node || !frag->node->raw) { 12179c261b33SJoe Perches jffs2_dbg(1, "First frag in page is hole (0x%x-0x%x). Not expanding down.\n", 12189c261b33SJoe Perches frag->ofs, frag->ofs+frag->size); 12191da177e4SLinus Torvalds break; 12201da177e4SLinus Torvalds } else { 12211da177e4SLinus Torvalds 12221da177e4SLinus Torvalds /* OK, it's a frag which extends to the beginning of the page. Does it live 12231da177e4SLinus Torvalds in a block which is still considered clean? If so, don't obsolete it. 12241da177e4SLinus Torvalds If not, cover it anyway. */ 12251da177e4SLinus Torvalds 12261da177e4SLinus Torvalds struct jffs2_raw_node_ref *raw = frag->node->raw; 12271da177e4SLinus Torvalds struct jffs2_eraseblock *jeb; 12281da177e4SLinus Torvalds 12291da177e4SLinus Torvalds jeb = &c->blocks[raw->flash_offset / c->sector_size]; 12301da177e4SLinus Torvalds 12311da177e4SLinus Torvalds if (jeb == c->gcblock) { 12329c261b33SJoe Perches jffs2_dbg(1, "Expanding down to cover frag (0x%x-0x%x) in gcblock at %08x\n", 12339c261b33SJoe Perches frag->ofs, 12349c261b33SJoe Perches frag->ofs + frag->size, 12359c261b33SJoe Perches ref_offset(raw)); 12361da177e4SLinus Torvalds start = frag->ofs; 12371da177e4SLinus Torvalds break; 12381da177e4SLinus Torvalds } 12391da177e4SLinus Torvalds if (!ISDIRTY(jeb->dirty_size + jeb->wasted_size)) { 12409c261b33SJoe Perches jffs2_dbg(1, "Not expanding down to cover frag (0x%x-0x%x) in clean block %08x\n", 12419c261b33SJoe Perches frag->ofs, 12429c261b33SJoe Perches frag->ofs + frag->size, 12439c261b33SJoe Perches jeb->offset); 12441da177e4SLinus Torvalds break; 12451da177e4SLinus Torvalds } 12461da177e4SLinus Torvalds 12479c261b33SJoe Perches jffs2_dbg(1, "Expanding down to cover frag (0x%x-0x%x) in dirty block %08x\n", 12489c261b33SJoe Perches frag->ofs, 12499c261b33SJoe Perches frag->ofs + frag->size, 12509c261b33SJoe Perches jeb->offset); 12511da177e4SLinus Torvalds start = frag->ofs; 12521da177e4SLinus Torvalds break; 12531da177e4SLinus Torvalds } 12541da177e4SLinus Torvalds } 12551da177e4SLinus Torvalds 12561da177e4SLinus Torvalds /* ... then up */ 12571da177e4SLinus Torvalds 12581da177e4SLinus Torvalds /* Find last frag which is actually part of the node we're to GC. */ 12591da177e4SLinus Torvalds frag = jffs2_lookup_node_frag(&f->fragtree, end-1); 12601da177e4SLinus Torvalds 12611da177e4SLinus Torvalds while((frag = frag_next(frag)) && frag->ofs+frag->size <= max) { 12621da177e4SLinus Torvalds 12631da177e4SLinus Torvalds /* If the previous frag doesn't even reach the beginning, there's lots 12641da177e4SLinus Torvalds of fragmentation. Just merge. */ 12651da177e4SLinus Torvalds if (frag->ofs+frag->size < max) { 12669c261b33SJoe Perches jffs2_dbg(1, "Expanding up to cover partial frag (0x%x-0x%x)\n", 12679c261b33SJoe Perches frag->ofs, frag->ofs+frag->size); 12681da177e4SLinus Torvalds end = frag->ofs + frag->size; 12691da177e4SLinus Torvalds continue; 12701da177e4SLinus Torvalds } 12711da177e4SLinus Torvalds 12721da177e4SLinus Torvalds if (!frag->node || !frag->node->raw) { 12739c261b33SJoe Perches jffs2_dbg(1, "Last frag in page is hole (0x%x-0x%x). Not expanding up.\n", 12749c261b33SJoe Perches frag->ofs, frag->ofs+frag->size); 12751da177e4SLinus Torvalds break; 12761da177e4SLinus Torvalds } else { 12771da177e4SLinus Torvalds 12781da177e4SLinus Torvalds /* OK, it's a frag which extends to the beginning of the page. Does it live 12791da177e4SLinus Torvalds in a block which is still considered clean? If so, don't obsolete it. 12801da177e4SLinus Torvalds If not, cover it anyway. */ 12811da177e4SLinus Torvalds 12821da177e4SLinus Torvalds struct jffs2_raw_node_ref *raw = frag->node->raw; 12831da177e4SLinus Torvalds struct jffs2_eraseblock *jeb; 12841da177e4SLinus Torvalds 12851da177e4SLinus Torvalds jeb = &c->blocks[raw->flash_offset / c->sector_size]; 12861da177e4SLinus Torvalds 12871da177e4SLinus Torvalds if (jeb == c->gcblock) { 12889c261b33SJoe Perches jffs2_dbg(1, "Expanding up to cover frag (0x%x-0x%x) in gcblock at %08x\n", 12899c261b33SJoe Perches frag->ofs, 12909c261b33SJoe Perches frag->ofs + frag->size, 12919c261b33SJoe Perches ref_offset(raw)); 12921da177e4SLinus Torvalds end = frag->ofs + frag->size; 12931da177e4SLinus Torvalds break; 12941da177e4SLinus Torvalds } 12951da177e4SLinus Torvalds if (!ISDIRTY(jeb->dirty_size + jeb->wasted_size)) { 12969c261b33SJoe Perches jffs2_dbg(1, "Not expanding up to cover frag (0x%x-0x%x) in clean block %08x\n", 12979c261b33SJoe Perches frag->ofs, 12989c261b33SJoe Perches frag->ofs + frag->size, 12999c261b33SJoe Perches jeb->offset); 13001da177e4SLinus Torvalds break; 13011da177e4SLinus Torvalds } 13021da177e4SLinus Torvalds 13039c261b33SJoe Perches jffs2_dbg(1, "Expanding up to cover frag (0x%x-0x%x) in dirty block %08x\n", 13049c261b33SJoe Perches frag->ofs, 13059c261b33SJoe Perches frag->ofs + frag->size, 13069c261b33SJoe Perches jeb->offset); 13071da177e4SLinus Torvalds end = frag->ofs + frag->size; 13081da177e4SLinus Torvalds break; 13091da177e4SLinus Torvalds } 13101da177e4SLinus Torvalds } 13119c261b33SJoe Perches jffs2_dbg(1, "Expanded dnode to write from (0x%x-0x%x) to (0x%x-0x%x)\n", 13129c261b33SJoe Perches orig_start, orig_end, start, end); 13131da177e4SLinus Torvalds 13148557fd51SArtem B. Bityuckiy D1(BUG_ON(end > frag_last(&f->fragtree)->ofs + frag_last(&f->fragtree)->size)); 13151da177e4SLinus Torvalds BUG_ON(end < orig_end); 13161da177e4SLinus Torvalds BUG_ON(start > orig_start); 13171da177e4SLinus Torvalds } 13181da177e4SLinus Torvalds 13191da177e4SLinus Torvalds /* First, use readpage() to read the appropriate page into the page cache */ 13201da177e4SLinus Torvalds /* Q: What happens if we actually try to GC the _same_ page for which commit_write() 13211da177e4SLinus Torvalds * triggered garbage collection in the first place? 13221da177e4SLinus Torvalds * A: I _think_ it's OK. read_cache_page shouldn't deadlock, we'll write out the 13231da177e4SLinus Torvalds * page OK. We'll actually write it out again in commit_write, which is a little 13241da177e4SLinus Torvalds * suboptimal, but at least we're correct. 13251da177e4SLinus Torvalds */ 13261da177e4SLinus Torvalds pg_ptr = jffs2_gc_fetch_page(c, f, start, &pg); 13271da177e4SLinus Torvalds 13281da177e4SLinus Torvalds if (IS_ERR(pg_ptr)) { 1329da320f05SJoe Perches pr_warn("read_cache_page() returned error: %ld\n", 1330da320f05SJoe Perches PTR_ERR(pg_ptr)); 13311da177e4SLinus Torvalds return PTR_ERR(pg_ptr); 13321da177e4SLinus Torvalds } 13331da177e4SLinus Torvalds 13341da177e4SLinus Torvalds offset = start; 13351da177e4SLinus Torvalds while(offset < orig_end) { 13361da177e4SLinus Torvalds uint32_t datalen; 13371da177e4SLinus Torvalds uint32_t cdatalen; 13381da177e4SLinus Torvalds uint16_t comprtype = JFFS2_COMPR_NONE; 13391da177e4SLinus Torvalds 13409fe4854cSDavid Woodhouse ret = jffs2_reserve_space_gc(c, sizeof(ri) + JFFS2_MIN_DATA_LEN, 1341e631ddbaSFerenc Havasi &alloclen, JFFS2_SUMMARY_INODE_SIZE); 13421da177e4SLinus Torvalds 13431da177e4SLinus Torvalds if (ret) { 1344da320f05SJoe Perches pr_warn("jffs2_reserve_space_gc of %zd bytes for garbage_collect_dnode failed: %d\n", 13451da177e4SLinus Torvalds sizeof(ri) + JFFS2_MIN_DATA_LEN, ret); 13461da177e4SLinus Torvalds break; 13471da177e4SLinus Torvalds } 13481da177e4SLinus Torvalds cdatalen = min_t(uint32_t, alloclen - sizeof(ri), end - offset); 13491da177e4SLinus Torvalds datalen = end - offset; 13501da177e4SLinus Torvalds 13511da177e4SLinus Torvalds writebuf = pg_ptr + (offset & (PAGE_CACHE_SIZE -1)); 13521da177e4SLinus Torvalds 13531da177e4SLinus Torvalds comprtype = jffs2_compress(c, f, writebuf, &comprbuf, &datalen, &cdatalen); 13541da177e4SLinus Torvalds 13551da177e4SLinus Torvalds ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); 13561da177e4SLinus Torvalds ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE); 13571da177e4SLinus Torvalds ri.totlen = cpu_to_je32(sizeof(ri) + cdatalen); 13581da177e4SLinus Torvalds ri.hdr_crc = cpu_to_je32(crc32(0, &ri, sizeof(struct jffs2_unknown_node)-4)); 13591da177e4SLinus Torvalds 13601da177e4SLinus Torvalds ri.ino = cpu_to_je32(f->inocache->ino); 13611da177e4SLinus Torvalds ri.version = cpu_to_je32(++f->highest_version); 13621da177e4SLinus Torvalds ri.mode = cpu_to_jemode(JFFS2_F_I_MODE(f)); 13631da177e4SLinus Torvalds ri.uid = cpu_to_je16(JFFS2_F_I_UID(f)); 13641da177e4SLinus Torvalds ri.gid = cpu_to_je16(JFFS2_F_I_GID(f)); 13651da177e4SLinus Torvalds ri.isize = cpu_to_je32(JFFS2_F_I_SIZE(f)); 13661da177e4SLinus Torvalds ri.atime = cpu_to_je32(JFFS2_F_I_ATIME(f)); 13671da177e4SLinus Torvalds ri.ctime = cpu_to_je32(JFFS2_F_I_CTIME(f)); 13681da177e4SLinus Torvalds ri.mtime = cpu_to_je32(JFFS2_F_I_MTIME(f)); 13691da177e4SLinus Torvalds ri.offset = cpu_to_je32(offset); 13701da177e4SLinus Torvalds ri.csize = cpu_to_je32(cdatalen); 13711da177e4SLinus Torvalds ri.dsize = cpu_to_je32(datalen); 13721da177e4SLinus Torvalds ri.compr = comprtype & 0xff; 13731da177e4SLinus Torvalds ri.usercompr = (comprtype >> 8) & 0xff; 13741da177e4SLinus Torvalds ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri)-8)); 13751da177e4SLinus Torvalds ri.data_crc = cpu_to_je32(crc32(0, comprbuf, cdatalen)); 13761da177e4SLinus Torvalds 13779fe4854cSDavid Woodhouse new_fn = jffs2_write_dnode(c, f, &ri, comprbuf, cdatalen, ALLOC_GC); 13781da177e4SLinus Torvalds 13791da177e4SLinus Torvalds jffs2_free_comprbuf(comprbuf, writebuf); 13801da177e4SLinus Torvalds 13811da177e4SLinus Torvalds if (IS_ERR(new_fn)) { 1382da320f05SJoe Perches pr_warn("Error writing new dnode: %ld\n", 1383da320f05SJoe Perches PTR_ERR(new_fn)); 13841da177e4SLinus Torvalds ret = PTR_ERR(new_fn); 13851da177e4SLinus Torvalds break; 13861da177e4SLinus Torvalds } 13871da177e4SLinus Torvalds ret = jffs2_add_full_dnode_to_inode(c, f, new_fn); 13881da177e4SLinus Torvalds offset += datalen; 13891da177e4SLinus Torvalds if (f->metadata) { 13901da177e4SLinus Torvalds jffs2_mark_node_obsolete(c, f->metadata->raw); 13911da177e4SLinus Torvalds jffs2_free_full_dnode(f->metadata); 13921da177e4SLinus Torvalds f->metadata = NULL; 13931da177e4SLinus Torvalds } 13941da177e4SLinus Torvalds } 13951da177e4SLinus Torvalds 13961da177e4SLinus Torvalds jffs2_gc_release_page(c, pg_ptr, &pg); 13971da177e4SLinus Torvalds return ret; 13981da177e4SLinus Torvalds } 1399