18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * JFFS2 -- Journalling Flash File System, Version 2.
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Copyright © 2001-2007 Red Hat, Inc.
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Created by David Woodhouse <dwmw2@infradead.org>
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * For licensing information, see the file 'LICENCE' in this directory.
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci */
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#include <linux/kernel.h>
158c2ecf20Sopenharmony_ci#include <linux/sched.h>
168c2ecf20Sopenharmony_ci#include <linux/fs.h>
178c2ecf20Sopenharmony_ci#include <linux/mtd/mtd.h>
188c2ecf20Sopenharmony_ci#include <linux/rbtree.h>
198c2ecf20Sopenharmony_ci#include <linux/crc32.h>
208c2ecf20Sopenharmony_ci#include <linux/pagemap.h>
218c2ecf20Sopenharmony_ci#include "nodelist.h"
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_cistatic void jffs2_obsolete_node_frag(struct jffs2_sb_info *c,
248c2ecf20Sopenharmony_ci				     struct jffs2_node_frag *this);
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_civoid jffs2_add_fd_to_list(struct jffs2_sb_info *c, struct jffs2_full_dirent *new, struct jffs2_full_dirent **list)
278c2ecf20Sopenharmony_ci{
288c2ecf20Sopenharmony_ci	struct jffs2_full_dirent **prev = list;
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci	dbg_dentlist("add dirent \"%s\", ino #%u\n", new->name, new->ino);
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci	while ((*prev) && (*prev)->nhash <= new->nhash) {
338c2ecf20Sopenharmony_ci		if ((*prev)->nhash == new->nhash && !strcmp((*prev)->name, new->name)) {
348c2ecf20Sopenharmony_ci			/* Duplicate. Free one */
358c2ecf20Sopenharmony_ci			if (new->version < (*prev)->version) {
368c2ecf20Sopenharmony_ci				dbg_dentlist("Eep! Marking new dirent node obsolete, old is \"%s\", ino #%u\n",
378c2ecf20Sopenharmony_ci					(*prev)->name, (*prev)->ino);
388c2ecf20Sopenharmony_ci				jffs2_mark_node_obsolete(c, new->raw);
398c2ecf20Sopenharmony_ci				jffs2_free_full_dirent(new);
408c2ecf20Sopenharmony_ci			} else {
418c2ecf20Sopenharmony_ci				dbg_dentlist("marking old dirent \"%s\", ino #%u obsolete\n",
428c2ecf20Sopenharmony_ci					(*prev)->name, (*prev)->ino);
438c2ecf20Sopenharmony_ci				new->next = (*prev)->next;
448c2ecf20Sopenharmony_ci				/* It may have been a 'placeholder' deletion dirent,
458c2ecf20Sopenharmony_ci				   if jffs2_can_mark_obsolete() (see jffs2_do_unlink()) */
468c2ecf20Sopenharmony_ci				if ((*prev)->raw)
478c2ecf20Sopenharmony_ci					jffs2_mark_node_obsolete(c, ((*prev)->raw));
488c2ecf20Sopenharmony_ci				jffs2_free_full_dirent(*prev);
498c2ecf20Sopenharmony_ci				*prev = new;
508c2ecf20Sopenharmony_ci			}
518c2ecf20Sopenharmony_ci			return;
528c2ecf20Sopenharmony_ci		}
538c2ecf20Sopenharmony_ci		prev = &((*prev)->next);
548c2ecf20Sopenharmony_ci	}
558c2ecf20Sopenharmony_ci	new->next = *prev;
568c2ecf20Sopenharmony_ci	*prev = new;
578c2ecf20Sopenharmony_ci}
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ciuint32_t jffs2_truncate_fragtree(struct jffs2_sb_info *c, struct rb_root *list, uint32_t size)
608c2ecf20Sopenharmony_ci{
618c2ecf20Sopenharmony_ci	struct jffs2_node_frag *frag = jffs2_lookup_node_frag(list, size);
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	dbg_fragtree("truncating fragtree to 0x%08x bytes\n", size);
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	/* We know frag->ofs <= size. That's what lookup does for us */
668c2ecf20Sopenharmony_ci	if (frag && frag->ofs != size) {
678c2ecf20Sopenharmony_ci		if (frag->ofs+frag->size > size) {
688c2ecf20Sopenharmony_ci			frag->size = size - frag->ofs;
698c2ecf20Sopenharmony_ci		}
708c2ecf20Sopenharmony_ci		frag = frag_next(frag);
718c2ecf20Sopenharmony_ci	}
728c2ecf20Sopenharmony_ci	while (frag && frag->ofs >= size) {
738c2ecf20Sopenharmony_ci		struct jffs2_node_frag *next = frag_next(frag);
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci		frag_erase(frag, list);
768c2ecf20Sopenharmony_ci		jffs2_obsolete_node_frag(c, frag);
778c2ecf20Sopenharmony_ci		frag = next;
788c2ecf20Sopenharmony_ci	}
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci	if (size == 0)
818c2ecf20Sopenharmony_ci		return 0;
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	frag = frag_last(list);
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	/* Sanity check for truncation to longer than we started with... */
868c2ecf20Sopenharmony_ci	if (!frag)
878c2ecf20Sopenharmony_ci		return 0;
888c2ecf20Sopenharmony_ci	if (frag->ofs + frag->size < size)
898c2ecf20Sopenharmony_ci		return frag->ofs + frag->size;
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	/* If the last fragment starts at the RAM page boundary, it is
928c2ecf20Sopenharmony_ci	 * REF_PRISTINE irrespective of its size. */
938c2ecf20Sopenharmony_ci	if (frag->node && (frag->ofs & (PAGE_SIZE - 1)) == 0) {
948c2ecf20Sopenharmony_ci		dbg_fragtree2("marking the last fragment 0x%08x-0x%08x REF_PRISTINE.\n",
958c2ecf20Sopenharmony_ci			frag->ofs, frag->ofs + frag->size);
968c2ecf20Sopenharmony_ci		frag->node->raw->flash_offset = ref_offset(frag->node->raw) | REF_PRISTINE;
978c2ecf20Sopenharmony_ci	}
988c2ecf20Sopenharmony_ci	return size;
998c2ecf20Sopenharmony_ci}
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_cistatic void jffs2_obsolete_node_frag(struct jffs2_sb_info *c,
1028c2ecf20Sopenharmony_ci				     struct jffs2_node_frag *this)
1038c2ecf20Sopenharmony_ci{
1048c2ecf20Sopenharmony_ci	if (this->node) {
1058c2ecf20Sopenharmony_ci		this->node->frags--;
1068c2ecf20Sopenharmony_ci		if (!this->node->frags) {
1078c2ecf20Sopenharmony_ci			/* The node has no valid frags left. It's totally obsoleted */
1088c2ecf20Sopenharmony_ci			dbg_fragtree2("marking old node @0x%08x (0x%04x-0x%04x) obsolete\n",
1098c2ecf20Sopenharmony_ci				ref_offset(this->node->raw), this->node->ofs, this->node->ofs+this->node->size);
1108c2ecf20Sopenharmony_ci			jffs2_mark_node_obsolete(c, this->node->raw);
1118c2ecf20Sopenharmony_ci			jffs2_free_full_dnode(this->node);
1128c2ecf20Sopenharmony_ci		} else {
1138c2ecf20Sopenharmony_ci			dbg_fragtree2("marking old node @0x%08x (0x%04x-0x%04x) REF_NORMAL. frags is %d\n",
1148c2ecf20Sopenharmony_ci				ref_offset(this->node->raw), this->node->ofs, this->node->ofs+this->node->size, this->node->frags);
1158c2ecf20Sopenharmony_ci			mark_ref_normal(this->node->raw);
1168c2ecf20Sopenharmony_ci		}
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	}
1198c2ecf20Sopenharmony_ci	jffs2_free_node_frag(this);
1208c2ecf20Sopenharmony_ci}
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_cistatic void jffs2_fragtree_insert(struct jffs2_node_frag *newfrag, struct jffs2_node_frag *base)
1238c2ecf20Sopenharmony_ci{
1248c2ecf20Sopenharmony_ci	struct rb_node *parent = &base->rb;
1258c2ecf20Sopenharmony_ci	struct rb_node **link = &parent;
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	dbg_fragtree2("insert frag (0x%04x-0x%04x)\n", newfrag->ofs, newfrag->ofs + newfrag->size);
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	while (*link) {
1308c2ecf20Sopenharmony_ci		parent = *link;
1318c2ecf20Sopenharmony_ci		base = rb_entry(parent, struct jffs2_node_frag, rb);
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci		if (newfrag->ofs > base->ofs)
1348c2ecf20Sopenharmony_ci			link = &base->rb.rb_right;
1358c2ecf20Sopenharmony_ci		else if (newfrag->ofs < base->ofs)
1368c2ecf20Sopenharmony_ci			link = &base->rb.rb_left;
1378c2ecf20Sopenharmony_ci		else {
1388c2ecf20Sopenharmony_ci			JFFS2_ERROR("duplicate frag at %08x (%p,%p)\n", newfrag->ofs, newfrag, base);
1398c2ecf20Sopenharmony_ci			BUG();
1408c2ecf20Sopenharmony_ci		}
1418c2ecf20Sopenharmony_ci	}
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	rb_link_node(&newfrag->rb, &base->rb, link);
1448c2ecf20Sopenharmony_ci}
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci/*
1478c2ecf20Sopenharmony_ci * Allocate and initializes a new fragment.
1488c2ecf20Sopenharmony_ci */
1498c2ecf20Sopenharmony_cistatic struct jffs2_node_frag * new_fragment(struct jffs2_full_dnode *fn, uint32_t ofs, uint32_t size)
1508c2ecf20Sopenharmony_ci{
1518c2ecf20Sopenharmony_ci	struct jffs2_node_frag *newfrag;
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	newfrag = jffs2_alloc_node_frag();
1548c2ecf20Sopenharmony_ci	if (likely(newfrag)) {
1558c2ecf20Sopenharmony_ci		newfrag->ofs = ofs;
1568c2ecf20Sopenharmony_ci		newfrag->size = size;
1578c2ecf20Sopenharmony_ci		newfrag->node = fn;
1588c2ecf20Sopenharmony_ci	} else {
1598c2ecf20Sopenharmony_ci		JFFS2_ERROR("cannot allocate a jffs2_node_frag object\n");
1608c2ecf20Sopenharmony_ci	}
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	return newfrag;
1638c2ecf20Sopenharmony_ci}
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci/*
1668c2ecf20Sopenharmony_ci * Called when there is no overlapping fragment exist. Inserts a hole before the new
1678c2ecf20Sopenharmony_ci * fragment and inserts the new fragment to the fragtree.
1688c2ecf20Sopenharmony_ci */
1698c2ecf20Sopenharmony_cistatic int no_overlapping_node(struct jffs2_sb_info *c, struct rb_root *root,
1708c2ecf20Sopenharmony_ci		 	       struct jffs2_node_frag *newfrag,
1718c2ecf20Sopenharmony_ci			       struct jffs2_node_frag *this, uint32_t lastend)
1728c2ecf20Sopenharmony_ci{
1738c2ecf20Sopenharmony_ci	if (lastend < newfrag->node->ofs) {
1748c2ecf20Sopenharmony_ci		/* put a hole in before the new fragment */
1758c2ecf20Sopenharmony_ci		struct jffs2_node_frag *holefrag;
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci		holefrag= new_fragment(NULL, lastend, newfrag->node->ofs - lastend);
1788c2ecf20Sopenharmony_ci		if (unlikely(!holefrag)) {
1798c2ecf20Sopenharmony_ci			jffs2_free_node_frag(newfrag);
1808c2ecf20Sopenharmony_ci			return -ENOMEM;
1818c2ecf20Sopenharmony_ci		}
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci		if (this) {
1848c2ecf20Sopenharmony_ci			/* By definition, the 'this' node has no right-hand child,
1858c2ecf20Sopenharmony_ci			   because there are no frags with offset greater than it.
1868c2ecf20Sopenharmony_ci			   So that's where we want to put the hole */
1878c2ecf20Sopenharmony_ci			dbg_fragtree2("add hole frag %#04x-%#04x on the right of the new frag.\n",
1888c2ecf20Sopenharmony_ci				holefrag->ofs, holefrag->ofs + holefrag->size);
1898c2ecf20Sopenharmony_ci			rb_link_node(&holefrag->rb, &this->rb, &this->rb.rb_right);
1908c2ecf20Sopenharmony_ci		} else {
1918c2ecf20Sopenharmony_ci			dbg_fragtree2("Add hole frag %#04x-%#04x to the root of the tree.\n",
1928c2ecf20Sopenharmony_ci				holefrag->ofs, holefrag->ofs + holefrag->size);
1938c2ecf20Sopenharmony_ci			rb_link_node(&holefrag->rb, NULL, &root->rb_node);
1948c2ecf20Sopenharmony_ci		}
1958c2ecf20Sopenharmony_ci		rb_insert_color(&holefrag->rb, root);
1968c2ecf20Sopenharmony_ci		this = holefrag;
1978c2ecf20Sopenharmony_ci	}
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	if (this) {
2008c2ecf20Sopenharmony_ci		/* By definition, the 'this' node has no right-hand child,
2018c2ecf20Sopenharmony_ci		   because there are no frags with offset greater than it.
2028c2ecf20Sopenharmony_ci		   So that's where we want to put new fragment */
2038c2ecf20Sopenharmony_ci		dbg_fragtree2("add the new node at the right\n");
2048c2ecf20Sopenharmony_ci		rb_link_node(&newfrag->rb, &this->rb, &this->rb.rb_right);
2058c2ecf20Sopenharmony_ci	} else {
2068c2ecf20Sopenharmony_ci		dbg_fragtree2("insert the new node at the root of the tree\n");
2078c2ecf20Sopenharmony_ci		rb_link_node(&newfrag->rb, NULL, &root->rb_node);
2088c2ecf20Sopenharmony_ci	}
2098c2ecf20Sopenharmony_ci	rb_insert_color(&newfrag->rb, root);
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	return 0;
2128c2ecf20Sopenharmony_ci}
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci/* Doesn't set inode->i_size */
2158c2ecf20Sopenharmony_cistatic int jffs2_add_frag_to_fragtree(struct jffs2_sb_info *c, struct rb_root *root, struct jffs2_node_frag *newfrag)
2168c2ecf20Sopenharmony_ci{
2178c2ecf20Sopenharmony_ci	struct jffs2_node_frag *this;
2188c2ecf20Sopenharmony_ci	uint32_t lastend;
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	/* Skip all the nodes which are completed before this one starts */
2218c2ecf20Sopenharmony_ci	this = jffs2_lookup_node_frag(root, newfrag->node->ofs);
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci	if (this) {
2248c2ecf20Sopenharmony_ci		dbg_fragtree2("lookup gave frag 0x%04x-0x%04x; phys 0x%08x (*%p)\n",
2258c2ecf20Sopenharmony_ci			  this->ofs, this->ofs+this->size, this->node?(ref_offset(this->node->raw)):0xffffffff, this);
2268c2ecf20Sopenharmony_ci		lastend = this->ofs + this->size;
2278c2ecf20Sopenharmony_ci	} else {
2288c2ecf20Sopenharmony_ci		dbg_fragtree2("lookup gave no frag\n");
2298c2ecf20Sopenharmony_ci		lastend = 0;
2308c2ecf20Sopenharmony_ci	}
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	/* See if we ran off the end of the fragtree */
2338c2ecf20Sopenharmony_ci	if (lastend <= newfrag->ofs) {
2348c2ecf20Sopenharmony_ci		/* We did */
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci		/* Check if 'this' node was on the same page as the new node.
2378c2ecf20Sopenharmony_ci		   If so, both 'this' and the new node get marked REF_NORMAL so
2388c2ecf20Sopenharmony_ci		   the GC can take a look.
2398c2ecf20Sopenharmony_ci		*/
2408c2ecf20Sopenharmony_ci		if (lastend && (lastend-1) >> PAGE_SHIFT == newfrag->ofs >> PAGE_SHIFT) {
2418c2ecf20Sopenharmony_ci			if (this->node)
2428c2ecf20Sopenharmony_ci				mark_ref_normal(this->node->raw);
2438c2ecf20Sopenharmony_ci			mark_ref_normal(newfrag->node->raw);
2448c2ecf20Sopenharmony_ci		}
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci		return no_overlapping_node(c, root, newfrag, this, lastend);
2478c2ecf20Sopenharmony_ci	}
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci	if (this->node)
2508c2ecf20Sopenharmony_ci		dbg_fragtree2("dealing with frag %u-%u, phys %#08x(%d).\n",
2518c2ecf20Sopenharmony_ci		this->ofs, this->ofs + this->size,
2528c2ecf20Sopenharmony_ci		ref_offset(this->node->raw), ref_flags(this->node->raw));
2538c2ecf20Sopenharmony_ci	else
2548c2ecf20Sopenharmony_ci		dbg_fragtree2("dealing with hole frag %u-%u.\n",
2558c2ecf20Sopenharmony_ci		this->ofs, this->ofs + this->size);
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	/* OK. 'this' is pointing at the first frag that newfrag->ofs at least partially obsoletes,
2588c2ecf20Sopenharmony_ci	 * - i.e. newfrag->ofs < this->ofs+this->size && newfrag->ofs >= this->ofs
2598c2ecf20Sopenharmony_ci	 */
2608c2ecf20Sopenharmony_ci	if (newfrag->ofs > this->ofs) {
2618c2ecf20Sopenharmony_ci		/* This node isn't completely obsoleted. The start of it remains valid */
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci		/* Mark the new node and the partially covered node REF_NORMAL -- let
2648c2ecf20Sopenharmony_ci		   the GC take a look at them */
2658c2ecf20Sopenharmony_ci		mark_ref_normal(newfrag->node->raw);
2668c2ecf20Sopenharmony_ci		if (this->node)
2678c2ecf20Sopenharmony_ci			mark_ref_normal(this->node->raw);
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci		if (this->ofs + this->size > newfrag->ofs + newfrag->size) {
2708c2ecf20Sopenharmony_ci			/* The new node splits 'this' frag into two */
2718c2ecf20Sopenharmony_ci			struct jffs2_node_frag *newfrag2;
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci			if (this->node)
2748c2ecf20Sopenharmony_ci				dbg_fragtree2("split old frag 0x%04x-0x%04x, phys 0x%08x\n",
2758c2ecf20Sopenharmony_ci					this->ofs, this->ofs+this->size, ref_offset(this->node->raw));
2768c2ecf20Sopenharmony_ci			else
2778c2ecf20Sopenharmony_ci				dbg_fragtree2("split old hole frag 0x%04x-0x%04x\n",
2788c2ecf20Sopenharmony_ci					this->ofs, this->ofs+this->size);
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci			/* New second frag pointing to this's node */
2818c2ecf20Sopenharmony_ci			newfrag2 = new_fragment(this->node, newfrag->ofs + newfrag->size,
2828c2ecf20Sopenharmony_ci						this->ofs + this->size - newfrag->ofs - newfrag->size);
2838c2ecf20Sopenharmony_ci			if (unlikely(!newfrag2))
2848c2ecf20Sopenharmony_ci				return -ENOMEM;
2858c2ecf20Sopenharmony_ci			if (this->node)
2868c2ecf20Sopenharmony_ci				this->node->frags++;
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci			/* Adjust size of original 'this' */
2898c2ecf20Sopenharmony_ci			this->size = newfrag->ofs - this->ofs;
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci			/* Now, we know there's no node with offset
2928c2ecf20Sopenharmony_ci			   greater than this->ofs but smaller than
2938c2ecf20Sopenharmony_ci			   newfrag2->ofs or newfrag->ofs, for obvious
2948c2ecf20Sopenharmony_ci			   reasons. So we can do a tree insert from
2958c2ecf20Sopenharmony_ci			   'this' to insert newfrag, and a tree insert
2968c2ecf20Sopenharmony_ci			   from newfrag to insert newfrag2. */
2978c2ecf20Sopenharmony_ci			jffs2_fragtree_insert(newfrag, this);
2988c2ecf20Sopenharmony_ci			rb_insert_color(&newfrag->rb, root);
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci			jffs2_fragtree_insert(newfrag2, newfrag);
3018c2ecf20Sopenharmony_ci			rb_insert_color(&newfrag2->rb, root);
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci			return 0;
3048c2ecf20Sopenharmony_ci		}
3058c2ecf20Sopenharmony_ci		/* New node just reduces 'this' frag in size, doesn't split it */
3068c2ecf20Sopenharmony_ci		this->size = newfrag->ofs - this->ofs;
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci		/* Again, we know it lives down here in the tree */
3098c2ecf20Sopenharmony_ci		jffs2_fragtree_insert(newfrag, this);
3108c2ecf20Sopenharmony_ci		rb_insert_color(&newfrag->rb, root);
3118c2ecf20Sopenharmony_ci	} else {
3128c2ecf20Sopenharmony_ci		/* New frag starts at the same point as 'this' used to. Replace
3138c2ecf20Sopenharmony_ci		   it in the tree without doing a delete and insertion */
3148c2ecf20Sopenharmony_ci		dbg_fragtree2("inserting newfrag (*%p),%d-%d in before 'this' (*%p),%d-%d\n",
3158c2ecf20Sopenharmony_ci			  newfrag, newfrag->ofs, newfrag->ofs+newfrag->size, this, this->ofs, this->ofs+this->size);
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci		rb_replace_node(&this->rb, &newfrag->rb, root);
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci		if (newfrag->ofs + newfrag->size >= this->ofs+this->size) {
3208c2ecf20Sopenharmony_ci			dbg_fragtree2("obsoleting node frag %p (%x-%x)\n", this, this->ofs, this->ofs+this->size);
3218c2ecf20Sopenharmony_ci			jffs2_obsolete_node_frag(c, this);
3228c2ecf20Sopenharmony_ci		} else {
3238c2ecf20Sopenharmony_ci			this->ofs += newfrag->size;
3248c2ecf20Sopenharmony_ci			this->size -= newfrag->size;
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci			jffs2_fragtree_insert(this, newfrag);
3278c2ecf20Sopenharmony_ci			rb_insert_color(&this->rb, root);
3288c2ecf20Sopenharmony_ci			return 0;
3298c2ecf20Sopenharmony_ci		}
3308c2ecf20Sopenharmony_ci	}
3318c2ecf20Sopenharmony_ci	/* OK, now we have newfrag added in the correct place in the tree, but
3328c2ecf20Sopenharmony_ci	   frag_next(newfrag) may be a fragment which is overlapped by it
3338c2ecf20Sopenharmony_ci	*/
3348c2ecf20Sopenharmony_ci	while ((this = frag_next(newfrag)) && newfrag->ofs + newfrag->size >= this->ofs + this->size) {
3358c2ecf20Sopenharmony_ci		/* 'this' frag is obsoleted completely. */
3368c2ecf20Sopenharmony_ci		dbg_fragtree2("obsoleting node frag %p (%x-%x) and removing from tree\n",
3378c2ecf20Sopenharmony_ci			this, this->ofs, this->ofs+this->size);
3388c2ecf20Sopenharmony_ci		rb_erase(&this->rb, root);
3398c2ecf20Sopenharmony_ci		jffs2_obsolete_node_frag(c, this);
3408c2ecf20Sopenharmony_ci	}
3418c2ecf20Sopenharmony_ci	/* Now we're pointing at the first frag which isn't totally obsoleted by
3428c2ecf20Sopenharmony_ci	   the new frag */
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci	if (!this || newfrag->ofs + newfrag->size == this->ofs)
3458c2ecf20Sopenharmony_ci		return 0;
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci	/* Still some overlap but we don't need to move it in the tree */
3488c2ecf20Sopenharmony_ci	this->size = (this->ofs + this->size) - (newfrag->ofs + newfrag->size);
3498c2ecf20Sopenharmony_ci	this->ofs = newfrag->ofs + newfrag->size;
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	/* And mark them REF_NORMAL so the GC takes a look at them */
3528c2ecf20Sopenharmony_ci	if (this->node)
3538c2ecf20Sopenharmony_ci		mark_ref_normal(this->node->raw);
3548c2ecf20Sopenharmony_ci	mark_ref_normal(newfrag->node->raw);
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	return 0;
3578c2ecf20Sopenharmony_ci}
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci/*
3608c2ecf20Sopenharmony_ci * Given an inode, probably with existing tree of fragments, add the new node
3618c2ecf20Sopenharmony_ci * to the fragment tree.
3628c2ecf20Sopenharmony_ci */
3638c2ecf20Sopenharmony_ciint jffs2_add_full_dnode_to_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_full_dnode *fn)
3648c2ecf20Sopenharmony_ci{
3658c2ecf20Sopenharmony_ci	int ret;
3668c2ecf20Sopenharmony_ci	struct jffs2_node_frag *newfrag;
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci	if (unlikely(!fn->size))
3698c2ecf20Sopenharmony_ci		return 0;
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci	newfrag = new_fragment(fn, fn->ofs, fn->size);
3728c2ecf20Sopenharmony_ci	if (unlikely(!newfrag))
3738c2ecf20Sopenharmony_ci		return -ENOMEM;
3748c2ecf20Sopenharmony_ci	newfrag->node->frags = 1;
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci	dbg_fragtree("adding node %#04x-%#04x @0x%08x on flash, newfrag *%p\n",
3778c2ecf20Sopenharmony_ci		  fn->ofs, fn->ofs+fn->size, ref_offset(fn->raw), newfrag);
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci	ret = jffs2_add_frag_to_fragtree(c, &f->fragtree, newfrag);
3808c2ecf20Sopenharmony_ci	if (unlikely(ret))
3818c2ecf20Sopenharmony_ci		return ret;
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci	/* If we now share a page with other nodes, mark either previous
3848c2ecf20Sopenharmony_ci	   or next node REF_NORMAL, as appropriate.  */
3858c2ecf20Sopenharmony_ci	if (newfrag->ofs & (PAGE_SIZE-1)) {
3868c2ecf20Sopenharmony_ci		struct jffs2_node_frag *prev = frag_prev(newfrag);
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci		mark_ref_normal(fn->raw);
3898c2ecf20Sopenharmony_ci		/* If we don't start at zero there's _always_ a previous */
3908c2ecf20Sopenharmony_ci		if (prev->node)
3918c2ecf20Sopenharmony_ci			mark_ref_normal(prev->node->raw);
3928c2ecf20Sopenharmony_ci	}
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci	if ((newfrag->ofs+newfrag->size) & (PAGE_SIZE-1)) {
3958c2ecf20Sopenharmony_ci		struct jffs2_node_frag *next = frag_next(newfrag);
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci		if (next) {
3988c2ecf20Sopenharmony_ci			mark_ref_normal(fn->raw);
3998c2ecf20Sopenharmony_ci			if (next->node)
4008c2ecf20Sopenharmony_ci				mark_ref_normal(next->node->raw);
4018c2ecf20Sopenharmony_ci		}
4028c2ecf20Sopenharmony_ci	}
4038c2ecf20Sopenharmony_ci	jffs2_dbg_fragtree_paranoia_check_nolock(f);
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci	return 0;
4068c2ecf20Sopenharmony_ci}
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_civoid jffs2_set_inocache_state(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic, int state)
4098c2ecf20Sopenharmony_ci{
4108c2ecf20Sopenharmony_ci	spin_lock(&c->inocache_lock);
4118c2ecf20Sopenharmony_ci	ic->state = state;
4128c2ecf20Sopenharmony_ci	wake_up(&c->inocache_wq);
4138c2ecf20Sopenharmony_ci	spin_unlock(&c->inocache_lock);
4148c2ecf20Sopenharmony_ci}
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ci/* During mount, this needs no locking. During normal operation, its
4178c2ecf20Sopenharmony_ci   callers want to do other stuff while still holding the inocache_lock.
4188c2ecf20Sopenharmony_ci   Rather than introducing special case get_ino_cache functions or
4198c2ecf20Sopenharmony_ci   callbacks, we just let the caller do the locking itself. */
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_cistruct jffs2_inode_cache *jffs2_get_ino_cache(struct jffs2_sb_info *c, uint32_t ino)
4228c2ecf20Sopenharmony_ci{
4238c2ecf20Sopenharmony_ci	struct jffs2_inode_cache *ret;
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_ci	ret = c->inocache_list[ino % c->inocache_hashsize];
4268c2ecf20Sopenharmony_ci	while (ret && ret->ino < ino) {
4278c2ecf20Sopenharmony_ci		ret = ret->next;
4288c2ecf20Sopenharmony_ci	}
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_ci	if (ret && ret->ino != ino)
4318c2ecf20Sopenharmony_ci		ret = NULL;
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci	return ret;
4348c2ecf20Sopenharmony_ci}
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_civoid jffs2_add_ino_cache (struct jffs2_sb_info *c, struct jffs2_inode_cache *new)
4378c2ecf20Sopenharmony_ci{
4388c2ecf20Sopenharmony_ci	struct jffs2_inode_cache **prev;
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci	spin_lock(&c->inocache_lock);
4418c2ecf20Sopenharmony_ci	if (!new->ino)
4428c2ecf20Sopenharmony_ci		new->ino = ++c->highest_ino;
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci	dbg_inocache("add %p (ino #%u)\n", new, new->ino);
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci	prev = &c->inocache_list[new->ino % c->inocache_hashsize];
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci	while ((*prev) && (*prev)->ino < new->ino) {
4498c2ecf20Sopenharmony_ci		prev = &(*prev)->next;
4508c2ecf20Sopenharmony_ci	}
4518c2ecf20Sopenharmony_ci	new->next = *prev;
4528c2ecf20Sopenharmony_ci	*prev = new;
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ci	spin_unlock(&c->inocache_lock);
4558c2ecf20Sopenharmony_ci}
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_civoid jffs2_del_ino_cache(struct jffs2_sb_info *c, struct jffs2_inode_cache *old)
4588c2ecf20Sopenharmony_ci{
4598c2ecf20Sopenharmony_ci	struct jffs2_inode_cache **prev;
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci#ifdef CONFIG_JFFS2_FS_XATTR
4628c2ecf20Sopenharmony_ci	BUG_ON(old->xref);
4638c2ecf20Sopenharmony_ci#endif
4648c2ecf20Sopenharmony_ci	dbg_inocache("del %p (ino #%u)\n", old, old->ino);
4658c2ecf20Sopenharmony_ci	spin_lock(&c->inocache_lock);
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_ci	prev = &c->inocache_list[old->ino % c->inocache_hashsize];
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci	while ((*prev) && (*prev)->ino < old->ino) {
4708c2ecf20Sopenharmony_ci		prev = &(*prev)->next;
4718c2ecf20Sopenharmony_ci	}
4728c2ecf20Sopenharmony_ci	if ((*prev) == old) {
4738c2ecf20Sopenharmony_ci		*prev = old->next;
4748c2ecf20Sopenharmony_ci	}
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_ci	/* Free it now unless it's in READING or CLEARING state, which
4778c2ecf20Sopenharmony_ci	   are the transitions upon read_inode() and clear_inode(). The
4788c2ecf20Sopenharmony_ci	   rest of the time we know nobody else is looking at it, and
4798c2ecf20Sopenharmony_ci	   if it's held by read_inode() or clear_inode() they'll free it
4808c2ecf20Sopenharmony_ci	   for themselves. */
4818c2ecf20Sopenharmony_ci	if (old->state != INO_STATE_READING && old->state != INO_STATE_CLEARING)
4828c2ecf20Sopenharmony_ci		jffs2_free_inode_cache(old);
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci	spin_unlock(&c->inocache_lock);
4858c2ecf20Sopenharmony_ci}
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_civoid jffs2_free_ino_caches(struct jffs2_sb_info *c)
4888c2ecf20Sopenharmony_ci{
4898c2ecf20Sopenharmony_ci	int i;
4908c2ecf20Sopenharmony_ci	struct jffs2_inode_cache *this, *next;
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci	for (i=0; i < c->inocache_hashsize; i++) {
4938c2ecf20Sopenharmony_ci		this = c->inocache_list[i];
4948c2ecf20Sopenharmony_ci		while (this) {
4958c2ecf20Sopenharmony_ci			next = this->next;
4968c2ecf20Sopenharmony_ci			jffs2_xattr_free_inode(c, this);
4978c2ecf20Sopenharmony_ci			jffs2_free_inode_cache(this);
4988c2ecf20Sopenharmony_ci			this = next;
4998c2ecf20Sopenharmony_ci		}
5008c2ecf20Sopenharmony_ci		c->inocache_list[i] = NULL;
5018c2ecf20Sopenharmony_ci	}
5028c2ecf20Sopenharmony_ci}
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_civoid jffs2_free_raw_node_refs(struct jffs2_sb_info *c)
5058c2ecf20Sopenharmony_ci{
5068c2ecf20Sopenharmony_ci	int i;
5078c2ecf20Sopenharmony_ci	struct jffs2_raw_node_ref *this, *next;
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci	for (i=0; i<c->nr_blocks; i++) {
5108c2ecf20Sopenharmony_ci		this = c->blocks[i].first_node;
5118c2ecf20Sopenharmony_ci		while (this) {
5128c2ecf20Sopenharmony_ci			if (this[REFS_PER_BLOCK].flash_offset == REF_LINK_NODE)
5138c2ecf20Sopenharmony_ci				next = this[REFS_PER_BLOCK].next_in_ino;
5148c2ecf20Sopenharmony_ci			else
5158c2ecf20Sopenharmony_ci				next = NULL;
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci			jffs2_free_refblock(this);
5188c2ecf20Sopenharmony_ci			this = next;
5198c2ecf20Sopenharmony_ci		}
5208c2ecf20Sopenharmony_ci		c->blocks[i].first_node = c->blocks[i].last_node = NULL;
5218c2ecf20Sopenharmony_ci	}
5228c2ecf20Sopenharmony_ci}
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_cistruct jffs2_node_frag *jffs2_lookup_node_frag(struct rb_root *fragtree, uint32_t offset)
5258c2ecf20Sopenharmony_ci{
5268c2ecf20Sopenharmony_ci	/* The common case in lookup is that there will be a node
5278c2ecf20Sopenharmony_ci	   which precisely matches. So we go looking for that first */
5288c2ecf20Sopenharmony_ci	struct rb_node *next;
5298c2ecf20Sopenharmony_ci	struct jffs2_node_frag *prev = NULL;
5308c2ecf20Sopenharmony_ci	struct jffs2_node_frag *frag = NULL;
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_ci	dbg_fragtree2("root %p, offset %d\n", fragtree, offset);
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_ci	next = fragtree->rb_node;
5358c2ecf20Sopenharmony_ci
5368c2ecf20Sopenharmony_ci	while(next) {
5378c2ecf20Sopenharmony_ci		frag = rb_entry(next, struct jffs2_node_frag, rb);
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_ci		if (frag->ofs + frag->size <= offset) {
5408c2ecf20Sopenharmony_ci			/* Remember the closest smaller match on the way down */
5418c2ecf20Sopenharmony_ci			if (!prev || frag->ofs > prev->ofs)
5428c2ecf20Sopenharmony_ci				prev = frag;
5438c2ecf20Sopenharmony_ci			next = frag->rb.rb_right;
5448c2ecf20Sopenharmony_ci		} else if (frag->ofs > offset) {
5458c2ecf20Sopenharmony_ci			next = frag->rb.rb_left;
5468c2ecf20Sopenharmony_ci		} else {
5478c2ecf20Sopenharmony_ci			return frag;
5488c2ecf20Sopenharmony_ci		}
5498c2ecf20Sopenharmony_ci	}
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_ci	/* Exact match not found. Go back up looking at each parent,
5528c2ecf20Sopenharmony_ci	   and return the closest smaller one */
5538c2ecf20Sopenharmony_ci
5548c2ecf20Sopenharmony_ci	if (prev)
5558c2ecf20Sopenharmony_ci		dbg_fragtree2("no match. Returning frag %#04x-%#04x, closest previous\n",
5568c2ecf20Sopenharmony_ci			  prev->ofs, prev->ofs+prev->size);
5578c2ecf20Sopenharmony_ci	else
5588c2ecf20Sopenharmony_ci		dbg_fragtree2("returning NULL, empty fragtree\n");
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_ci	return prev;
5618c2ecf20Sopenharmony_ci}
5628c2ecf20Sopenharmony_ci
5638c2ecf20Sopenharmony_ci/* Pass 'c' argument to indicate that nodes should be marked obsolete as
5648c2ecf20Sopenharmony_ci   they're killed. */
5658c2ecf20Sopenharmony_civoid jffs2_kill_fragtree(struct rb_root *root, struct jffs2_sb_info *c)
5668c2ecf20Sopenharmony_ci{
5678c2ecf20Sopenharmony_ci	struct jffs2_node_frag *frag, *next;
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ci	dbg_fragtree("killing\n");
5708c2ecf20Sopenharmony_ci	rbtree_postorder_for_each_entry_safe(frag, next, root, rb) {
5718c2ecf20Sopenharmony_ci		if (frag->node && !(--frag->node->frags)) {
5728c2ecf20Sopenharmony_ci			/* Not a hole, and it's the final remaining frag
5738c2ecf20Sopenharmony_ci			   of this node. Free the node */
5748c2ecf20Sopenharmony_ci			if (c)
5758c2ecf20Sopenharmony_ci				jffs2_mark_node_obsolete(c, frag->node->raw);
5768c2ecf20Sopenharmony_ci
5778c2ecf20Sopenharmony_ci			jffs2_free_full_dnode(frag->node);
5788c2ecf20Sopenharmony_ci		}
5798c2ecf20Sopenharmony_ci
5808c2ecf20Sopenharmony_ci		jffs2_free_node_frag(frag);
5818c2ecf20Sopenharmony_ci		cond_resched();
5828c2ecf20Sopenharmony_ci	}
5838c2ecf20Sopenharmony_ci}
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_cistruct jffs2_raw_node_ref *jffs2_link_node_ref(struct jffs2_sb_info *c,
5868c2ecf20Sopenharmony_ci					       struct jffs2_eraseblock *jeb,
5878c2ecf20Sopenharmony_ci					       uint32_t ofs, uint32_t len,
5888c2ecf20Sopenharmony_ci					       struct jffs2_inode_cache *ic)
5898c2ecf20Sopenharmony_ci{
5908c2ecf20Sopenharmony_ci	struct jffs2_raw_node_ref *ref;
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ci	BUG_ON(!jeb->allocated_refs);
5938c2ecf20Sopenharmony_ci	jeb->allocated_refs--;
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_ci	ref = jeb->last_node;
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_ci	dbg_noderef("Last node at %p is (%08x,%p)\n", ref, ref->flash_offset,
5988c2ecf20Sopenharmony_ci		    ref->next_in_ino);
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_ci	while (ref->flash_offset != REF_EMPTY_NODE) {
6018c2ecf20Sopenharmony_ci		if (ref->flash_offset == REF_LINK_NODE)
6028c2ecf20Sopenharmony_ci			ref = ref->next_in_ino;
6038c2ecf20Sopenharmony_ci		else
6048c2ecf20Sopenharmony_ci			ref++;
6058c2ecf20Sopenharmony_ci	}
6068c2ecf20Sopenharmony_ci
6078c2ecf20Sopenharmony_ci	dbg_noderef("New ref is %p (%08x becomes %08x,%p) len 0x%x\n", ref,
6088c2ecf20Sopenharmony_ci		    ref->flash_offset, ofs, ref->next_in_ino, len);
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_ci	ref->flash_offset = ofs;
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_ci	if (!jeb->first_node) {
6138c2ecf20Sopenharmony_ci		jeb->first_node = ref;
6148c2ecf20Sopenharmony_ci		BUG_ON(ref_offset(ref) != jeb->offset);
6158c2ecf20Sopenharmony_ci	} else if (unlikely(ref_offset(ref) != jeb->offset + c->sector_size - jeb->free_size)) {
6168c2ecf20Sopenharmony_ci		uint32_t last_len = ref_totlen(c, jeb, jeb->last_node);
6178c2ecf20Sopenharmony_ci
6188c2ecf20Sopenharmony_ci		JFFS2_ERROR("Adding new ref %p at (0x%08x-0x%08x) not immediately after previous (0x%08x-0x%08x)\n",
6198c2ecf20Sopenharmony_ci			    ref, ref_offset(ref), ref_offset(ref)+len,
6208c2ecf20Sopenharmony_ci			    ref_offset(jeb->last_node),
6218c2ecf20Sopenharmony_ci			    ref_offset(jeb->last_node)+last_len);
6228c2ecf20Sopenharmony_ci		BUG();
6238c2ecf20Sopenharmony_ci	}
6248c2ecf20Sopenharmony_ci	jeb->last_node = ref;
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_ci	if (ic) {
6278c2ecf20Sopenharmony_ci		ref->next_in_ino = ic->nodes;
6288c2ecf20Sopenharmony_ci		ic->nodes = ref;
6298c2ecf20Sopenharmony_ci	} else {
6308c2ecf20Sopenharmony_ci		ref->next_in_ino = NULL;
6318c2ecf20Sopenharmony_ci	}
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_ci	switch(ref_flags(ref)) {
6348c2ecf20Sopenharmony_ci	case REF_UNCHECKED:
6358c2ecf20Sopenharmony_ci		c->unchecked_size += len;
6368c2ecf20Sopenharmony_ci		jeb->unchecked_size += len;
6378c2ecf20Sopenharmony_ci		break;
6388c2ecf20Sopenharmony_ci
6398c2ecf20Sopenharmony_ci	case REF_NORMAL:
6408c2ecf20Sopenharmony_ci	case REF_PRISTINE:
6418c2ecf20Sopenharmony_ci		c->used_size += len;
6428c2ecf20Sopenharmony_ci		jeb->used_size += len;
6438c2ecf20Sopenharmony_ci		break;
6448c2ecf20Sopenharmony_ci
6458c2ecf20Sopenharmony_ci	case REF_OBSOLETE:
6468c2ecf20Sopenharmony_ci		c->dirty_size += len;
6478c2ecf20Sopenharmony_ci		jeb->dirty_size += len;
6488c2ecf20Sopenharmony_ci		break;
6498c2ecf20Sopenharmony_ci	}
6508c2ecf20Sopenharmony_ci	c->free_size -= len;
6518c2ecf20Sopenharmony_ci	jeb->free_size -= len;
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_ci#ifdef TEST_TOTLEN
6548c2ecf20Sopenharmony_ci	/* Set (and test) __totlen field... for now */
6558c2ecf20Sopenharmony_ci	ref->__totlen = len;
6568c2ecf20Sopenharmony_ci	ref_totlen(c, jeb, ref);
6578c2ecf20Sopenharmony_ci#endif
6588c2ecf20Sopenharmony_ci	return ref;
6598c2ecf20Sopenharmony_ci}
6608c2ecf20Sopenharmony_ci
6618c2ecf20Sopenharmony_ci/* No locking, no reservation of 'ref'. Do not use on a live file system */
6628c2ecf20Sopenharmony_ciint jffs2_scan_dirty_space(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
6638c2ecf20Sopenharmony_ci			   uint32_t size)
6648c2ecf20Sopenharmony_ci{
6658c2ecf20Sopenharmony_ci	if (!size)
6668c2ecf20Sopenharmony_ci		return 0;
6678c2ecf20Sopenharmony_ci	if (unlikely(size > jeb->free_size)) {
6688c2ecf20Sopenharmony_ci		pr_crit("Dirty space 0x%x larger then free_size 0x%x (wasted 0x%x)\n",
6698c2ecf20Sopenharmony_ci			size, jeb->free_size, jeb->wasted_size);
6708c2ecf20Sopenharmony_ci		BUG();
6718c2ecf20Sopenharmony_ci	}
6728c2ecf20Sopenharmony_ci	/* REF_EMPTY_NODE is !obsolete, so that works OK */
6738c2ecf20Sopenharmony_ci	if (jeb->last_node && ref_obsolete(jeb->last_node)) {
6748c2ecf20Sopenharmony_ci#ifdef TEST_TOTLEN
6758c2ecf20Sopenharmony_ci		jeb->last_node->__totlen += size;
6768c2ecf20Sopenharmony_ci#endif
6778c2ecf20Sopenharmony_ci		c->dirty_size += size;
6788c2ecf20Sopenharmony_ci		c->free_size -= size;
6798c2ecf20Sopenharmony_ci		jeb->dirty_size += size;
6808c2ecf20Sopenharmony_ci		jeb->free_size -= size;
6818c2ecf20Sopenharmony_ci	} else {
6828c2ecf20Sopenharmony_ci		uint32_t ofs = jeb->offset + c->sector_size - jeb->free_size;
6838c2ecf20Sopenharmony_ci		ofs |= REF_OBSOLETE;
6848c2ecf20Sopenharmony_ci
6858c2ecf20Sopenharmony_ci		jffs2_link_node_ref(c, jeb, ofs, size, NULL);
6868c2ecf20Sopenharmony_ci	}
6878c2ecf20Sopenharmony_ci
6888c2ecf20Sopenharmony_ci	return 0;
6898c2ecf20Sopenharmony_ci}
6908c2ecf20Sopenharmony_ci
6918c2ecf20Sopenharmony_ci/* Calculate totlen from surrounding nodes or eraseblock */
6928c2ecf20Sopenharmony_cistatic inline uint32_t __ref_totlen(struct jffs2_sb_info *c,
6938c2ecf20Sopenharmony_ci				    struct jffs2_eraseblock *jeb,
6948c2ecf20Sopenharmony_ci				    struct jffs2_raw_node_ref *ref)
6958c2ecf20Sopenharmony_ci{
6968c2ecf20Sopenharmony_ci	uint32_t ref_end;
6978c2ecf20Sopenharmony_ci	struct jffs2_raw_node_ref *next_ref = ref_next(ref);
6988c2ecf20Sopenharmony_ci
6998c2ecf20Sopenharmony_ci	if (next_ref)
7008c2ecf20Sopenharmony_ci		ref_end = ref_offset(next_ref);
7018c2ecf20Sopenharmony_ci	else {
7028c2ecf20Sopenharmony_ci		if (!jeb)
7038c2ecf20Sopenharmony_ci			jeb = &c->blocks[ref->flash_offset / c->sector_size];
7048c2ecf20Sopenharmony_ci
7058c2ecf20Sopenharmony_ci		/* Last node in block. Use free_space */
7068c2ecf20Sopenharmony_ci		if (unlikely(ref != jeb->last_node)) {
7078c2ecf20Sopenharmony_ci			pr_crit("ref %p @0x%08x is not jeb->last_node (%p @0x%08x)\n",
7088c2ecf20Sopenharmony_ci				ref, ref_offset(ref), jeb->last_node,
7098c2ecf20Sopenharmony_ci				jeb->last_node ?
7108c2ecf20Sopenharmony_ci				ref_offset(jeb->last_node) : 0);
7118c2ecf20Sopenharmony_ci			BUG();
7128c2ecf20Sopenharmony_ci		}
7138c2ecf20Sopenharmony_ci		ref_end = jeb->offset + c->sector_size - jeb->free_size;
7148c2ecf20Sopenharmony_ci	}
7158c2ecf20Sopenharmony_ci	return ref_end - ref_offset(ref);
7168c2ecf20Sopenharmony_ci}
7178c2ecf20Sopenharmony_ci
7188c2ecf20Sopenharmony_ciuint32_t __jffs2_ref_totlen(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
7198c2ecf20Sopenharmony_ci			    struct jffs2_raw_node_ref *ref)
7208c2ecf20Sopenharmony_ci{
7218c2ecf20Sopenharmony_ci	uint32_t ret;
7228c2ecf20Sopenharmony_ci
7238c2ecf20Sopenharmony_ci	ret = __ref_totlen(c, jeb, ref);
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_ci#ifdef TEST_TOTLEN
7268c2ecf20Sopenharmony_ci	if (unlikely(ret != ref->__totlen)) {
7278c2ecf20Sopenharmony_ci		if (!jeb)
7288c2ecf20Sopenharmony_ci			jeb = &c->blocks[ref->flash_offset / c->sector_size];
7298c2ecf20Sopenharmony_ci
7308c2ecf20Sopenharmony_ci		pr_crit("Totlen for ref at %p (0x%08x-0x%08x) miscalculated as 0x%x instead of %x\n",
7318c2ecf20Sopenharmony_ci			ref, ref_offset(ref), ref_offset(ref) + ref->__totlen,
7328c2ecf20Sopenharmony_ci			ret, ref->__totlen);
7338c2ecf20Sopenharmony_ci		if (ref_next(ref)) {
7348c2ecf20Sopenharmony_ci			pr_crit("next %p (0x%08x-0x%08x)\n",
7358c2ecf20Sopenharmony_ci				ref_next(ref), ref_offset(ref_next(ref)),
7368c2ecf20Sopenharmony_ci				ref_offset(ref_next(ref)) + ref->__totlen);
7378c2ecf20Sopenharmony_ci		} else
7388c2ecf20Sopenharmony_ci			pr_crit("No next ref. jeb->last_node is %p\n",
7398c2ecf20Sopenharmony_ci				jeb->last_node);
7408c2ecf20Sopenharmony_ci
7418c2ecf20Sopenharmony_ci		pr_crit("jeb->wasted_size %x, dirty_size %x, used_size %x, free_size %x\n",
7428c2ecf20Sopenharmony_ci			jeb->wasted_size, jeb->dirty_size, jeb->used_size,
7438c2ecf20Sopenharmony_ci			jeb->free_size);
7448c2ecf20Sopenharmony_ci
7458c2ecf20Sopenharmony_ci#if defined(JFFS2_DBG_DUMPS) || defined(JFFS2_DBG_PARANOIA_CHECKS)
7468c2ecf20Sopenharmony_ci		__jffs2_dbg_dump_node_refs_nolock(c, jeb);
7478c2ecf20Sopenharmony_ci#endif
7488c2ecf20Sopenharmony_ci
7498c2ecf20Sopenharmony_ci		WARN_ON(1);
7508c2ecf20Sopenharmony_ci
7518c2ecf20Sopenharmony_ci		ret = ref->__totlen;
7528c2ecf20Sopenharmony_ci	}
7538c2ecf20Sopenharmony_ci#endif /* TEST_TOTLEN */
7548c2ecf20Sopenharmony_ci	return ret;
7558c2ecf20Sopenharmony_ci}
756