mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	[JFFS2] Correct handling of JFFS2_FEATURE_RWCOMPAT_COPY nodes.
We should preserve these when we come to garbage collect them, not let them get erased. Use jffs2_garbage_collect_pristine() for this, and make sure the summary code copes -- just refrain from writing a summary for any block which contains a node we don't understand. Signed-off-by: David Woodhouse <dwmw2@infradead.org>
This commit is contained in:
		
							parent
							
								
									fb9fbbcc93
								
							
						
					
					
						commit
						6171586a7a
					
				
					 4 changed files with 55 additions and 23 deletions
				
			
		| 
						 | 
				
			
			@ -256,10 +256,14 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
 | 
			
		|||
 | 
			
		||||
	if (!raw->next_in_ino) {
 | 
			
		||||
		/* Inode-less node. Clean marker, snapshot or something like that */
 | 
			
		||||
		/* FIXME: If it's something that needs to be copied, including something
 | 
			
		||||
		   we don't grok that has JFFS2_NODETYPE_RWCOMPAT_COPY, we should do so */
 | 
			
		||||
		spin_unlock(&c->erase_completion_lock);
 | 
			
		||||
		if (ref_flags(raw) == REF_PRISTINE) {
 | 
			
		||||
			/* It's an unknown node with JFFS2_FEATURE_RWCOMPAT_COPY */
 | 
			
		||||
			jffs2_garbage_collect_pristine(c, NULL, raw);
 | 
			
		||||
		} else {
 | 
			
		||||
			/* Just mark it obsolete */
 | 
			
		||||
			jffs2_mark_node_obsolete(c, raw);
 | 
			
		||||
		}
 | 
			
		||||
		up(&c->alloc_sem);
 | 
			
		||||
		goto eraseit_lock;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -533,15 +537,16 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c,
 | 
			
		|||
 | 
			
		||||
	D1(printk(KERN_DEBUG "Going to GC REF_PRISTINE node at 0x%08x\n", ref_offset(raw)));
 | 
			
		||||
 | 
			
		||||
	rawlen = ref_totlen(c, c->gcblock, raw);
 | 
			
		||||
	alloclen = rawlen = ref_totlen(c, c->gcblock, raw);
 | 
			
		||||
 | 
			
		||||
	/* Ask for a small amount of space (or the totlen if smaller) because we
 | 
			
		||||
	   don't want to force wastage of the end of a block if splitting would
 | 
			
		||||
	   work. */
 | 
			
		||||
	ret = jffs2_reserve_space_gc(c, min_t(uint32_t, sizeof(struct jffs2_raw_inode) +
 | 
			
		||||
				JFFS2_MIN_DATA_LEN, rawlen), &phys_ofs, &alloclen, rawlen);
 | 
			
		||||
				/* this is not the exact summary size of it,
 | 
			
		||||
					it is only an upper estimation */
 | 
			
		||||
	if (ic && alloclen > sizeof(struct jffs2_raw_inode) + JFFS2_MIN_DATA_LEN)
 | 
			
		||||
		alloclen = sizeof(struct jffs2_raw_inode) + JFFS2_MIN_DATA_LEN;
 | 
			
		||||
 | 
			
		||||
	ret = jffs2_reserve_space_gc(c, alloclen, &phys_ofs, &alloclen, rawlen);
 | 
			
		||||
	/* 'rawlen' is not the exact summary size; it is only an upper estimation */
 | 
			
		||||
 | 
			
		||||
	if (ret)
 | 
			
		||||
		return ret;
 | 
			
		||||
| 
						 | 
				
			
			@ -605,10 +610,13 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c,
 | 
			
		|||
		}
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		/* If it's inode-less, we don't _know_ what it is. Just copy it intact */
 | 
			
		||||
		if (ic) {
 | 
			
		||||
			printk(KERN_WARNING "Unknown node type for REF_PRISTINE node at 0x%08x: 0x%04x\n",
 | 
			
		||||
			       ref_offset(raw), je16_to_cpu(node->u.nodetype));
 | 
			
		||||
			goto bail;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	nraw = jffs2_alloc_raw_node_ref();
 | 
			
		||||
	if (!nraw) {
 | 
			
		||||
| 
						 | 
				
			
			@ -674,6 +682,7 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c,
 | 
			
		|||
	nraw->flash_offset |= REF_PRISTINE;
 | 
			
		||||
	jffs2_add_physical_node_ref(c, nraw);
 | 
			
		||||
 | 
			
		||||
	if (ic) {
 | 
			
		||||
		/* Link into per-inode list. This is safe because of the ic
 | 
			
		||||
		   state being INO_STATE_GC. Note that if we're doing this
 | 
			
		||||
		   for an inode which is in-core, the 'nraw' pointer is then
 | 
			
		||||
| 
						 | 
				
			
			@ -682,7 +691,7 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c,
 | 
			
		|||
		nraw->next_in_ino = ic->nodes;
 | 
			
		||||
		ic->nodes = nraw;
 | 
			
		||||
		spin_unlock(&c->erase_completion_lock);
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
	jffs2_mark_node_obsolete(c, raw);
 | 
			
		||||
	D1(printk(KERN_DEBUG "WHEEE! GC REF_PRISTINE node at 0x%08x succeeded\n", ref_offset(raw)));
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -97,6 +97,11 @@ struct jffs2_raw_node_ref
 | 
			
		|||
#define ref_obsolete(ref)	(((ref)->flash_offset & 3) == REF_OBSOLETE)
 | 
			
		||||
#define mark_ref_normal(ref)    do { (ref)->flash_offset = ref_offset(ref) | REF_NORMAL; } while(0)
 | 
			
		||||
 | 
			
		||||
/* NB: REF_PRISTINE for an inode-less node (ref->next_in_ino == NULL) indicates
 | 
			
		||||
   it is an unknown node of type JFFS2_NODETYPE_RWCOMPAT_COPY, so it'll get
 | 
			
		||||
   copied. If you need to do anything different to GC inode-less nodes, then
 | 
			
		||||
   you need to modify gc.c accordingly. */
 | 
			
		||||
 | 
			
		||||
/* For each inode in the filesystem, we need to keep a record of
 | 
			
		||||
   nlink, because it would be a PITA to scan the whole directory tree
 | 
			
		||||
   at read_inode() time to calculate it, and to keep sufficient information
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -851,14 +851,25 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo
 | 
			
		|||
				ofs += PAD(je32_to_cpu(node->totlen));
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			case JFFS2_FEATURE_RWCOMPAT_COPY:
 | 
			
		||||
			case JFFS2_FEATURE_RWCOMPAT_COPY: {
 | 
			
		||||
				struct jffs2_raw_node_ref *ref;
 | 
			
		||||
				D1(printk(KERN_NOTICE "Unknown but compatible feature node (0x%04x) found at offset 0x%08x\n", je16_to_cpu(node->nodetype), ofs));
 | 
			
		||||
				USED_SPACE(PAD(je32_to_cpu(node->totlen)));
 | 
			
		||||
 | 
			
		||||
				ref = jffs2_alloc_raw_node_ref();
 | 
			
		||||
				if (!ref)
 | 
			
		||||
					return -ENOMEM;
 | 
			
		||||
				ref->flash_offset = ofs | REF_PRISTINE;
 | 
			
		||||
				ref->next_in_ino = 0;
 | 
			
		||||
				jffs2_link_node_ref(c, jeb, ref, PAD(je32_to_cpu(node->totlen)));
 | 
			
		||||
 | 
			
		||||
				/* We can't summarise nodes we don't grok */
 | 
			
		||||
				jffs2_sum_disable_collecting(s);
 | 
			
		||||
				ofs += PAD(je32_to_cpu(node->totlen));
 | 
			
		||||
				break;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (jffs2_sum_active()) {
 | 
			
		||||
		if (PAD(s->sum_size + JFFS2_SUMMARY_FRAME_SIZE) > jeb->free_size) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -760,9 +760,16 @@ static int jffs2_sum_write_data(struct jffs2_sb_info *c, struct jffs2_eraseblock
 | 
			
		|||
			}
 | 
			
		||||
#endif
 | 
			
		||||
			default : {
 | 
			
		||||
				if ((je16_to_cpu(temp->u.nodetype) & JFFS2_COMPAT_MASK)
 | 
			
		||||
				    == JFFS2_FEATURE_RWCOMPAT_COPY) {
 | 
			
		||||
					dbg_summary("Writing unknown RWCOMPAT_COPY node type %x\n",
 | 
			
		||||
						    je16_to_cpu(temp->u.nodetype));
 | 
			
		||||
					jffs2_sum_disable_collecting(c->summary);
 | 
			
		||||
				} else {
 | 
			
		||||
					BUG();	/* unknown node in summary information */
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		c->summary->sum_list_head = temp->u.next;
 | 
			
		||||
		kfree(temp);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue