162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * JFFS2 -- Journalling Flash File System, Version 2. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright © 2001-2007 Red Hat, Inc. 562306a36Sopenharmony_ci * Copyright © 2004-2010 David Woodhouse <dwmw2@infradead.org> 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Created by David Woodhouse <dwmw2@infradead.org> 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * For licensing information, see the file 'LICENCE' in this directory. 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci */ 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include <linux/kernel.h> 1662306a36Sopenharmony_ci#include <linux/mtd/mtd.h> 1762306a36Sopenharmony_ci#include <linux/slab.h> 1862306a36Sopenharmony_ci#include <linux/pagemap.h> 1962306a36Sopenharmony_ci#include <linux/crc32.h> 2062306a36Sopenharmony_ci#include <linux/compiler.h> 2162306a36Sopenharmony_ci#include <linux/stat.h> 2262306a36Sopenharmony_ci#include "nodelist.h" 2362306a36Sopenharmony_ci#include "compr.h" 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_cistatic int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, 2662306a36Sopenharmony_ci struct jffs2_inode_cache *ic, 2762306a36Sopenharmony_ci struct jffs2_raw_node_ref *raw); 2862306a36Sopenharmony_cistatic int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, 2962306a36Sopenharmony_ci struct jffs2_inode_info *f, struct jffs2_full_dnode *fd); 3062306a36Sopenharmony_cistatic int jffs2_garbage_collect_dirent(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, 3162306a36Sopenharmony_ci struct jffs2_inode_info *f, struct jffs2_full_dirent *fd); 3262306a36Sopenharmony_cistatic int jffs2_garbage_collect_deletion_dirent(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, 3362306a36Sopenharmony_ci struct jffs2_inode_info *f, struct jffs2_full_dirent *fd); 3462306a36Sopenharmony_cistatic int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, 3562306a36Sopenharmony_ci struct jffs2_inode_info *f, struct jffs2_full_dnode *fn, 3662306a36Sopenharmony_ci uint32_t start, uint32_t end); 3762306a36Sopenharmony_cistatic int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, 3862306a36Sopenharmony_ci struct jffs2_inode_info *f, struct jffs2_full_dnode *fn, 3962306a36Sopenharmony_ci uint32_t start, uint32_t end); 4062306a36Sopenharmony_cistatic int jffs2_garbage_collect_live(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, 4162306a36Sopenharmony_ci struct jffs2_raw_node_ref *raw, struct jffs2_inode_info *f); 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci/* Called with erase_completion_lock held */ 4462306a36Sopenharmony_cistatic struct jffs2_eraseblock *jffs2_find_gc_block(struct jffs2_sb_info *c) 4562306a36Sopenharmony_ci{ 4662306a36Sopenharmony_ci struct jffs2_eraseblock *ret; 4762306a36Sopenharmony_ci struct list_head *nextlist = NULL; 4862306a36Sopenharmony_ci int n = jiffies % 128; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci /* Pick an eraseblock to garbage collect next. This is where we'll 5162306a36Sopenharmony_ci put the clever wear-levelling algorithms. Eventually. */ 5262306a36Sopenharmony_ci /* We possibly want to favour the dirtier blocks more when the 5362306a36Sopenharmony_ci number of free blocks is low. */ 5462306a36Sopenharmony_ciagain: 5562306a36Sopenharmony_ci if (!list_empty(&c->bad_used_list) && c->nr_free_blocks > c->resv_blocks_gcbad) { 5662306a36Sopenharmony_ci jffs2_dbg(1, "Picking block from bad_used_list to GC next\n"); 5762306a36Sopenharmony_ci nextlist = &c->bad_used_list; 5862306a36Sopenharmony_ci } else if (n < 50 && !list_empty(&c->erasable_list)) { 5962306a36Sopenharmony_ci /* Note that most of them will have gone directly to be erased. 6062306a36Sopenharmony_ci So don't favour the erasable_list _too_ much. */ 6162306a36Sopenharmony_ci jffs2_dbg(1, "Picking block from erasable_list to GC next\n"); 6262306a36Sopenharmony_ci nextlist = &c->erasable_list; 6362306a36Sopenharmony_ci } else if (n < 110 && !list_empty(&c->very_dirty_list)) { 6462306a36Sopenharmony_ci /* Most of the time, pick one off the very_dirty list */ 6562306a36Sopenharmony_ci jffs2_dbg(1, "Picking block from very_dirty_list to GC next\n"); 6662306a36Sopenharmony_ci nextlist = &c->very_dirty_list; 6762306a36Sopenharmony_ci } else if (n < 126 && !list_empty(&c->dirty_list)) { 6862306a36Sopenharmony_ci jffs2_dbg(1, "Picking block from dirty_list to GC next\n"); 6962306a36Sopenharmony_ci nextlist = &c->dirty_list; 7062306a36Sopenharmony_ci } else if (!list_empty(&c->clean_list)) { 7162306a36Sopenharmony_ci jffs2_dbg(1, "Picking block from clean_list to GC next\n"); 7262306a36Sopenharmony_ci nextlist = &c->clean_list; 7362306a36Sopenharmony_ci } else if (!list_empty(&c->dirty_list)) { 7462306a36Sopenharmony_ci jffs2_dbg(1, "Picking block from dirty_list to GC next (clean_list was empty)\n"); 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci nextlist = &c->dirty_list; 7762306a36Sopenharmony_ci } else if (!list_empty(&c->very_dirty_list)) { 7862306a36Sopenharmony_ci jffs2_dbg(1, "Picking block from very_dirty_list to GC next (clean_list and dirty_list were empty)\n"); 7962306a36Sopenharmony_ci nextlist = &c->very_dirty_list; 8062306a36Sopenharmony_ci } else if (!list_empty(&c->erasable_list)) { 8162306a36Sopenharmony_ci jffs2_dbg(1, "Picking block from erasable_list to GC next (clean_list and {very_,}dirty_list were empty)\n"); 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci nextlist = &c->erasable_list; 8462306a36Sopenharmony_ci } else if (!list_empty(&c->erasable_pending_wbuf_list)) { 8562306a36Sopenharmony_ci /* There are blocks are wating for the wbuf sync */ 8662306a36Sopenharmony_ci jffs2_dbg(1, "Synching wbuf in order to reuse erasable_pending_wbuf_list blocks\n"); 8762306a36Sopenharmony_ci spin_unlock(&c->erase_completion_lock); 8862306a36Sopenharmony_ci jffs2_flush_wbuf_pad(c); 8962306a36Sopenharmony_ci spin_lock(&c->erase_completion_lock); 9062306a36Sopenharmony_ci goto again; 9162306a36Sopenharmony_ci } else { 9262306a36Sopenharmony_ci /* Eep. All were empty */ 9362306a36Sopenharmony_ci jffs2_dbg(1, "No clean, dirty _or_ erasable blocks to GC from! Where are they all?\n"); 9462306a36Sopenharmony_ci return NULL; 9562306a36Sopenharmony_ci } 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci ret = list_entry(nextlist->next, struct jffs2_eraseblock, list); 9862306a36Sopenharmony_ci list_del(&ret->list); 9962306a36Sopenharmony_ci c->gcblock = ret; 10062306a36Sopenharmony_ci ret->gc_node = ret->first_node; 10162306a36Sopenharmony_ci if (!ret->gc_node) { 10262306a36Sopenharmony_ci pr_warn("Eep. ret->gc_node for block at 0x%08x is NULL\n", 10362306a36Sopenharmony_ci ret->offset); 10462306a36Sopenharmony_ci BUG(); 10562306a36Sopenharmony_ci } 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci /* Have we accidentally picked a clean block with wasted space ? */ 10862306a36Sopenharmony_ci if (ret->wasted_size) { 10962306a36Sopenharmony_ci jffs2_dbg(1, "Converting wasted_size %08x to dirty_size\n", 11062306a36Sopenharmony_ci ret->wasted_size); 11162306a36Sopenharmony_ci ret->dirty_size += ret->wasted_size; 11262306a36Sopenharmony_ci c->wasted_size -= ret->wasted_size; 11362306a36Sopenharmony_ci c->dirty_size += ret->wasted_size; 11462306a36Sopenharmony_ci ret->wasted_size = 0; 11562306a36Sopenharmony_ci } 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci return ret; 11862306a36Sopenharmony_ci} 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci/* jffs2_garbage_collect_pass 12162306a36Sopenharmony_ci * Make a single attempt to progress GC. Move one node, and possibly 12262306a36Sopenharmony_ci * start erasing one eraseblock. 12362306a36Sopenharmony_ci */ 12462306a36Sopenharmony_ciint jffs2_garbage_collect_pass(struct jffs2_sb_info *c) 12562306a36Sopenharmony_ci{ 12662306a36Sopenharmony_ci struct jffs2_inode_info *f; 12762306a36Sopenharmony_ci struct jffs2_inode_cache *ic; 12862306a36Sopenharmony_ci struct jffs2_eraseblock *jeb; 12962306a36Sopenharmony_ci struct jffs2_raw_node_ref *raw; 13062306a36Sopenharmony_ci uint32_t gcblock_dirty; 13162306a36Sopenharmony_ci int ret = 0, inum, nlink; 13262306a36Sopenharmony_ci int xattr = 0; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci if (mutex_lock_interruptible(&c->alloc_sem)) 13562306a36Sopenharmony_ci return -EINTR; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci for (;;) { 13962306a36Sopenharmony_ci /* We can't start doing GC until we've finished checking 14062306a36Sopenharmony_ci the node CRCs etc. */ 14162306a36Sopenharmony_ci int bucket, want_ino; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci spin_lock(&c->erase_completion_lock); 14462306a36Sopenharmony_ci if (!c->unchecked_size) 14562306a36Sopenharmony_ci break; 14662306a36Sopenharmony_ci spin_unlock(&c->erase_completion_lock); 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci if (!xattr) 14962306a36Sopenharmony_ci xattr = jffs2_verify_xattr(c); 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci spin_lock(&c->inocache_lock); 15262306a36Sopenharmony_ci /* Instead of doing the inodes in numeric order, doing a lookup 15362306a36Sopenharmony_ci * in the hash for each possible number, just walk the hash 15462306a36Sopenharmony_ci * buckets of *existing* inodes. This means that we process 15562306a36Sopenharmony_ci * them out-of-order, but it can be a lot faster if there's 15662306a36Sopenharmony_ci * a sparse inode# space. Which there often is. */ 15762306a36Sopenharmony_ci want_ino = c->check_ino; 15862306a36Sopenharmony_ci for (bucket = c->check_ino % c->inocache_hashsize ; bucket < c->inocache_hashsize; bucket++) { 15962306a36Sopenharmony_ci for (ic = c->inocache_list[bucket]; ic; ic = ic->next) { 16062306a36Sopenharmony_ci if (ic->ino < want_ino) 16162306a36Sopenharmony_ci continue; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci if (ic->state != INO_STATE_CHECKEDABSENT && 16462306a36Sopenharmony_ci ic->state != INO_STATE_PRESENT) 16562306a36Sopenharmony_ci goto got_next; /* with inocache_lock held */ 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci jffs2_dbg(1, "Skipping ino #%u already checked\n", 16862306a36Sopenharmony_ci ic->ino); 16962306a36Sopenharmony_ci } 17062306a36Sopenharmony_ci want_ino = 0; 17162306a36Sopenharmony_ci } 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci /* Point c->check_ino past the end of the last bucket. */ 17462306a36Sopenharmony_ci c->check_ino = ((c->highest_ino + c->inocache_hashsize + 1) & 17562306a36Sopenharmony_ci ~c->inocache_hashsize) - 1; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci spin_unlock(&c->inocache_lock); 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci pr_crit("Checked all inodes but still 0x%x bytes of unchecked space?\n", 18062306a36Sopenharmony_ci c->unchecked_size); 18162306a36Sopenharmony_ci jffs2_dbg_dump_block_lists_nolock(c); 18262306a36Sopenharmony_ci mutex_unlock(&c->alloc_sem); 18362306a36Sopenharmony_ci return -ENOSPC; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci got_next: 18662306a36Sopenharmony_ci /* For next time round the loop, we want c->checked_ino to indicate 18762306a36Sopenharmony_ci * the *next* one we want to check. And since we're walking the 18862306a36Sopenharmony_ci * buckets rather than doing it sequentially, it's: */ 18962306a36Sopenharmony_ci c->check_ino = ic->ino + c->inocache_hashsize; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci if (!ic->pino_nlink) { 19262306a36Sopenharmony_ci jffs2_dbg(1, "Skipping check of ino #%d with nlink/pino zero\n", 19362306a36Sopenharmony_ci ic->ino); 19462306a36Sopenharmony_ci spin_unlock(&c->inocache_lock); 19562306a36Sopenharmony_ci jffs2_xattr_delete_inode(c, ic); 19662306a36Sopenharmony_ci continue; 19762306a36Sopenharmony_ci } 19862306a36Sopenharmony_ci switch(ic->state) { 19962306a36Sopenharmony_ci case INO_STATE_CHECKEDABSENT: 20062306a36Sopenharmony_ci case INO_STATE_PRESENT: 20162306a36Sopenharmony_ci spin_unlock(&c->inocache_lock); 20262306a36Sopenharmony_ci continue; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci case INO_STATE_GC: 20562306a36Sopenharmony_ci case INO_STATE_CHECKING: 20662306a36Sopenharmony_ci pr_warn("Inode #%u is in state %d during CRC check phase!\n", 20762306a36Sopenharmony_ci ic->ino, ic->state); 20862306a36Sopenharmony_ci spin_unlock(&c->inocache_lock); 20962306a36Sopenharmony_ci BUG(); 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci case INO_STATE_READING: 21262306a36Sopenharmony_ci /* We need to wait for it to finish, lest we move on 21362306a36Sopenharmony_ci and trigger the BUG() above while we haven't yet 21462306a36Sopenharmony_ci finished checking all its nodes */ 21562306a36Sopenharmony_ci jffs2_dbg(1, "Waiting for ino #%u to finish reading\n", 21662306a36Sopenharmony_ci ic->ino); 21762306a36Sopenharmony_ci /* We need to come back again for the _same_ inode. We've 21862306a36Sopenharmony_ci made no progress in this case, but that should be OK */ 21962306a36Sopenharmony_ci c->check_ino = ic->ino; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci mutex_unlock(&c->alloc_sem); 22262306a36Sopenharmony_ci sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock); 22362306a36Sopenharmony_ci return 0; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci default: 22662306a36Sopenharmony_ci BUG(); 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci case INO_STATE_UNCHECKED: 22962306a36Sopenharmony_ci ; 23062306a36Sopenharmony_ci } 23162306a36Sopenharmony_ci ic->state = INO_STATE_CHECKING; 23262306a36Sopenharmony_ci spin_unlock(&c->inocache_lock); 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci jffs2_dbg(1, "%s(): triggering inode scan of ino#%u\n", 23562306a36Sopenharmony_ci __func__, ic->ino); 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci ret = jffs2_do_crccheck_inode(c, ic); 23862306a36Sopenharmony_ci if (ret) 23962306a36Sopenharmony_ci pr_warn("Returned error for crccheck of ino #%u. Expect badness...\n", 24062306a36Sopenharmony_ci ic->ino); 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci jffs2_set_inocache_state(c, ic, INO_STATE_CHECKEDABSENT); 24362306a36Sopenharmony_ci mutex_unlock(&c->alloc_sem); 24462306a36Sopenharmony_ci return ret; 24562306a36Sopenharmony_ci } 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci /* If there are any blocks which need erasing, erase them now */ 24862306a36Sopenharmony_ci if (!list_empty(&c->erase_complete_list) || 24962306a36Sopenharmony_ci !list_empty(&c->erase_pending_list)) { 25062306a36Sopenharmony_ci spin_unlock(&c->erase_completion_lock); 25162306a36Sopenharmony_ci mutex_unlock(&c->alloc_sem); 25262306a36Sopenharmony_ci jffs2_dbg(1, "%s(): erasing pending blocks\n", __func__); 25362306a36Sopenharmony_ci if (jffs2_erase_pending_blocks(c, 1)) 25462306a36Sopenharmony_ci return 0; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci jffs2_dbg(1, "No progress from erasing block; doing GC anyway\n"); 25762306a36Sopenharmony_ci mutex_lock(&c->alloc_sem); 25862306a36Sopenharmony_ci spin_lock(&c->erase_completion_lock); 25962306a36Sopenharmony_ci } 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci /* First, work out which block we're garbage-collecting */ 26262306a36Sopenharmony_ci jeb = c->gcblock; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci if (!jeb) 26562306a36Sopenharmony_ci jeb = jffs2_find_gc_block(c); 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci if (!jeb) { 26862306a36Sopenharmony_ci /* Couldn't find a free block. But maybe we can just erase one and make 'progress'? */ 26962306a36Sopenharmony_ci if (c->nr_erasing_blocks) { 27062306a36Sopenharmony_ci spin_unlock(&c->erase_completion_lock); 27162306a36Sopenharmony_ci mutex_unlock(&c->alloc_sem); 27262306a36Sopenharmony_ci return -EAGAIN; 27362306a36Sopenharmony_ci } 27462306a36Sopenharmony_ci jffs2_dbg(1, "Couldn't find erase block to garbage collect!\n"); 27562306a36Sopenharmony_ci spin_unlock(&c->erase_completion_lock); 27662306a36Sopenharmony_ci mutex_unlock(&c->alloc_sem); 27762306a36Sopenharmony_ci return -EIO; 27862306a36Sopenharmony_ci } 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci jffs2_dbg(1, "GC from block %08x, used_size %08x, dirty_size %08x, free_size %08x\n", 28162306a36Sopenharmony_ci jeb->offset, jeb->used_size, jeb->dirty_size, jeb->free_size); 28262306a36Sopenharmony_ci D1(if (c->nextblock) 28362306a36Sopenharmony_ci 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)); 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci if (!jeb->used_size) { 28662306a36Sopenharmony_ci mutex_unlock(&c->alloc_sem); 28762306a36Sopenharmony_ci goto eraseit; 28862306a36Sopenharmony_ci } 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci raw = jeb->gc_node; 29162306a36Sopenharmony_ci gcblock_dirty = jeb->dirty_size; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci while(ref_obsolete(raw)) { 29462306a36Sopenharmony_ci jffs2_dbg(1, "Node at 0x%08x is obsolete... skipping\n", 29562306a36Sopenharmony_ci ref_offset(raw)); 29662306a36Sopenharmony_ci raw = ref_next(raw); 29762306a36Sopenharmony_ci if (unlikely(!raw)) { 29862306a36Sopenharmony_ci pr_warn("eep. End of raw list while still supposedly nodes to GC\n"); 29962306a36Sopenharmony_ci pr_warn("erase block at 0x%08x. free_size 0x%08x, dirty_size 0x%08x, used_size 0x%08x\n", 30062306a36Sopenharmony_ci jeb->offset, jeb->free_size, 30162306a36Sopenharmony_ci jeb->dirty_size, jeb->used_size); 30262306a36Sopenharmony_ci jeb->gc_node = raw; 30362306a36Sopenharmony_ci spin_unlock(&c->erase_completion_lock); 30462306a36Sopenharmony_ci mutex_unlock(&c->alloc_sem); 30562306a36Sopenharmony_ci BUG(); 30662306a36Sopenharmony_ci } 30762306a36Sopenharmony_ci } 30862306a36Sopenharmony_ci jeb->gc_node = raw; 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci jffs2_dbg(1, "Going to garbage collect node at 0x%08x\n", 31162306a36Sopenharmony_ci ref_offset(raw)); 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci if (!raw->next_in_ino) { 31462306a36Sopenharmony_ci /* Inode-less node. Clean marker, snapshot or something like that */ 31562306a36Sopenharmony_ci spin_unlock(&c->erase_completion_lock); 31662306a36Sopenharmony_ci if (ref_flags(raw) == REF_PRISTINE) { 31762306a36Sopenharmony_ci /* It's an unknown node with JFFS2_FEATURE_RWCOMPAT_COPY */ 31862306a36Sopenharmony_ci jffs2_garbage_collect_pristine(c, NULL, raw); 31962306a36Sopenharmony_ci } else { 32062306a36Sopenharmony_ci /* Just mark it obsolete */ 32162306a36Sopenharmony_ci jffs2_mark_node_obsolete(c, raw); 32262306a36Sopenharmony_ci } 32362306a36Sopenharmony_ci mutex_unlock(&c->alloc_sem); 32462306a36Sopenharmony_ci goto eraseit_lock; 32562306a36Sopenharmony_ci } 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci ic = jffs2_raw_ref_to_ic(raw); 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci#ifdef CONFIG_JFFS2_FS_XATTR 33062306a36Sopenharmony_ci /* When 'ic' refers xattr_datum/xattr_ref, this node is GCed as xattr. 33162306a36Sopenharmony_ci * We can decide whether this node is inode or xattr by ic->class. */ 33262306a36Sopenharmony_ci if (ic->class == RAWNODE_CLASS_XATTR_DATUM 33362306a36Sopenharmony_ci || ic->class == RAWNODE_CLASS_XATTR_REF) { 33462306a36Sopenharmony_ci spin_unlock(&c->erase_completion_lock); 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci if (ic->class == RAWNODE_CLASS_XATTR_DATUM) { 33762306a36Sopenharmony_ci ret = jffs2_garbage_collect_xattr_datum(c, (struct jffs2_xattr_datum *)ic, raw); 33862306a36Sopenharmony_ci } else { 33962306a36Sopenharmony_ci ret = jffs2_garbage_collect_xattr_ref(c, (struct jffs2_xattr_ref *)ic, raw); 34062306a36Sopenharmony_ci } 34162306a36Sopenharmony_ci goto test_gcnode; 34262306a36Sopenharmony_ci } 34362306a36Sopenharmony_ci#endif 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci /* We need to hold the inocache. Either the erase_completion_lock or 34662306a36Sopenharmony_ci the inocache_lock are sufficient; we trade down since the inocache_lock 34762306a36Sopenharmony_ci causes less contention. */ 34862306a36Sopenharmony_ci spin_lock(&c->inocache_lock); 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci spin_unlock(&c->erase_completion_lock); 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci jffs2_dbg(1, "%s(): collecting from block @0x%08x. Node @0x%08x(%d), ino #%u\n", 35362306a36Sopenharmony_ci __func__, jeb->offset, ref_offset(raw), ref_flags(raw), 35462306a36Sopenharmony_ci ic->ino); 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci /* Three possibilities: 35762306a36Sopenharmony_ci 1. Inode is already in-core. We must iget it and do proper 35862306a36Sopenharmony_ci updating to its fragtree, etc. 35962306a36Sopenharmony_ci 2. Inode is not in-core, node is REF_PRISTINE. We lock the 36062306a36Sopenharmony_ci inocache to prevent a read_inode(), copy the node intact. 36162306a36Sopenharmony_ci 3. Inode is not in-core, node is not pristine. We must iget() 36262306a36Sopenharmony_ci and take the slow path. 36362306a36Sopenharmony_ci */ 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci switch(ic->state) { 36662306a36Sopenharmony_ci case INO_STATE_CHECKEDABSENT: 36762306a36Sopenharmony_ci /* It's been checked, but it's not currently in-core. 36862306a36Sopenharmony_ci We can just copy any pristine nodes, but have 36962306a36Sopenharmony_ci to prevent anyone else from doing read_inode() while 37062306a36Sopenharmony_ci we're at it, so we set the state accordingly */ 37162306a36Sopenharmony_ci if (ref_flags(raw) == REF_PRISTINE) 37262306a36Sopenharmony_ci ic->state = INO_STATE_GC; 37362306a36Sopenharmony_ci else { 37462306a36Sopenharmony_ci jffs2_dbg(1, "Ino #%u is absent but node not REF_PRISTINE. Reading.\n", 37562306a36Sopenharmony_ci ic->ino); 37662306a36Sopenharmony_ci } 37762306a36Sopenharmony_ci break; 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci case INO_STATE_PRESENT: 38062306a36Sopenharmony_ci /* It's in-core. GC must iget() it. */ 38162306a36Sopenharmony_ci break; 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci case INO_STATE_UNCHECKED: 38462306a36Sopenharmony_ci case INO_STATE_CHECKING: 38562306a36Sopenharmony_ci case INO_STATE_GC: 38662306a36Sopenharmony_ci /* Should never happen. We should have finished checking 38762306a36Sopenharmony_ci by the time we actually start doing any GC, and since 38862306a36Sopenharmony_ci we're holding the alloc_sem, no other garbage collection 38962306a36Sopenharmony_ci can happen. 39062306a36Sopenharmony_ci */ 39162306a36Sopenharmony_ci pr_crit("Inode #%u already in state %d in jffs2_garbage_collect_pass()!\n", 39262306a36Sopenharmony_ci ic->ino, ic->state); 39362306a36Sopenharmony_ci mutex_unlock(&c->alloc_sem); 39462306a36Sopenharmony_ci spin_unlock(&c->inocache_lock); 39562306a36Sopenharmony_ci BUG(); 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci case INO_STATE_READING: 39862306a36Sopenharmony_ci /* Someone's currently trying to read it. We must wait for 39962306a36Sopenharmony_ci them to finish and then go through the full iget() route 40062306a36Sopenharmony_ci to do the GC. However, sometimes read_inode() needs to get 40162306a36Sopenharmony_ci the alloc_sem() (for marking nodes invalid) so we must 40262306a36Sopenharmony_ci drop the alloc_sem before sleeping. */ 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci mutex_unlock(&c->alloc_sem); 40562306a36Sopenharmony_ci jffs2_dbg(1, "%s(): waiting for ino #%u in state %d\n", 40662306a36Sopenharmony_ci __func__, ic->ino, ic->state); 40762306a36Sopenharmony_ci sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock); 40862306a36Sopenharmony_ci /* And because we dropped the alloc_sem we must start again from the 40962306a36Sopenharmony_ci beginning. Ponder chance of livelock here -- we're returning success 41062306a36Sopenharmony_ci without actually making any progress. 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci Q: What are the chances that the inode is back in INO_STATE_READING 41362306a36Sopenharmony_ci again by the time we next enter this function? And that this happens 41462306a36Sopenharmony_ci enough times to cause a real delay? 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci A: Small enough that I don't care :) 41762306a36Sopenharmony_ci */ 41862306a36Sopenharmony_ci return 0; 41962306a36Sopenharmony_ci } 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci /* OK. Now if the inode is in state INO_STATE_GC, we are going to copy the 42262306a36Sopenharmony_ci node intact, and we don't have to muck about with the fragtree etc. 42362306a36Sopenharmony_ci because we know it's not in-core. If it _was_ in-core, we go through 42462306a36Sopenharmony_ci all the iget() crap anyway */ 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci if (ic->state == INO_STATE_GC) { 42762306a36Sopenharmony_ci spin_unlock(&c->inocache_lock); 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci ret = jffs2_garbage_collect_pristine(c, ic, raw); 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci spin_lock(&c->inocache_lock); 43262306a36Sopenharmony_ci ic->state = INO_STATE_CHECKEDABSENT; 43362306a36Sopenharmony_ci wake_up(&c->inocache_wq); 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci if (ret != -EBADFD) { 43662306a36Sopenharmony_ci spin_unlock(&c->inocache_lock); 43762306a36Sopenharmony_ci goto test_gcnode; 43862306a36Sopenharmony_ci } 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci /* Fall through if it wanted us to, with inocache_lock held */ 44162306a36Sopenharmony_ci } 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci /* Prevent the fairly unlikely race where the gcblock is 44462306a36Sopenharmony_ci entirely obsoleted by the final close of a file which had 44562306a36Sopenharmony_ci the only valid nodes in the block, followed by erasure, 44662306a36Sopenharmony_ci followed by freeing of the ic because the erased block(s) 44762306a36Sopenharmony_ci held _all_ the nodes of that inode.... never been seen but 44862306a36Sopenharmony_ci it's vaguely possible. */ 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci inum = ic->ino; 45162306a36Sopenharmony_ci nlink = ic->pino_nlink; 45262306a36Sopenharmony_ci spin_unlock(&c->inocache_lock); 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci f = jffs2_gc_fetch_inode(c, inum, !nlink); 45562306a36Sopenharmony_ci if (IS_ERR(f)) { 45662306a36Sopenharmony_ci ret = PTR_ERR(f); 45762306a36Sopenharmony_ci goto release_sem; 45862306a36Sopenharmony_ci } 45962306a36Sopenharmony_ci if (!f) { 46062306a36Sopenharmony_ci ret = 0; 46162306a36Sopenharmony_ci goto release_sem; 46262306a36Sopenharmony_ci } 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci ret = jffs2_garbage_collect_live(c, jeb, raw, f); 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci jffs2_gc_release_inode(c, f); 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci test_gcnode: 46962306a36Sopenharmony_ci if (jeb->dirty_size == gcblock_dirty && !ref_obsolete(jeb->gc_node)) { 47062306a36Sopenharmony_ci /* Eep. This really should never happen. GC is broken */ 47162306a36Sopenharmony_ci pr_err("Error garbage collecting node at %08x!\n", 47262306a36Sopenharmony_ci ref_offset(jeb->gc_node)); 47362306a36Sopenharmony_ci ret = -ENOSPC; 47462306a36Sopenharmony_ci } 47562306a36Sopenharmony_ci release_sem: 47662306a36Sopenharmony_ci mutex_unlock(&c->alloc_sem); 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci eraseit_lock: 47962306a36Sopenharmony_ci /* If we've finished this block, start it erasing */ 48062306a36Sopenharmony_ci spin_lock(&c->erase_completion_lock); 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci eraseit: 48362306a36Sopenharmony_ci if (c->gcblock && !c->gcblock->used_size) { 48462306a36Sopenharmony_ci jffs2_dbg(1, "Block at 0x%08x completely obsoleted by GC. Moving to erase_pending_list\n", 48562306a36Sopenharmony_ci c->gcblock->offset); 48662306a36Sopenharmony_ci /* We're GC'ing an empty block? */ 48762306a36Sopenharmony_ci list_add_tail(&c->gcblock->list, &c->erase_pending_list); 48862306a36Sopenharmony_ci c->gcblock = NULL; 48962306a36Sopenharmony_ci c->nr_erasing_blocks++; 49062306a36Sopenharmony_ci jffs2_garbage_collect_trigger(c); 49162306a36Sopenharmony_ci } 49262306a36Sopenharmony_ci spin_unlock(&c->erase_completion_lock); 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci return ret; 49562306a36Sopenharmony_ci} 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_cistatic int jffs2_garbage_collect_live(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, 49862306a36Sopenharmony_ci struct jffs2_raw_node_ref *raw, struct jffs2_inode_info *f) 49962306a36Sopenharmony_ci{ 50062306a36Sopenharmony_ci struct jffs2_node_frag *frag; 50162306a36Sopenharmony_ci struct jffs2_full_dnode *fn = NULL; 50262306a36Sopenharmony_ci struct jffs2_full_dirent *fd; 50362306a36Sopenharmony_ci uint32_t start = 0, end = 0, nrfrags = 0; 50462306a36Sopenharmony_ci int ret = 0; 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci mutex_lock(&f->sem); 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci /* Now we have the lock for this inode. Check that it's still the one at the head 50962306a36Sopenharmony_ci of the list. */ 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci spin_lock(&c->erase_completion_lock); 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci if (c->gcblock != jeb) { 51462306a36Sopenharmony_ci spin_unlock(&c->erase_completion_lock); 51562306a36Sopenharmony_ci jffs2_dbg(1, "GC block is no longer gcblock. Restart\n"); 51662306a36Sopenharmony_ci goto upnout; 51762306a36Sopenharmony_ci } 51862306a36Sopenharmony_ci if (ref_obsolete(raw)) { 51962306a36Sopenharmony_ci spin_unlock(&c->erase_completion_lock); 52062306a36Sopenharmony_ci jffs2_dbg(1, "node to be GC'd was obsoleted in the meantime.\n"); 52162306a36Sopenharmony_ci /* They'll call again */ 52262306a36Sopenharmony_ci goto upnout; 52362306a36Sopenharmony_ci } 52462306a36Sopenharmony_ci spin_unlock(&c->erase_completion_lock); 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci /* OK. Looks safe. And nobody can get us now because we have the semaphore. Move the block */ 52762306a36Sopenharmony_ci if (f->metadata && f->metadata->raw == raw) { 52862306a36Sopenharmony_ci fn = f->metadata; 52962306a36Sopenharmony_ci ret = jffs2_garbage_collect_metadata(c, jeb, f, fn); 53062306a36Sopenharmony_ci goto upnout; 53162306a36Sopenharmony_ci } 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci /* FIXME. Read node and do lookup? */ 53462306a36Sopenharmony_ci for (frag = frag_first(&f->fragtree); frag; frag = frag_next(frag)) { 53562306a36Sopenharmony_ci if (frag->node && frag->node->raw == raw) { 53662306a36Sopenharmony_ci fn = frag->node; 53762306a36Sopenharmony_ci end = frag->ofs + frag->size; 53862306a36Sopenharmony_ci if (!nrfrags++) 53962306a36Sopenharmony_ci start = frag->ofs; 54062306a36Sopenharmony_ci if (nrfrags == frag->node->frags) 54162306a36Sopenharmony_ci break; /* We've found them all */ 54262306a36Sopenharmony_ci } 54362306a36Sopenharmony_ci } 54462306a36Sopenharmony_ci if (fn) { 54562306a36Sopenharmony_ci if (ref_flags(raw) == REF_PRISTINE) { 54662306a36Sopenharmony_ci ret = jffs2_garbage_collect_pristine(c, f->inocache, raw); 54762306a36Sopenharmony_ci if (!ret) { 54862306a36Sopenharmony_ci /* Urgh. Return it sensibly. */ 54962306a36Sopenharmony_ci frag->node->raw = f->inocache->nodes; 55062306a36Sopenharmony_ci } 55162306a36Sopenharmony_ci if (ret != -EBADFD) 55262306a36Sopenharmony_ci goto upnout; 55362306a36Sopenharmony_ci } 55462306a36Sopenharmony_ci /* We found a datanode. Do the GC */ 55562306a36Sopenharmony_ci if((start >> PAGE_SHIFT) < ((end-1) >> PAGE_SHIFT)) { 55662306a36Sopenharmony_ci /* It crosses a page boundary. Therefore, it must be a hole. */ 55762306a36Sopenharmony_ci ret = jffs2_garbage_collect_hole(c, jeb, f, fn, start, end); 55862306a36Sopenharmony_ci } else { 55962306a36Sopenharmony_ci /* It could still be a hole. But we GC the page this way anyway */ 56062306a36Sopenharmony_ci ret = jffs2_garbage_collect_dnode(c, jeb, f, fn, start, end); 56162306a36Sopenharmony_ci } 56262306a36Sopenharmony_ci goto upnout; 56362306a36Sopenharmony_ci } 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci /* Wasn't a dnode. Try dirent */ 56662306a36Sopenharmony_ci for (fd = f->dents; fd; fd=fd->next) { 56762306a36Sopenharmony_ci if (fd->raw == raw) 56862306a36Sopenharmony_ci break; 56962306a36Sopenharmony_ci } 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci if (fd && fd->ino) { 57262306a36Sopenharmony_ci ret = jffs2_garbage_collect_dirent(c, jeb, f, fd); 57362306a36Sopenharmony_ci } else if (fd) { 57462306a36Sopenharmony_ci ret = jffs2_garbage_collect_deletion_dirent(c, jeb, f, fd); 57562306a36Sopenharmony_ci } else { 57662306a36Sopenharmony_ci pr_warn("Raw node at 0x%08x wasn't in node lists for ino #%u\n", 57762306a36Sopenharmony_ci ref_offset(raw), f->inocache->ino); 57862306a36Sopenharmony_ci if (ref_obsolete(raw)) { 57962306a36Sopenharmony_ci pr_warn("But it's obsolete so we don't mind too much\n"); 58062306a36Sopenharmony_ci } else { 58162306a36Sopenharmony_ci jffs2_dbg_dump_node(c, ref_offset(raw)); 58262306a36Sopenharmony_ci BUG(); 58362306a36Sopenharmony_ci } 58462306a36Sopenharmony_ci } 58562306a36Sopenharmony_ci upnout: 58662306a36Sopenharmony_ci mutex_unlock(&f->sem); 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci return ret; 58962306a36Sopenharmony_ci} 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_cistatic int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, 59262306a36Sopenharmony_ci struct jffs2_inode_cache *ic, 59362306a36Sopenharmony_ci struct jffs2_raw_node_ref *raw) 59462306a36Sopenharmony_ci{ 59562306a36Sopenharmony_ci union jffs2_node_union *node; 59662306a36Sopenharmony_ci size_t retlen; 59762306a36Sopenharmony_ci int ret; 59862306a36Sopenharmony_ci uint32_t phys_ofs, alloclen; 59962306a36Sopenharmony_ci uint32_t crc, rawlen; 60062306a36Sopenharmony_ci int retried = 0; 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci jffs2_dbg(1, "Going to GC REF_PRISTINE node at 0x%08x\n", 60362306a36Sopenharmony_ci ref_offset(raw)); 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci alloclen = rawlen = ref_totlen(c, c->gcblock, raw); 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci /* Ask for a small amount of space (or the totlen if smaller) because we 60862306a36Sopenharmony_ci don't want to force wastage of the end of a block if splitting would 60962306a36Sopenharmony_ci work. */ 61062306a36Sopenharmony_ci if (ic && alloclen > sizeof(struct jffs2_raw_inode) + JFFS2_MIN_DATA_LEN) 61162306a36Sopenharmony_ci alloclen = sizeof(struct jffs2_raw_inode) + JFFS2_MIN_DATA_LEN; 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci ret = jffs2_reserve_space_gc(c, alloclen, &alloclen, rawlen); 61462306a36Sopenharmony_ci /* 'rawlen' is not the exact summary size; it is only an upper estimation */ 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci if (ret) 61762306a36Sopenharmony_ci return ret; 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci if (alloclen < rawlen) { 62062306a36Sopenharmony_ci /* Doesn't fit untouched. We'll go the old route and split it */ 62162306a36Sopenharmony_ci return -EBADFD; 62262306a36Sopenharmony_ci } 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci node = kmalloc(rawlen, GFP_KERNEL); 62562306a36Sopenharmony_ci if (!node) 62662306a36Sopenharmony_ci return -ENOMEM; 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci ret = jffs2_flash_read(c, ref_offset(raw), rawlen, &retlen, (char *)node); 62962306a36Sopenharmony_ci if (!ret && retlen != rawlen) 63062306a36Sopenharmony_ci ret = -EIO; 63162306a36Sopenharmony_ci if (ret) 63262306a36Sopenharmony_ci goto out_node; 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci crc = crc32(0, node, sizeof(struct jffs2_unknown_node)-4); 63562306a36Sopenharmony_ci if (je32_to_cpu(node->u.hdr_crc) != crc) { 63662306a36Sopenharmony_ci pr_warn("Header CRC failed on REF_PRISTINE node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", 63762306a36Sopenharmony_ci ref_offset(raw), je32_to_cpu(node->u.hdr_crc), crc); 63862306a36Sopenharmony_ci goto bail; 63962306a36Sopenharmony_ci } 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci switch(je16_to_cpu(node->u.nodetype)) { 64262306a36Sopenharmony_ci case JFFS2_NODETYPE_INODE: 64362306a36Sopenharmony_ci crc = crc32(0, node, sizeof(node->i)-8); 64462306a36Sopenharmony_ci if (je32_to_cpu(node->i.node_crc) != crc) { 64562306a36Sopenharmony_ci pr_warn("Node CRC failed on REF_PRISTINE data node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", 64662306a36Sopenharmony_ci ref_offset(raw), je32_to_cpu(node->i.node_crc), 64762306a36Sopenharmony_ci crc); 64862306a36Sopenharmony_ci goto bail; 64962306a36Sopenharmony_ci } 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci if (je32_to_cpu(node->i.dsize)) { 65262306a36Sopenharmony_ci crc = crc32(0, node->i.data, je32_to_cpu(node->i.csize)); 65362306a36Sopenharmony_ci if (je32_to_cpu(node->i.data_crc) != crc) { 65462306a36Sopenharmony_ci pr_warn("Data CRC failed on REF_PRISTINE data node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", 65562306a36Sopenharmony_ci ref_offset(raw), 65662306a36Sopenharmony_ci je32_to_cpu(node->i.data_crc), crc); 65762306a36Sopenharmony_ci goto bail; 65862306a36Sopenharmony_ci } 65962306a36Sopenharmony_ci } 66062306a36Sopenharmony_ci break; 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci case JFFS2_NODETYPE_DIRENT: 66362306a36Sopenharmony_ci crc = crc32(0, node, sizeof(node->d)-8); 66462306a36Sopenharmony_ci if (je32_to_cpu(node->d.node_crc) != crc) { 66562306a36Sopenharmony_ci pr_warn("Node CRC failed on REF_PRISTINE dirent node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", 66662306a36Sopenharmony_ci ref_offset(raw), 66762306a36Sopenharmony_ci je32_to_cpu(node->d.node_crc), crc); 66862306a36Sopenharmony_ci goto bail; 66962306a36Sopenharmony_ci } 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci if (strnlen(node->d.name, node->d.nsize) != node->d.nsize) { 67262306a36Sopenharmony_ci pr_warn("Name in dirent node at 0x%08x contains zeroes\n", 67362306a36Sopenharmony_ci ref_offset(raw)); 67462306a36Sopenharmony_ci goto bail; 67562306a36Sopenharmony_ci } 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci if (node->d.nsize) { 67862306a36Sopenharmony_ci crc = crc32(0, node->d.name, node->d.nsize); 67962306a36Sopenharmony_ci if (je32_to_cpu(node->d.name_crc) != crc) { 68062306a36Sopenharmony_ci pr_warn("Name CRC failed on REF_PRISTINE dirent node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", 68162306a36Sopenharmony_ci ref_offset(raw), 68262306a36Sopenharmony_ci je32_to_cpu(node->d.name_crc), crc); 68362306a36Sopenharmony_ci goto bail; 68462306a36Sopenharmony_ci } 68562306a36Sopenharmony_ci } 68662306a36Sopenharmony_ci break; 68762306a36Sopenharmony_ci default: 68862306a36Sopenharmony_ci /* If it's inode-less, we don't _know_ what it is. Just copy it intact */ 68962306a36Sopenharmony_ci if (ic) { 69062306a36Sopenharmony_ci pr_warn("Unknown node type for REF_PRISTINE node at 0x%08x: 0x%04x\n", 69162306a36Sopenharmony_ci ref_offset(raw), je16_to_cpu(node->u.nodetype)); 69262306a36Sopenharmony_ci goto bail; 69362306a36Sopenharmony_ci } 69462306a36Sopenharmony_ci } 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci /* OK, all the CRCs are good; this node can just be copied as-is. */ 69762306a36Sopenharmony_ci retry: 69862306a36Sopenharmony_ci phys_ofs = write_ofs(c); 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci ret = jffs2_flash_write(c, phys_ofs, rawlen, &retlen, (char *)node); 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci if (ret || (retlen != rawlen)) { 70362306a36Sopenharmony_ci pr_notice("Write of %d bytes at 0x%08x failed. returned %d, retlen %zd\n", 70462306a36Sopenharmony_ci rawlen, phys_ofs, ret, retlen); 70562306a36Sopenharmony_ci if (retlen) { 70662306a36Sopenharmony_ci jffs2_add_physical_node_ref(c, phys_ofs | REF_OBSOLETE, rawlen, NULL); 70762306a36Sopenharmony_ci } else { 70862306a36Sopenharmony_ci pr_notice("Not marking the space at 0x%08x as dirty because the flash driver returned retlen zero\n", 70962306a36Sopenharmony_ci phys_ofs); 71062306a36Sopenharmony_ci } 71162306a36Sopenharmony_ci if (!retried) { 71262306a36Sopenharmony_ci /* Try to reallocate space and retry */ 71362306a36Sopenharmony_ci uint32_t dummy; 71462306a36Sopenharmony_ci struct jffs2_eraseblock *jeb = &c->blocks[phys_ofs / c->sector_size]; 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci retried = 1; 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci jffs2_dbg(1, "Retrying failed write of REF_PRISTINE node.\n"); 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci jffs2_dbg_acct_sanity_check(c,jeb); 72162306a36Sopenharmony_ci jffs2_dbg_acct_paranoia_check(c, jeb); 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci ret = jffs2_reserve_space_gc(c, rawlen, &dummy, rawlen); 72462306a36Sopenharmony_ci /* this is not the exact summary size of it, 72562306a36Sopenharmony_ci it is only an upper estimation */ 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci if (!ret) { 72862306a36Sopenharmony_ci jffs2_dbg(1, "Allocated space at 0x%08x to retry failed write.\n", 72962306a36Sopenharmony_ci phys_ofs); 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci jffs2_dbg_acct_sanity_check(c,jeb); 73262306a36Sopenharmony_ci jffs2_dbg_acct_paranoia_check(c, jeb); 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci goto retry; 73562306a36Sopenharmony_ci } 73662306a36Sopenharmony_ci jffs2_dbg(1, "Failed to allocate space to retry failed write: %d!\n", 73762306a36Sopenharmony_ci ret); 73862306a36Sopenharmony_ci } 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci if (!ret) 74162306a36Sopenharmony_ci ret = -EIO; 74262306a36Sopenharmony_ci goto out_node; 74362306a36Sopenharmony_ci } 74462306a36Sopenharmony_ci jffs2_add_physical_node_ref(c, phys_ofs | REF_PRISTINE, rawlen, ic); 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci jffs2_mark_node_obsolete(c, raw); 74762306a36Sopenharmony_ci jffs2_dbg(1, "WHEEE! GC REF_PRISTINE node at 0x%08x succeeded\n", 74862306a36Sopenharmony_ci ref_offset(raw)); 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci out_node: 75162306a36Sopenharmony_ci kfree(node); 75262306a36Sopenharmony_ci return ret; 75362306a36Sopenharmony_ci bail: 75462306a36Sopenharmony_ci ret = -EBADFD; 75562306a36Sopenharmony_ci goto out_node; 75662306a36Sopenharmony_ci} 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_cistatic int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, 75962306a36Sopenharmony_ci struct jffs2_inode_info *f, struct jffs2_full_dnode *fn) 76062306a36Sopenharmony_ci{ 76162306a36Sopenharmony_ci struct jffs2_full_dnode *new_fn; 76262306a36Sopenharmony_ci struct jffs2_raw_inode ri; 76362306a36Sopenharmony_ci struct jffs2_node_frag *last_frag; 76462306a36Sopenharmony_ci union jffs2_device_node dev; 76562306a36Sopenharmony_ci char *mdata = NULL; 76662306a36Sopenharmony_ci int mdatalen = 0; 76762306a36Sopenharmony_ci uint32_t alloclen, ilen; 76862306a36Sopenharmony_ci int ret; 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci if (S_ISBLK(JFFS2_F_I_MODE(f)) || 77162306a36Sopenharmony_ci S_ISCHR(JFFS2_F_I_MODE(f)) ) { 77262306a36Sopenharmony_ci /* For these, we don't actually need to read the old node */ 77362306a36Sopenharmony_ci mdatalen = jffs2_encode_dev(&dev, JFFS2_F_I_RDEV(f)); 77462306a36Sopenharmony_ci mdata = (char *)&dev; 77562306a36Sopenharmony_ci jffs2_dbg(1, "%s(): Writing %d bytes of kdev_t\n", 77662306a36Sopenharmony_ci __func__, mdatalen); 77762306a36Sopenharmony_ci } else if (S_ISLNK(JFFS2_F_I_MODE(f))) { 77862306a36Sopenharmony_ci mdatalen = fn->size; 77962306a36Sopenharmony_ci mdata = kmalloc(fn->size, GFP_KERNEL); 78062306a36Sopenharmony_ci if (!mdata) { 78162306a36Sopenharmony_ci pr_warn("kmalloc of mdata failed in jffs2_garbage_collect_metadata()\n"); 78262306a36Sopenharmony_ci return -ENOMEM; 78362306a36Sopenharmony_ci } 78462306a36Sopenharmony_ci ret = jffs2_read_dnode(c, f, fn, mdata, 0, mdatalen); 78562306a36Sopenharmony_ci if (ret) { 78662306a36Sopenharmony_ci pr_warn("read of old metadata failed in jffs2_garbage_collect_metadata(): %d\n", 78762306a36Sopenharmony_ci ret); 78862306a36Sopenharmony_ci kfree(mdata); 78962306a36Sopenharmony_ci return ret; 79062306a36Sopenharmony_ci } 79162306a36Sopenharmony_ci jffs2_dbg(1, "%s(): Writing %d bites of symlink target\n", 79262306a36Sopenharmony_ci __func__, mdatalen); 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci } 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci ret = jffs2_reserve_space_gc(c, sizeof(ri) + mdatalen, &alloclen, 79762306a36Sopenharmony_ci JFFS2_SUMMARY_INODE_SIZE); 79862306a36Sopenharmony_ci if (ret) { 79962306a36Sopenharmony_ci pr_warn("jffs2_reserve_space_gc of %zd bytes for garbage_collect_metadata failed: %d\n", 80062306a36Sopenharmony_ci sizeof(ri) + mdatalen, ret); 80162306a36Sopenharmony_ci goto out; 80262306a36Sopenharmony_ci } 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci last_frag = frag_last(&f->fragtree); 80562306a36Sopenharmony_ci if (last_frag) 80662306a36Sopenharmony_ci /* Fetch the inode length from the fragtree rather then 80762306a36Sopenharmony_ci * from i_size since i_size may have not been updated yet */ 80862306a36Sopenharmony_ci ilen = last_frag->ofs + last_frag->size; 80962306a36Sopenharmony_ci else 81062306a36Sopenharmony_ci ilen = JFFS2_F_I_SIZE(f); 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci memset(&ri, 0, sizeof(ri)); 81362306a36Sopenharmony_ci ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); 81462306a36Sopenharmony_ci ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE); 81562306a36Sopenharmony_ci ri.totlen = cpu_to_je32(sizeof(ri) + mdatalen); 81662306a36Sopenharmony_ci ri.hdr_crc = cpu_to_je32(crc32(0, &ri, sizeof(struct jffs2_unknown_node)-4)); 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci ri.ino = cpu_to_je32(f->inocache->ino); 81962306a36Sopenharmony_ci ri.version = cpu_to_je32(++f->highest_version); 82062306a36Sopenharmony_ci ri.mode = cpu_to_jemode(JFFS2_F_I_MODE(f)); 82162306a36Sopenharmony_ci ri.uid = cpu_to_je16(JFFS2_F_I_UID(f)); 82262306a36Sopenharmony_ci ri.gid = cpu_to_je16(JFFS2_F_I_GID(f)); 82362306a36Sopenharmony_ci ri.isize = cpu_to_je32(ilen); 82462306a36Sopenharmony_ci ri.atime = cpu_to_je32(JFFS2_F_I_ATIME(f)); 82562306a36Sopenharmony_ci ri.ctime = cpu_to_je32(JFFS2_F_I_CTIME(f)); 82662306a36Sopenharmony_ci ri.mtime = cpu_to_je32(JFFS2_F_I_MTIME(f)); 82762306a36Sopenharmony_ci ri.offset = cpu_to_je32(0); 82862306a36Sopenharmony_ci ri.csize = cpu_to_je32(mdatalen); 82962306a36Sopenharmony_ci ri.dsize = cpu_to_je32(mdatalen); 83062306a36Sopenharmony_ci ri.compr = JFFS2_COMPR_NONE; 83162306a36Sopenharmony_ci ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri)-8)); 83262306a36Sopenharmony_ci ri.data_crc = cpu_to_je32(crc32(0, mdata, mdatalen)); 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci new_fn = jffs2_write_dnode(c, f, &ri, mdata, mdatalen, ALLOC_GC); 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci if (IS_ERR(new_fn)) { 83762306a36Sopenharmony_ci pr_warn("Error writing new dnode: %ld\n", PTR_ERR(new_fn)); 83862306a36Sopenharmony_ci ret = PTR_ERR(new_fn); 83962306a36Sopenharmony_ci goto out; 84062306a36Sopenharmony_ci } 84162306a36Sopenharmony_ci jffs2_mark_node_obsolete(c, fn->raw); 84262306a36Sopenharmony_ci jffs2_free_full_dnode(fn); 84362306a36Sopenharmony_ci f->metadata = new_fn; 84462306a36Sopenharmony_ci out: 84562306a36Sopenharmony_ci if (S_ISLNK(JFFS2_F_I_MODE(f))) 84662306a36Sopenharmony_ci kfree(mdata); 84762306a36Sopenharmony_ci return ret; 84862306a36Sopenharmony_ci} 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_cistatic int jffs2_garbage_collect_dirent(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, 85162306a36Sopenharmony_ci struct jffs2_inode_info *f, struct jffs2_full_dirent *fd) 85262306a36Sopenharmony_ci{ 85362306a36Sopenharmony_ci struct jffs2_full_dirent *new_fd; 85462306a36Sopenharmony_ci struct jffs2_raw_dirent rd; 85562306a36Sopenharmony_ci uint32_t alloclen; 85662306a36Sopenharmony_ci int ret; 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_ci rd.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); 85962306a36Sopenharmony_ci rd.nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT); 86062306a36Sopenharmony_ci rd.nsize = strlen(fd->name); 86162306a36Sopenharmony_ci rd.totlen = cpu_to_je32(sizeof(rd) + rd.nsize); 86262306a36Sopenharmony_ci rd.hdr_crc = cpu_to_je32(crc32(0, &rd, sizeof(struct jffs2_unknown_node)-4)); 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci rd.pino = cpu_to_je32(f->inocache->ino); 86562306a36Sopenharmony_ci rd.version = cpu_to_je32(++f->highest_version); 86662306a36Sopenharmony_ci rd.ino = cpu_to_je32(fd->ino); 86762306a36Sopenharmony_ci /* If the times on this inode were set by explicit utime() they can be different, 86862306a36Sopenharmony_ci so refrain from splatting them. */ 86962306a36Sopenharmony_ci if (JFFS2_F_I_MTIME(f) == JFFS2_F_I_CTIME(f)) 87062306a36Sopenharmony_ci rd.mctime = cpu_to_je32(JFFS2_F_I_MTIME(f)); 87162306a36Sopenharmony_ci else 87262306a36Sopenharmony_ci rd.mctime = cpu_to_je32(0); 87362306a36Sopenharmony_ci rd.type = fd->type; 87462306a36Sopenharmony_ci rd.node_crc = cpu_to_je32(crc32(0, &rd, sizeof(rd)-8)); 87562306a36Sopenharmony_ci rd.name_crc = cpu_to_je32(crc32(0, fd->name, rd.nsize)); 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci ret = jffs2_reserve_space_gc(c, sizeof(rd)+rd.nsize, &alloclen, 87862306a36Sopenharmony_ci JFFS2_SUMMARY_DIRENT_SIZE(rd.nsize)); 87962306a36Sopenharmony_ci if (ret) { 88062306a36Sopenharmony_ci pr_warn("jffs2_reserve_space_gc of %zd bytes for garbage_collect_dirent failed: %d\n", 88162306a36Sopenharmony_ci sizeof(rd)+rd.nsize, ret); 88262306a36Sopenharmony_ci return ret; 88362306a36Sopenharmony_ci } 88462306a36Sopenharmony_ci new_fd = jffs2_write_dirent(c, f, &rd, fd->name, rd.nsize, ALLOC_GC); 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci if (IS_ERR(new_fd)) { 88762306a36Sopenharmony_ci pr_warn("jffs2_write_dirent in garbage_collect_dirent failed: %ld\n", 88862306a36Sopenharmony_ci PTR_ERR(new_fd)); 88962306a36Sopenharmony_ci return PTR_ERR(new_fd); 89062306a36Sopenharmony_ci } 89162306a36Sopenharmony_ci jffs2_add_fd_to_list(c, new_fd, &f->dents); 89262306a36Sopenharmony_ci return 0; 89362306a36Sopenharmony_ci} 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_cistatic int jffs2_garbage_collect_deletion_dirent(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, 89662306a36Sopenharmony_ci struct jffs2_inode_info *f, struct jffs2_full_dirent *fd) 89762306a36Sopenharmony_ci{ 89862306a36Sopenharmony_ci struct jffs2_full_dirent **fdp = &f->dents; 89962306a36Sopenharmony_ci int found = 0; 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci /* On a medium where we can't actually mark nodes obsolete 90262306a36Sopenharmony_ci pernamently, such as NAND flash, we need to work out 90362306a36Sopenharmony_ci whether this deletion dirent is still needed to actively 90462306a36Sopenharmony_ci delete a 'real' dirent with the same name that's still 90562306a36Sopenharmony_ci somewhere else on the flash. */ 90662306a36Sopenharmony_ci if (!jffs2_can_mark_obsolete(c)) { 90762306a36Sopenharmony_ci struct jffs2_raw_dirent *rd; 90862306a36Sopenharmony_ci struct jffs2_raw_node_ref *raw; 90962306a36Sopenharmony_ci int ret; 91062306a36Sopenharmony_ci size_t retlen; 91162306a36Sopenharmony_ci int name_len = strlen(fd->name); 91262306a36Sopenharmony_ci uint32_t name_crc = crc32(0, fd->name, name_len); 91362306a36Sopenharmony_ci uint32_t rawlen = ref_totlen(c, jeb, fd->raw); 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_ci rd = kmalloc(rawlen, GFP_KERNEL); 91662306a36Sopenharmony_ci if (!rd) 91762306a36Sopenharmony_ci return -ENOMEM; 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_ci /* Prevent the erase code from nicking the obsolete node refs while 92062306a36Sopenharmony_ci we're looking at them. I really don't like this extra lock but 92162306a36Sopenharmony_ci can't see any alternative. Suggestions on a postcard to... */ 92262306a36Sopenharmony_ci mutex_lock(&c->erase_free_sem); 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci for (raw = f->inocache->nodes; raw != (void *)f->inocache; raw = raw->next_in_ino) { 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci cond_resched(); 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci /* We only care about obsolete ones */ 92962306a36Sopenharmony_ci if (!(ref_obsolete(raw))) 93062306a36Sopenharmony_ci continue; 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ci /* Any dirent with the same name is going to have the same length... */ 93362306a36Sopenharmony_ci if (ref_totlen(c, NULL, raw) != rawlen) 93462306a36Sopenharmony_ci continue; 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci /* Doesn't matter if there's one in the same erase block. We're going to 93762306a36Sopenharmony_ci delete it too at the same time. */ 93862306a36Sopenharmony_ci if (SECTOR_ADDR(raw->flash_offset) == SECTOR_ADDR(fd->raw->flash_offset)) 93962306a36Sopenharmony_ci continue; 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ci jffs2_dbg(1, "Check potential deletion dirent at %08x\n", 94262306a36Sopenharmony_ci ref_offset(raw)); 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_ci /* This is an obsolete node belonging to the same directory, and it's of the right 94562306a36Sopenharmony_ci length. We need to take a closer look...*/ 94662306a36Sopenharmony_ci ret = jffs2_flash_read(c, ref_offset(raw), rawlen, &retlen, (char *)rd); 94762306a36Sopenharmony_ci if (ret) { 94862306a36Sopenharmony_ci pr_warn("%s(): Read error (%d) reading obsolete node at %08x\n", 94962306a36Sopenharmony_ci __func__, ret, ref_offset(raw)); 95062306a36Sopenharmony_ci /* If we can't read it, we don't need to continue to obsolete it. Continue */ 95162306a36Sopenharmony_ci continue; 95262306a36Sopenharmony_ci } 95362306a36Sopenharmony_ci if (retlen != rawlen) { 95462306a36Sopenharmony_ci pr_warn("%s(): Short read (%zd not %u) reading header from obsolete node at %08x\n", 95562306a36Sopenharmony_ci __func__, retlen, rawlen, 95662306a36Sopenharmony_ci ref_offset(raw)); 95762306a36Sopenharmony_ci continue; 95862306a36Sopenharmony_ci } 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_ci if (je16_to_cpu(rd->nodetype) != JFFS2_NODETYPE_DIRENT) 96162306a36Sopenharmony_ci continue; 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_ci /* If the name CRC doesn't match, skip */ 96462306a36Sopenharmony_ci if (je32_to_cpu(rd->name_crc) != name_crc) 96562306a36Sopenharmony_ci continue; 96662306a36Sopenharmony_ci 96762306a36Sopenharmony_ci /* If the name length doesn't match, or it's another deletion dirent, skip */ 96862306a36Sopenharmony_ci if (rd->nsize != name_len || !je32_to_cpu(rd->ino)) 96962306a36Sopenharmony_ci continue; 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_ci /* OK, check the actual name now */ 97262306a36Sopenharmony_ci if (memcmp(rd->name, fd->name, name_len)) 97362306a36Sopenharmony_ci continue; 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_ci /* OK. The name really does match. There really is still an older node on 97662306a36Sopenharmony_ci the flash which our deletion dirent obsoletes. So we have to write out 97762306a36Sopenharmony_ci a new deletion dirent to replace it */ 97862306a36Sopenharmony_ci mutex_unlock(&c->erase_free_sem); 97962306a36Sopenharmony_ci 98062306a36Sopenharmony_ci jffs2_dbg(1, "Deletion dirent at %08x still obsoletes real dirent \"%s\" at %08x for ino #%u\n", 98162306a36Sopenharmony_ci ref_offset(fd->raw), fd->name, 98262306a36Sopenharmony_ci ref_offset(raw), je32_to_cpu(rd->ino)); 98362306a36Sopenharmony_ci kfree(rd); 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci return jffs2_garbage_collect_dirent(c, jeb, f, fd); 98662306a36Sopenharmony_ci } 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci mutex_unlock(&c->erase_free_sem); 98962306a36Sopenharmony_ci kfree(rd); 99062306a36Sopenharmony_ci } 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ci /* FIXME: If we're deleting a dirent which contains the current mtime and ctime, 99362306a36Sopenharmony_ci we should update the metadata node with those times accordingly */ 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_ci /* No need for it any more. Just mark it obsolete and remove it from the list */ 99662306a36Sopenharmony_ci while (*fdp) { 99762306a36Sopenharmony_ci if ((*fdp) == fd) { 99862306a36Sopenharmony_ci found = 1; 99962306a36Sopenharmony_ci *fdp = fd->next; 100062306a36Sopenharmony_ci break; 100162306a36Sopenharmony_ci } 100262306a36Sopenharmony_ci fdp = &(*fdp)->next; 100362306a36Sopenharmony_ci } 100462306a36Sopenharmony_ci if (!found) { 100562306a36Sopenharmony_ci pr_warn("Deletion dirent \"%s\" not found in list for ino #%u\n", 100662306a36Sopenharmony_ci fd->name, f->inocache->ino); 100762306a36Sopenharmony_ci } 100862306a36Sopenharmony_ci jffs2_mark_node_obsolete(c, fd->raw); 100962306a36Sopenharmony_ci jffs2_free_full_dirent(fd); 101062306a36Sopenharmony_ci return 0; 101162306a36Sopenharmony_ci} 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_cistatic int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, 101462306a36Sopenharmony_ci struct jffs2_inode_info *f, struct jffs2_full_dnode *fn, 101562306a36Sopenharmony_ci uint32_t start, uint32_t end) 101662306a36Sopenharmony_ci{ 101762306a36Sopenharmony_ci struct jffs2_raw_inode ri; 101862306a36Sopenharmony_ci struct jffs2_node_frag *frag; 101962306a36Sopenharmony_ci struct jffs2_full_dnode *new_fn; 102062306a36Sopenharmony_ci uint32_t alloclen, ilen; 102162306a36Sopenharmony_ci int ret; 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci jffs2_dbg(1, "Writing replacement hole node for ino #%u from offset 0x%x to 0x%x\n", 102462306a36Sopenharmony_ci f->inocache->ino, start, end); 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_ci memset(&ri, 0, sizeof(ri)); 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_ci if(fn->frags > 1) { 102962306a36Sopenharmony_ci size_t readlen; 103062306a36Sopenharmony_ci uint32_t crc; 103162306a36Sopenharmony_ci /* It's partially obsoleted by a later write. So we have to 103262306a36Sopenharmony_ci write it out again with the _same_ version as before */ 103362306a36Sopenharmony_ci ret = jffs2_flash_read(c, ref_offset(fn->raw), sizeof(ri), &readlen, (char *)&ri); 103462306a36Sopenharmony_ci if (readlen != sizeof(ri) || ret) { 103562306a36Sopenharmony_ci pr_warn("Node read failed in jffs2_garbage_collect_hole. Ret %d, retlen %zd. Data will be lost by writing new hole node\n", 103662306a36Sopenharmony_ci ret, readlen); 103762306a36Sopenharmony_ci goto fill; 103862306a36Sopenharmony_ci } 103962306a36Sopenharmony_ci if (je16_to_cpu(ri.nodetype) != JFFS2_NODETYPE_INODE) { 104062306a36Sopenharmony_ci pr_warn("%s(): Node at 0x%08x had node type 0x%04x instead of JFFS2_NODETYPE_INODE(0x%04x)\n", 104162306a36Sopenharmony_ci __func__, ref_offset(fn->raw), 104262306a36Sopenharmony_ci je16_to_cpu(ri.nodetype), JFFS2_NODETYPE_INODE); 104362306a36Sopenharmony_ci return -EIO; 104462306a36Sopenharmony_ci } 104562306a36Sopenharmony_ci if (je32_to_cpu(ri.totlen) != sizeof(ri)) { 104662306a36Sopenharmony_ci pr_warn("%s(): Node at 0x%08x had totlen 0x%x instead of expected 0x%zx\n", 104762306a36Sopenharmony_ci __func__, ref_offset(fn->raw), 104862306a36Sopenharmony_ci je32_to_cpu(ri.totlen), sizeof(ri)); 104962306a36Sopenharmony_ci return -EIO; 105062306a36Sopenharmony_ci } 105162306a36Sopenharmony_ci crc = crc32(0, &ri, sizeof(ri)-8); 105262306a36Sopenharmony_ci if (crc != je32_to_cpu(ri.node_crc)) { 105362306a36Sopenharmony_ci pr_warn("%s: Node at 0x%08x had CRC 0x%08x which doesn't match calculated CRC 0x%08x\n", 105462306a36Sopenharmony_ci __func__, ref_offset(fn->raw), 105562306a36Sopenharmony_ci je32_to_cpu(ri.node_crc), crc); 105662306a36Sopenharmony_ci /* FIXME: We could possibly deal with this by writing new holes for each frag */ 105762306a36Sopenharmony_ci pr_warn("Data in the range 0x%08x to 0x%08x of inode #%u will be lost\n", 105862306a36Sopenharmony_ci start, end, f->inocache->ino); 105962306a36Sopenharmony_ci goto fill; 106062306a36Sopenharmony_ci } 106162306a36Sopenharmony_ci if (ri.compr != JFFS2_COMPR_ZERO) { 106262306a36Sopenharmony_ci pr_warn("%s(): Node 0x%08x wasn't a hole node!\n", 106362306a36Sopenharmony_ci __func__, ref_offset(fn->raw)); 106462306a36Sopenharmony_ci pr_warn("Data in the range 0x%08x to 0x%08x of inode #%u will be lost\n", 106562306a36Sopenharmony_ci start, end, f->inocache->ino); 106662306a36Sopenharmony_ci goto fill; 106762306a36Sopenharmony_ci } 106862306a36Sopenharmony_ci } else { 106962306a36Sopenharmony_ci fill: 107062306a36Sopenharmony_ci ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); 107162306a36Sopenharmony_ci ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE); 107262306a36Sopenharmony_ci ri.totlen = cpu_to_je32(sizeof(ri)); 107362306a36Sopenharmony_ci ri.hdr_crc = cpu_to_je32(crc32(0, &ri, sizeof(struct jffs2_unknown_node)-4)); 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci ri.ino = cpu_to_je32(f->inocache->ino); 107662306a36Sopenharmony_ci ri.version = cpu_to_je32(++f->highest_version); 107762306a36Sopenharmony_ci ri.offset = cpu_to_je32(start); 107862306a36Sopenharmony_ci ri.dsize = cpu_to_je32(end - start); 107962306a36Sopenharmony_ci ri.csize = cpu_to_je32(0); 108062306a36Sopenharmony_ci ri.compr = JFFS2_COMPR_ZERO; 108162306a36Sopenharmony_ci } 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci frag = frag_last(&f->fragtree); 108462306a36Sopenharmony_ci if (frag) 108562306a36Sopenharmony_ci /* Fetch the inode length from the fragtree rather then 108662306a36Sopenharmony_ci * from i_size since i_size may have not been updated yet */ 108762306a36Sopenharmony_ci ilen = frag->ofs + frag->size; 108862306a36Sopenharmony_ci else 108962306a36Sopenharmony_ci ilen = JFFS2_F_I_SIZE(f); 109062306a36Sopenharmony_ci 109162306a36Sopenharmony_ci ri.mode = cpu_to_jemode(JFFS2_F_I_MODE(f)); 109262306a36Sopenharmony_ci ri.uid = cpu_to_je16(JFFS2_F_I_UID(f)); 109362306a36Sopenharmony_ci ri.gid = cpu_to_je16(JFFS2_F_I_GID(f)); 109462306a36Sopenharmony_ci ri.isize = cpu_to_je32(ilen); 109562306a36Sopenharmony_ci ri.atime = cpu_to_je32(JFFS2_F_I_ATIME(f)); 109662306a36Sopenharmony_ci ri.ctime = cpu_to_je32(JFFS2_F_I_CTIME(f)); 109762306a36Sopenharmony_ci ri.mtime = cpu_to_je32(JFFS2_F_I_MTIME(f)); 109862306a36Sopenharmony_ci ri.data_crc = cpu_to_je32(0); 109962306a36Sopenharmony_ci ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri)-8)); 110062306a36Sopenharmony_ci 110162306a36Sopenharmony_ci ret = jffs2_reserve_space_gc(c, sizeof(ri), &alloclen, 110262306a36Sopenharmony_ci JFFS2_SUMMARY_INODE_SIZE); 110362306a36Sopenharmony_ci if (ret) { 110462306a36Sopenharmony_ci pr_warn("jffs2_reserve_space_gc of %zd bytes for garbage_collect_hole failed: %d\n", 110562306a36Sopenharmony_ci sizeof(ri), ret); 110662306a36Sopenharmony_ci return ret; 110762306a36Sopenharmony_ci } 110862306a36Sopenharmony_ci new_fn = jffs2_write_dnode(c, f, &ri, NULL, 0, ALLOC_GC); 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_ci if (IS_ERR(new_fn)) { 111162306a36Sopenharmony_ci pr_warn("Error writing new hole node: %ld\n", PTR_ERR(new_fn)); 111262306a36Sopenharmony_ci return PTR_ERR(new_fn); 111362306a36Sopenharmony_ci } 111462306a36Sopenharmony_ci if (je32_to_cpu(ri.version) == f->highest_version) { 111562306a36Sopenharmony_ci jffs2_add_full_dnode_to_inode(c, f, new_fn); 111662306a36Sopenharmony_ci if (f->metadata) { 111762306a36Sopenharmony_ci jffs2_mark_node_obsolete(c, f->metadata->raw); 111862306a36Sopenharmony_ci jffs2_free_full_dnode(f->metadata); 111962306a36Sopenharmony_ci f->metadata = NULL; 112062306a36Sopenharmony_ci } 112162306a36Sopenharmony_ci return 0; 112262306a36Sopenharmony_ci } 112362306a36Sopenharmony_ci 112462306a36Sopenharmony_ci /* 112562306a36Sopenharmony_ci * We should only get here in the case where the node we are 112662306a36Sopenharmony_ci * replacing had more than one frag, so we kept the same version 112762306a36Sopenharmony_ci * number as before. (Except in case of error -- see 'goto fill;' 112862306a36Sopenharmony_ci * above.) 112962306a36Sopenharmony_ci */ 113062306a36Sopenharmony_ci D1(if(unlikely(fn->frags <= 1)) { 113162306a36Sopenharmony_ci pr_warn("%s(): Replacing fn with %d frag(s) but new ver %d != highest_version %d of ino #%d\n", 113262306a36Sopenharmony_ci __func__, fn->frags, je32_to_cpu(ri.version), 113362306a36Sopenharmony_ci f->highest_version, je32_to_cpu(ri.ino)); 113462306a36Sopenharmony_ci }); 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_ci /* This is a partially-overlapped hole node. Mark it REF_NORMAL not REF_PRISTINE */ 113762306a36Sopenharmony_ci mark_ref_normal(new_fn->raw); 113862306a36Sopenharmony_ci 113962306a36Sopenharmony_ci for (frag = jffs2_lookup_node_frag(&f->fragtree, fn->ofs); 114062306a36Sopenharmony_ci frag; frag = frag_next(frag)) { 114162306a36Sopenharmony_ci if (frag->ofs > fn->size + fn->ofs) 114262306a36Sopenharmony_ci break; 114362306a36Sopenharmony_ci if (frag->node == fn) { 114462306a36Sopenharmony_ci frag->node = new_fn; 114562306a36Sopenharmony_ci new_fn->frags++; 114662306a36Sopenharmony_ci fn->frags--; 114762306a36Sopenharmony_ci } 114862306a36Sopenharmony_ci } 114962306a36Sopenharmony_ci if (fn->frags) { 115062306a36Sopenharmony_ci pr_warn("%s(): Old node still has frags!\n", __func__); 115162306a36Sopenharmony_ci BUG(); 115262306a36Sopenharmony_ci } 115362306a36Sopenharmony_ci if (!new_fn->frags) { 115462306a36Sopenharmony_ci pr_warn("%s(): New node has no frags!\n", __func__); 115562306a36Sopenharmony_ci BUG(); 115662306a36Sopenharmony_ci } 115762306a36Sopenharmony_ci 115862306a36Sopenharmony_ci jffs2_mark_node_obsolete(c, fn->raw); 115962306a36Sopenharmony_ci jffs2_free_full_dnode(fn); 116062306a36Sopenharmony_ci 116162306a36Sopenharmony_ci return 0; 116262306a36Sopenharmony_ci} 116362306a36Sopenharmony_ci 116462306a36Sopenharmony_cistatic int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *orig_jeb, 116562306a36Sopenharmony_ci struct jffs2_inode_info *f, struct jffs2_full_dnode *fn, 116662306a36Sopenharmony_ci uint32_t start, uint32_t end) 116762306a36Sopenharmony_ci{ 116862306a36Sopenharmony_ci struct inode *inode = OFNI_EDONI_2SFFJ(f); 116962306a36Sopenharmony_ci struct jffs2_full_dnode *new_fn; 117062306a36Sopenharmony_ci struct jffs2_raw_inode ri; 117162306a36Sopenharmony_ci uint32_t alloclen, offset, orig_end, orig_start; 117262306a36Sopenharmony_ci int ret = 0; 117362306a36Sopenharmony_ci unsigned char *comprbuf = NULL, *writebuf; 117462306a36Sopenharmony_ci struct page *page; 117562306a36Sopenharmony_ci unsigned char *pg_ptr; 117662306a36Sopenharmony_ci 117762306a36Sopenharmony_ci memset(&ri, 0, sizeof(ri)); 117862306a36Sopenharmony_ci 117962306a36Sopenharmony_ci jffs2_dbg(1, "Writing replacement dnode for ino #%u from offset 0x%x to 0x%x\n", 118062306a36Sopenharmony_ci f->inocache->ino, start, end); 118162306a36Sopenharmony_ci 118262306a36Sopenharmony_ci orig_end = end; 118362306a36Sopenharmony_ci orig_start = start; 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_ci if (c->nr_free_blocks + c->nr_erasing_blocks > c->resv_blocks_gcmerge) { 118662306a36Sopenharmony_ci /* Attempt to do some merging. But only expand to cover logically 118762306a36Sopenharmony_ci adjacent frags if the block containing them is already considered 118862306a36Sopenharmony_ci to be dirty. Otherwise we end up with GC just going round in 118962306a36Sopenharmony_ci circles dirtying the nodes it already wrote out, especially 119062306a36Sopenharmony_ci on NAND where we have small eraseblocks and hence a much higher 119162306a36Sopenharmony_ci chance of nodes having to be split to cross boundaries. */ 119262306a36Sopenharmony_ci 119362306a36Sopenharmony_ci struct jffs2_node_frag *frag; 119462306a36Sopenharmony_ci uint32_t min, max; 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_ci min = start & ~(PAGE_SIZE-1); 119762306a36Sopenharmony_ci max = min + PAGE_SIZE; 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_ci frag = jffs2_lookup_node_frag(&f->fragtree, start); 120062306a36Sopenharmony_ci 120162306a36Sopenharmony_ci /* BUG_ON(!frag) but that'll happen anyway... */ 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_ci BUG_ON(frag->ofs != start); 120462306a36Sopenharmony_ci 120562306a36Sopenharmony_ci /* First grow down... */ 120662306a36Sopenharmony_ci while((frag = frag_prev(frag)) && frag->ofs >= min) { 120762306a36Sopenharmony_ci 120862306a36Sopenharmony_ci /* If the previous frag doesn't even reach the beginning, there's 120962306a36Sopenharmony_ci excessive fragmentation. Just merge. */ 121062306a36Sopenharmony_ci if (frag->ofs > min) { 121162306a36Sopenharmony_ci jffs2_dbg(1, "Expanding down to cover partial frag (0x%x-0x%x)\n", 121262306a36Sopenharmony_ci frag->ofs, frag->ofs+frag->size); 121362306a36Sopenharmony_ci start = frag->ofs; 121462306a36Sopenharmony_ci continue; 121562306a36Sopenharmony_ci } 121662306a36Sopenharmony_ci /* OK. This frag holds the first byte of the page. */ 121762306a36Sopenharmony_ci if (!frag->node || !frag->node->raw) { 121862306a36Sopenharmony_ci jffs2_dbg(1, "First frag in page is hole (0x%x-0x%x). Not expanding down.\n", 121962306a36Sopenharmony_ci frag->ofs, frag->ofs+frag->size); 122062306a36Sopenharmony_ci break; 122162306a36Sopenharmony_ci } else { 122262306a36Sopenharmony_ci 122362306a36Sopenharmony_ci /* OK, it's a frag which extends to the beginning of the page. Does it live 122462306a36Sopenharmony_ci in a block which is still considered clean? If so, don't obsolete it. 122562306a36Sopenharmony_ci If not, cover it anyway. */ 122662306a36Sopenharmony_ci 122762306a36Sopenharmony_ci struct jffs2_raw_node_ref *raw = frag->node->raw; 122862306a36Sopenharmony_ci struct jffs2_eraseblock *jeb; 122962306a36Sopenharmony_ci 123062306a36Sopenharmony_ci jeb = &c->blocks[raw->flash_offset / c->sector_size]; 123162306a36Sopenharmony_ci 123262306a36Sopenharmony_ci if (jeb == c->gcblock) { 123362306a36Sopenharmony_ci jffs2_dbg(1, "Expanding down to cover frag (0x%x-0x%x) in gcblock at %08x\n", 123462306a36Sopenharmony_ci frag->ofs, 123562306a36Sopenharmony_ci frag->ofs + frag->size, 123662306a36Sopenharmony_ci ref_offset(raw)); 123762306a36Sopenharmony_ci start = frag->ofs; 123862306a36Sopenharmony_ci break; 123962306a36Sopenharmony_ci } 124062306a36Sopenharmony_ci if (!ISDIRTY(jeb->dirty_size + jeb->wasted_size)) { 124162306a36Sopenharmony_ci jffs2_dbg(1, "Not expanding down to cover frag (0x%x-0x%x) in clean block %08x\n", 124262306a36Sopenharmony_ci frag->ofs, 124362306a36Sopenharmony_ci frag->ofs + frag->size, 124462306a36Sopenharmony_ci jeb->offset); 124562306a36Sopenharmony_ci break; 124662306a36Sopenharmony_ci } 124762306a36Sopenharmony_ci 124862306a36Sopenharmony_ci jffs2_dbg(1, "Expanding down to cover frag (0x%x-0x%x) in dirty block %08x\n", 124962306a36Sopenharmony_ci frag->ofs, 125062306a36Sopenharmony_ci frag->ofs + frag->size, 125162306a36Sopenharmony_ci jeb->offset); 125262306a36Sopenharmony_ci start = frag->ofs; 125362306a36Sopenharmony_ci break; 125462306a36Sopenharmony_ci } 125562306a36Sopenharmony_ci } 125662306a36Sopenharmony_ci 125762306a36Sopenharmony_ci /* ... then up */ 125862306a36Sopenharmony_ci 125962306a36Sopenharmony_ci /* Find last frag which is actually part of the node we're to GC. */ 126062306a36Sopenharmony_ci frag = jffs2_lookup_node_frag(&f->fragtree, end-1); 126162306a36Sopenharmony_ci 126262306a36Sopenharmony_ci while((frag = frag_next(frag)) && frag->ofs+frag->size <= max) { 126362306a36Sopenharmony_ci 126462306a36Sopenharmony_ci /* If the previous frag doesn't even reach the beginning, there's lots 126562306a36Sopenharmony_ci of fragmentation. Just merge. */ 126662306a36Sopenharmony_ci if (frag->ofs+frag->size < max) { 126762306a36Sopenharmony_ci jffs2_dbg(1, "Expanding up to cover partial frag (0x%x-0x%x)\n", 126862306a36Sopenharmony_ci frag->ofs, frag->ofs+frag->size); 126962306a36Sopenharmony_ci end = frag->ofs + frag->size; 127062306a36Sopenharmony_ci continue; 127162306a36Sopenharmony_ci } 127262306a36Sopenharmony_ci 127362306a36Sopenharmony_ci if (!frag->node || !frag->node->raw) { 127462306a36Sopenharmony_ci jffs2_dbg(1, "Last frag in page is hole (0x%x-0x%x). Not expanding up.\n", 127562306a36Sopenharmony_ci frag->ofs, frag->ofs+frag->size); 127662306a36Sopenharmony_ci break; 127762306a36Sopenharmony_ci } else { 127862306a36Sopenharmony_ci 127962306a36Sopenharmony_ci /* OK, it's a frag which extends to the beginning of the page. Does it live 128062306a36Sopenharmony_ci in a block which is still considered clean? If so, don't obsolete it. 128162306a36Sopenharmony_ci If not, cover it anyway. */ 128262306a36Sopenharmony_ci 128362306a36Sopenharmony_ci struct jffs2_raw_node_ref *raw = frag->node->raw; 128462306a36Sopenharmony_ci struct jffs2_eraseblock *jeb; 128562306a36Sopenharmony_ci 128662306a36Sopenharmony_ci jeb = &c->blocks[raw->flash_offset / c->sector_size]; 128762306a36Sopenharmony_ci 128862306a36Sopenharmony_ci if (jeb == c->gcblock) { 128962306a36Sopenharmony_ci jffs2_dbg(1, "Expanding up to cover frag (0x%x-0x%x) in gcblock at %08x\n", 129062306a36Sopenharmony_ci frag->ofs, 129162306a36Sopenharmony_ci frag->ofs + frag->size, 129262306a36Sopenharmony_ci ref_offset(raw)); 129362306a36Sopenharmony_ci end = frag->ofs + frag->size; 129462306a36Sopenharmony_ci break; 129562306a36Sopenharmony_ci } 129662306a36Sopenharmony_ci if (!ISDIRTY(jeb->dirty_size + jeb->wasted_size)) { 129762306a36Sopenharmony_ci jffs2_dbg(1, "Not expanding up to cover frag (0x%x-0x%x) in clean block %08x\n", 129862306a36Sopenharmony_ci frag->ofs, 129962306a36Sopenharmony_ci frag->ofs + frag->size, 130062306a36Sopenharmony_ci jeb->offset); 130162306a36Sopenharmony_ci break; 130262306a36Sopenharmony_ci } 130362306a36Sopenharmony_ci 130462306a36Sopenharmony_ci jffs2_dbg(1, "Expanding up to cover frag (0x%x-0x%x) in dirty block %08x\n", 130562306a36Sopenharmony_ci frag->ofs, 130662306a36Sopenharmony_ci frag->ofs + frag->size, 130762306a36Sopenharmony_ci jeb->offset); 130862306a36Sopenharmony_ci end = frag->ofs + frag->size; 130962306a36Sopenharmony_ci break; 131062306a36Sopenharmony_ci } 131162306a36Sopenharmony_ci } 131262306a36Sopenharmony_ci jffs2_dbg(1, "Expanded dnode to write from (0x%x-0x%x) to (0x%x-0x%x)\n", 131362306a36Sopenharmony_ci orig_start, orig_end, start, end); 131462306a36Sopenharmony_ci 131562306a36Sopenharmony_ci D1(BUG_ON(end > frag_last(&f->fragtree)->ofs + frag_last(&f->fragtree)->size)); 131662306a36Sopenharmony_ci BUG_ON(end < orig_end); 131762306a36Sopenharmony_ci BUG_ON(start > orig_start); 131862306a36Sopenharmony_ci } 131962306a36Sopenharmony_ci 132062306a36Sopenharmony_ci /* The rules state that we must obtain the page lock *before* f->sem, so 132162306a36Sopenharmony_ci * drop f->sem temporarily. Since we also hold c->alloc_sem, nothing's 132262306a36Sopenharmony_ci * actually going to *change* so we're safe; we only allow reading. 132362306a36Sopenharmony_ci * 132462306a36Sopenharmony_ci * It is important to note that jffs2_write_begin() will ensure that its 132562306a36Sopenharmony_ci * page is marked Uptodate before allocating space. That means that if we 132662306a36Sopenharmony_ci * end up here trying to GC the *same* page that jffs2_write_begin() is 132762306a36Sopenharmony_ci * trying to write out, read_cache_page() will not deadlock. */ 132862306a36Sopenharmony_ci mutex_unlock(&f->sem); 132962306a36Sopenharmony_ci page = read_cache_page(inode->i_mapping, start >> PAGE_SHIFT, 133062306a36Sopenharmony_ci __jffs2_read_folio, NULL); 133162306a36Sopenharmony_ci if (IS_ERR(page)) { 133262306a36Sopenharmony_ci pr_warn("read_cache_page() returned error: %ld\n", 133362306a36Sopenharmony_ci PTR_ERR(page)); 133462306a36Sopenharmony_ci mutex_lock(&f->sem); 133562306a36Sopenharmony_ci return PTR_ERR(page); 133662306a36Sopenharmony_ci } 133762306a36Sopenharmony_ci 133862306a36Sopenharmony_ci pg_ptr = kmap(page); 133962306a36Sopenharmony_ci mutex_lock(&f->sem); 134062306a36Sopenharmony_ci 134162306a36Sopenharmony_ci offset = start; 134262306a36Sopenharmony_ci while(offset < orig_end) { 134362306a36Sopenharmony_ci uint32_t datalen; 134462306a36Sopenharmony_ci uint32_t cdatalen; 134562306a36Sopenharmony_ci uint16_t comprtype = JFFS2_COMPR_NONE; 134662306a36Sopenharmony_ci 134762306a36Sopenharmony_ci ret = jffs2_reserve_space_gc(c, sizeof(ri) + JFFS2_MIN_DATA_LEN, 134862306a36Sopenharmony_ci &alloclen, JFFS2_SUMMARY_INODE_SIZE); 134962306a36Sopenharmony_ci 135062306a36Sopenharmony_ci if (ret) { 135162306a36Sopenharmony_ci pr_warn("jffs2_reserve_space_gc of %zd bytes for garbage_collect_dnode failed: %d\n", 135262306a36Sopenharmony_ci sizeof(ri) + JFFS2_MIN_DATA_LEN, ret); 135362306a36Sopenharmony_ci break; 135462306a36Sopenharmony_ci } 135562306a36Sopenharmony_ci cdatalen = min_t(uint32_t, alloclen - sizeof(ri), end - offset); 135662306a36Sopenharmony_ci datalen = end - offset; 135762306a36Sopenharmony_ci 135862306a36Sopenharmony_ci writebuf = pg_ptr + (offset & (PAGE_SIZE -1)); 135962306a36Sopenharmony_ci 136062306a36Sopenharmony_ci comprtype = jffs2_compress(c, f, writebuf, &comprbuf, &datalen, &cdatalen); 136162306a36Sopenharmony_ci 136262306a36Sopenharmony_ci ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); 136362306a36Sopenharmony_ci ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE); 136462306a36Sopenharmony_ci ri.totlen = cpu_to_je32(sizeof(ri) + cdatalen); 136562306a36Sopenharmony_ci ri.hdr_crc = cpu_to_je32(crc32(0, &ri, sizeof(struct jffs2_unknown_node)-4)); 136662306a36Sopenharmony_ci 136762306a36Sopenharmony_ci ri.ino = cpu_to_je32(f->inocache->ino); 136862306a36Sopenharmony_ci ri.version = cpu_to_je32(++f->highest_version); 136962306a36Sopenharmony_ci ri.mode = cpu_to_jemode(JFFS2_F_I_MODE(f)); 137062306a36Sopenharmony_ci ri.uid = cpu_to_je16(JFFS2_F_I_UID(f)); 137162306a36Sopenharmony_ci ri.gid = cpu_to_je16(JFFS2_F_I_GID(f)); 137262306a36Sopenharmony_ci ri.isize = cpu_to_je32(JFFS2_F_I_SIZE(f)); 137362306a36Sopenharmony_ci ri.atime = cpu_to_je32(JFFS2_F_I_ATIME(f)); 137462306a36Sopenharmony_ci ri.ctime = cpu_to_je32(JFFS2_F_I_CTIME(f)); 137562306a36Sopenharmony_ci ri.mtime = cpu_to_je32(JFFS2_F_I_MTIME(f)); 137662306a36Sopenharmony_ci ri.offset = cpu_to_je32(offset); 137762306a36Sopenharmony_ci ri.csize = cpu_to_je32(cdatalen); 137862306a36Sopenharmony_ci ri.dsize = cpu_to_je32(datalen); 137962306a36Sopenharmony_ci ri.compr = comprtype & 0xff; 138062306a36Sopenharmony_ci ri.usercompr = (comprtype >> 8) & 0xff; 138162306a36Sopenharmony_ci ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri)-8)); 138262306a36Sopenharmony_ci ri.data_crc = cpu_to_je32(crc32(0, comprbuf, cdatalen)); 138362306a36Sopenharmony_ci 138462306a36Sopenharmony_ci new_fn = jffs2_write_dnode(c, f, &ri, comprbuf, cdatalen, ALLOC_GC); 138562306a36Sopenharmony_ci 138662306a36Sopenharmony_ci jffs2_free_comprbuf(comprbuf, writebuf); 138762306a36Sopenharmony_ci 138862306a36Sopenharmony_ci if (IS_ERR(new_fn)) { 138962306a36Sopenharmony_ci pr_warn("Error writing new dnode: %ld\n", 139062306a36Sopenharmony_ci PTR_ERR(new_fn)); 139162306a36Sopenharmony_ci ret = PTR_ERR(new_fn); 139262306a36Sopenharmony_ci break; 139362306a36Sopenharmony_ci } 139462306a36Sopenharmony_ci ret = jffs2_add_full_dnode_to_inode(c, f, new_fn); 139562306a36Sopenharmony_ci offset += datalen; 139662306a36Sopenharmony_ci if (f->metadata) { 139762306a36Sopenharmony_ci jffs2_mark_node_obsolete(c, f->metadata->raw); 139862306a36Sopenharmony_ci jffs2_free_full_dnode(f->metadata); 139962306a36Sopenharmony_ci f->metadata = NULL; 140062306a36Sopenharmony_ci } 140162306a36Sopenharmony_ci } 140262306a36Sopenharmony_ci 140362306a36Sopenharmony_ci kunmap(page); 140462306a36Sopenharmony_ci put_page(page); 140562306a36Sopenharmony_ci return ret; 140662306a36Sopenharmony_ci} 1407