xref: /openbmc/linux/fs/jffs2/nodelist.c (revision dae6227f)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * JFFS2 -- Journalling Flash File System, Version 2.
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  * Copyright (C) 2001-2003 Red Hat, Inc.
51da177e4SLinus Torvalds  *
61da177e4SLinus Torvalds  * Created by David Woodhouse <dwmw2@infradead.org>
71da177e4SLinus Torvalds  *
81da177e4SLinus Torvalds  * For licensing information, see the file 'LICENCE' in this directory.
91da177e4SLinus Torvalds  *
10dae6227fSArtem B. Bityutskiy  * $Id: nodelist.c,v 1.99 2005/07/15 10:13:54 dedekind Exp $
111da177e4SLinus Torvalds  *
121da177e4SLinus Torvalds  */
131da177e4SLinus Torvalds 
141da177e4SLinus Torvalds #include <linux/kernel.h>
151da177e4SLinus Torvalds #include <linux/sched.h>
161da177e4SLinus Torvalds #include <linux/fs.h>
171da177e4SLinus Torvalds #include <linux/mtd/mtd.h>
181da177e4SLinus Torvalds #include <linux/rbtree.h>
191da177e4SLinus Torvalds #include <linux/crc32.h>
201da177e4SLinus Torvalds #include <linux/slab.h>
211da177e4SLinus Torvalds #include <linux/pagemap.h>
221da177e4SLinus Torvalds #include "nodelist.h"
231da177e4SLinus Torvalds 
241da177e4SLinus Torvalds void jffs2_add_fd_to_list(struct jffs2_sb_info *c, struct jffs2_full_dirent *new, struct jffs2_full_dirent **list)
251da177e4SLinus Torvalds {
261da177e4SLinus Torvalds 	struct jffs2_full_dirent **prev = list;
271da177e4SLinus Torvalds 	D1(printk(KERN_DEBUG "jffs2_add_fd_to_list( %p, %p (->%p))\n", new, list, *list));
281da177e4SLinus Torvalds 
291da177e4SLinus Torvalds 	while ((*prev) && (*prev)->nhash <= new->nhash) {
301da177e4SLinus Torvalds 		if ((*prev)->nhash == new->nhash && !strcmp((*prev)->name, new->name)) {
311da177e4SLinus Torvalds 			/* Duplicate. Free one */
321da177e4SLinus Torvalds 			if (new->version < (*prev)->version) {
331da177e4SLinus Torvalds 				D1(printk(KERN_DEBUG "Eep! Marking new dirent node obsolete\n"));
341da177e4SLinus Torvalds 				D1(printk(KERN_DEBUG "New dirent is \"%s\"->ino #%u. Old is \"%s\"->ino #%u\n", new->name, new->ino, (*prev)->name, (*prev)->ino));
351da177e4SLinus Torvalds 				jffs2_mark_node_obsolete(c, new->raw);
361da177e4SLinus Torvalds 				jffs2_free_full_dirent(new);
371da177e4SLinus Torvalds 			} else {
381da177e4SLinus Torvalds 				D1(printk(KERN_DEBUG "Marking old dirent node (ino #%u) obsolete\n", (*prev)->ino));
391da177e4SLinus Torvalds 				new->next = (*prev)->next;
401da177e4SLinus Torvalds 				jffs2_mark_node_obsolete(c, ((*prev)->raw));
411da177e4SLinus Torvalds 				jffs2_free_full_dirent(*prev);
421da177e4SLinus Torvalds 				*prev = new;
431da177e4SLinus Torvalds 			}
441da177e4SLinus Torvalds 			goto out;
451da177e4SLinus Torvalds 		}
461da177e4SLinus Torvalds 		prev = &((*prev)->next);
471da177e4SLinus Torvalds 	}
481da177e4SLinus Torvalds 	new->next = *prev;
491da177e4SLinus Torvalds 	*prev = new;
501da177e4SLinus Torvalds 
511da177e4SLinus Torvalds  out:
521da177e4SLinus Torvalds 	D2(while(*list) {
531da177e4SLinus Torvalds 		printk(KERN_DEBUG "Dirent \"%s\" (hash 0x%08x, ino #%u\n", (*list)->name, (*list)->nhash, (*list)->ino);
541da177e4SLinus Torvalds 		list = &(*list)->next;
551da177e4SLinus Torvalds 	});
561da177e4SLinus Torvalds }
571da177e4SLinus Torvalds 
58e4fef661SArtem B. Bityuckiy /*
59e4fef661SArtem B. Bityuckiy  * Put a new tmp_dnode_info into the temporaty RB-tree, keeping the list in
60e4fef661SArtem B. Bityuckiy  * order of increasing version.
611da177e4SLinus Torvalds  */
62e4fef661SArtem B. Bityuckiy static void jffs2_add_tn_to_tree(struct jffs2_tmp_dnode_info *tn, struct rb_root *list)
631da177e4SLinus Torvalds {
649dee7503SDavid Woodhouse 	struct rb_node **p = &list->rb_node;
659dee7503SDavid Woodhouse 	struct rb_node * parent = NULL;
669dee7503SDavid Woodhouse 	struct jffs2_tmp_dnode_info *this;
671da177e4SLinus Torvalds 
689dee7503SDavid Woodhouse 	while (*p) {
699dee7503SDavid Woodhouse 		parent = *p;
709dee7503SDavid Woodhouse 		this = rb_entry(parent, struct jffs2_tmp_dnode_info, rb);
719dee7503SDavid Woodhouse 
726430a8deSArtem B. Bityuckiy 		/* There may actually be a collision here, but it doesn't
736430a8deSArtem B. Bityuckiy 		   actually matter. As long as the two nodes with the same
746430a8deSArtem B. Bityuckiy 		   version are together, it's all fine. */
759dee7503SDavid Woodhouse 		if (tn->version < this->version)
769dee7503SDavid Woodhouse 			p = &(*p)->rb_left;
779dee7503SDavid Woodhouse 		else
789dee7503SDavid Woodhouse 			p = &(*p)->rb_right;
791da177e4SLinus Torvalds         }
801da177e4SLinus Torvalds 
819dee7503SDavid Woodhouse 	rb_link_node(&tn->rb, parent, p);
829dee7503SDavid Woodhouse 	rb_insert_color(&tn->rb, list);
839dee7503SDavid Woodhouse }
849dee7503SDavid Woodhouse 
859dee7503SDavid Woodhouse static void jffs2_free_tmp_dnode_info_list(struct rb_root *list)
861da177e4SLinus Torvalds {
879dee7503SDavid Woodhouse 	struct rb_node *this;
889dee7503SDavid Woodhouse 	struct jffs2_tmp_dnode_info *tn;
891da177e4SLinus Torvalds 
909dee7503SDavid Woodhouse 	this = list->rb_node;
919dee7503SDavid Woodhouse 
929dee7503SDavid Woodhouse 	/* Now at bottom of tree */
939dee7503SDavid Woodhouse 	while (this) {
949dee7503SDavid Woodhouse 		if (this->rb_left)
959dee7503SDavid Woodhouse 			this = this->rb_left;
969dee7503SDavid Woodhouse 		else if (this->rb_right)
979dee7503SDavid Woodhouse 			this = this->rb_right;
989dee7503SDavid Woodhouse 		else {
999dee7503SDavid Woodhouse 			tn = rb_entry(this, struct jffs2_tmp_dnode_info, rb);
1009dee7503SDavid Woodhouse 			jffs2_free_full_dnode(tn->fn);
1019dee7503SDavid Woodhouse 			jffs2_free_tmp_dnode_info(tn);
1029dee7503SDavid Woodhouse 
1039dee7503SDavid Woodhouse 			this = this->rb_parent;
1049dee7503SDavid Woodhouse 			if (!this)
1059dee7503SDavid Woodhouse 				break;
1069dee7503SDavid Woodhouse 
1079dee7503SDavid Woodhouse 			if (this->rb_left == &tn->rb)
1089dee7503SDavid Woodhouse 				this->rb_left = NULL;
1099dee7503SDavid Woodhouse 			else if (this->rb_right == &tn->rb)
1109dee7503SDavid Woodhouse 				this->rb_right = NULL;
1119dee7503SDavid Woodhouse 			else BUG();
1121da177e4SLinus Torvalds 		}
1131da177e4SLinus Torvalds 	}
1149dee7503SDavid Woodhouse 	list->rb_node = NULL;
1159dee7503SDavid Woodhouse }
1161da177e4SLinus Torvalds 
1171da177e4SLinus Torvalds static void jffs2_free_full_dirent_list(struct jffs2_full_dirent *fd)
1181da177e4SLinus Torvalds {
1191da177e4SLinus Torvalds 	struct jffs2_full_dirent *next;
1201da177e4SLinus Torvalds 
1211da177e4SLinus Torvalds 	while (fd) {
1221da177e4SLinus Torvalds 		next = fd->next;
1231da177e4SLinus Torvalds 		jffs2_free_full_dirent(fd);
1241da177e4SLinus Torvalds 		fd = next;
1251da177e4SLinus Torvalds 	}
1261da177e4SLinus Torvalds }
1271da177e4SLinus Torvalds 
1281da177e4SLinus Torvalds /* Returns first valid node after 'ref'. May return 'ref' */
1291da177e4SLinus Torvalds static struct jffs2_raw_node_ref *jffs2_first_valid_node(struct jffs2_raw_node_ref *ref)
1301da177e4SLinus Torvalds {
1311da177e4SLinus Torvalds 	while (ref && ref->next_in_ino) {
1321da177e4SLinus Torvalds 		if (!ref_obsolete(ref))
1331da177e4SLinus Torvalds 			return ref;
1341da177e4SLinus Torvalds 		D1(printk(KERN_DEBUG "node at 0x%08x is obsoleted. Ignoring.\n", ref_offset(ref)));
1351da177e4SLinus Torvalds 		ref = ref->next_in_ino;
1361da177e4SLinus Torvalds 	}
1371da177e4SLinus Torvalds 	return NULL;
1381da177e4SLinus Torvalds }
1391da177e4SLinus Torvalds 
140dae6227fSArtem B. Bityutskiy /*
141dae6227fSArtem B. Bityutskiy  * Helper function for jffs2_get_inode_nodes().
142dae6227fSArtem B. Bityutskiy  * It is called every time an directory entry node is found.
143dae6227fSArtem B. Bityutskiy  *
144dae6227fSArtem B. Bityutskiy  * Returns: 0 on succes;
145dae6227fSArtem B. Bityutskiy  * 	    1 if the node should be marked obsolete;
146dae6227fSArtem B. Bityutskiy  * 	    negative error code on failure.
147dae6227fSArtem B. Bityutskiy  */
148dae6227fSArtem B. Bityutskiy static inline int
149dae6227fSArtem B. Bityutskiy read_direntry(struct jffs2_sb_info *c,
150dae6227fSArtem B. Bityutskiy 	      struct jffs2_raw_node_ref *ref,
151dae6227fSArtem B. Bityutskiy 	      struct jffs2_raw_dirent *rd,
152dae6227fSArtem B. Bityutskiy 	      uint32_t read,
153dae6227fSArtem B. Bityutskiy 	      struct jffs2_full_dirent **fdp,
154dae6227fSArtem B. Bityutskiy 	      int32_t *latest_mctime,
155dae6227fSArtem B. Bityutskiy 	      uint32_t *mctime_ver)
156dae6227fSArtem B. Bityutskiy {
157dae6227fSArtem B. Bityutskiy 	struct jffs2_full_dirent *fd;
158dae6227fSArtem B. Bityutskiy 
159dae6227fSArtem B. Bityutskiy 	/* The direntry nodes are checked during the flash scanning */
160dae6227fSArtem B. Bityutskiy 	BUG_ON(ref_flags(ref) == REF_UNCHECKED);
161dae6227fSArtem B. Bityutskiy 	/* Obsoleted. This cannot happen, surely? dwmw2 20020308 */
162dae6227fSArtem B. Bityutskiy 	BUG_ON(ref_obsolete(ref));
163dae6227fSArtem B. Bityutskiy 
164dae6227fSArtem B. Bityutskiy 	/* Sanity check */
165dae6227fSArtem B. Bityutskiy 	if (unlikely(PAD((rd->nsize + sizeof(*rd))) != PAD(je32_to_cpu(rd->totlen)))) {
166dae6227fSArtem B. Bityutskiy 		printk(KERN_ERR "Error! Illegal nsize in node at %#08x: nsize %#02x, totlen %#04x\n",
167dae6227fSArtem B. Bityutskiy 		       ref_offset(ref), rd->nsize, je32_to_cpu(rd->totlen));
168dae6227fSArtem B. Bityutskiy 		return 1;
169dae6227fSArtem B. Bityutskiy 	}
170dae6227fSArtem B. Bityutskiy 
171dae6227fSArtem B. Bityutskiy 	fd = jffs2_alloc_full_dirent(rd->nsize + 1);
172dae6227fSArtem B. Bityutskiy 	if (unlikely(!fd))
173dae6227fSArtem B. Bityutskiy 		return -ENOMEM;
174dae6227fSArtem B. Bityutskiy 
175dae6227fSArtem B. Bityutskiy 	fd->raw = ref;
176dae6227fSArtem B. Bityutskiy 	fd->version = je32_to_cpu(rd->version);
177dae6227fSArtem B. Bityutskiy 	fd->ino = je32_to_cpu(rd->ino);
178dae6227fSArtem B. Bityutskiy 	fd->type = rd->type;
179dae6227fSArtem B. Bityutskiy 
180dae6227fSArtem B. Bityutskiy 	/* Pick out the mctime of the latest dirent */
181dae6227fSArtem B. Bityutskiy 	if(fd->version > *mctime_ver) {
182dae6227fSArtem B. Bityutskiy 		*mctime_ver = fd->version;
183dae6227fSArtem B. Bityutskiy 		*latest_mctime = je32_to_cpu(rd->mctime);
184dae6227fSArtem B. Bityutskiy 	}
185dae6227fSArtem B. Bityutskiy 
186dae6227fSArtem B. Bityutskiy 	/*
187dae6227fSArtem B. Bityutskiy 	 * Copy as much of the name as possible from the raw
188dae6227fSArtem B. Bityutskiy 	 * dirent we've already read from the flash.
189dae6227fSArtem B. Bityutskiy 	 */
190dae6227fSArtem B. Bityutskiy 	if (read > sizeof(*rd))
191dae6227fSArtem B. Bityutskiy 		memcpy(&fd->name[0], &rd->name[0],
192dae6227fSArtem B. Bityutskiy 		       min_t(uint32_t, rd->nsize, (read - sizeof(*rd)) ));
193dae6227fSArtem B. Bityutskiy 
194dae6227fSArtem B. Bityutskiy 	/* Do we need to copy any more of the name directly from the flash? */
195dae6227fSArtem B. Bityutskiy 	if (rd->nsize + sizeof(*rd) > read) {
196dae6227fSArtem B. Bityutskiy 		/* FIXME: point() */
197dae6227fSArtem B. Bityutskiy 		int err;
198dae6227fSArtem B. Bityutskiy 		int already = read - sizeof(*rd);
199dae6227fSArtem B. Bityutskiy 
200dae6227fSArtem B. Bityutskiy 		err = jffs2_flash_read(c, (ref_offset(ref)) + read,
201dae6227fSArtem B. Bityutskiy 				rd->nsize - already, &read, &fd->name[already]);
202dae6227fSArtem B. Bityutskiy 		if (unlikely(read != rd->nsize - already) && likely(!err))
203dae6227fSArtem B. Bityutskiy 			return -EIO;
204dae6227fSArtem B. Bityutskiy 
205dae6227fSArtem B. Bityutskiy 		if (unlikely(err)) {
206dae6227fSArtem B. Bityutskiy 			printk(KERN_WARNING "Read remainder of name in jffs2_get_inode_nodes(): error %d\n", err);
207dae6227fSArtem B. Bityutskiy 			jffs2_free_full_dirent(fd);
208dae6227fSArtem B. Bityutskiy 			return -EIO;
209dae6227fSArtem B. Bityutskiy 		}
210dae6227fSArtem B. Bityutskiy 	}
211dae6227fSArtem B. Bityutskiy 
212dae6227fSArtem B. Bityutskiy 	fd->nhash = full_name_hash(fd->name, rd->nsize);
213dae6227fSArtem B. Bityutskiy 	fd->next = NULL;
214dae6227fSArtem B. Bityutskiy 	fd->name[rd->nsize] = '\0';
215dae6227fSArtem B. Bityutskiy 
216dae6227fSArtem B. Bityutskiy 	/*
217dae6227fSArtem B. Bityutskiy 	 * Wheee. We now have a complete jffs2_full_dirent structure, with
218dae6227fSArtem B. Bityutskiy 	 * the name in it and everything. Link it into the list
219dae6227fSArtem B. Bityutskiy 	 */
220dae6227fSArtem B. Bityutskiy 	D1(printk(KERN_DEBUG "Adding fd \"%s\", ino #%u\n", fd->name, fd->ino));
221dae6227fSArtem B. Bityutskiy 
222dae6227fSArtem B. Bityutskiy 	jffs2_add_fd_to_list(c, fd, fdp);
223dae6227fSArtem B. Bityutskiy 
224dae6227fSArtem B. Bityutskiy 	return 0;
225dae6227fSArtem B. Bityutskiy }
226dae6227fSArtem B. Bityutskiy 
227dae6227fSArtem B. Bityutskiy /*
228dae6227fSArtem B. Bityutskiy  * Helper function for jffs2_get_inode_nodes().
229dae6227fSArtem B. Bityutskiy  * It is called every time an inode node is found.
230dae6227fSArtem B. Bityutskiy  *
231dae6227fSArtem B. Bityutskiy  * Returns: 0 on succes;
232dae6227fSArtem B. Bityutskiy  * 	    1 if the node should be marked obsolete;
233dae6227fSArtem B. Bityutskiy  * 	    negative error code on failure.
234dae6227fSArtem B. Bityutskiy  */
235dae6227fSArtem B. Bityutskiy static inline int
236dae6227fSArtem B. Bityutskiy read_dnode(struct jffs2_sb_info *c,
237dae6227fSArtem B. Bityutskiy 	   struct jffs2_raw_node_ref *ref,
238dae6227fSArtem B. Bityutskiy 	   struct jffs2_raw_inode *rd,
239dae6227fSArtem B. Bityutskiy 	   uint32_t read,
240dae6227fSArtem B. Bityutskiy 	   struct rb_root *tnp,
241dae6227fSArtem B. Bityutskiy 	   int32_t *latest_mctime,
242dae6227fSArtem B. Bityutskiy 	   uint32_t *mctime_ver)
243dae6227fSArtem B. Bityutskiy {
244dae6227fSArtem B. Bityutskiy 	struct jffs2_eraseblock *jeb;
245dae6227fSArtem B. Bityutskiy 	struct jffs2_tmp_dnode_info *tn;
246dae6227fSArtem B. Bityutskiy 
247dae6227fSArtem B. Bityutskiy 	/* Obsoleted. This cannot happen, surely? dwmw2 20020308 */
248dae6227fSArtem B. Bityutskiy 	BUG_ON(ref_obsolete(ref));
249dae6227fSArtem B. Bityutskiy 
250dae6227fSArtem B. Bityutskiy 	/* If we've never checked the CRCs on this node, check them now */
251dae6227fSArtem B. Bityutskiy 	if (ref_flags(ref) == REF_UNCHECKED) {
252dae6227fSArtem B. Bityutskiy 		uint32_t crc, len;
253dae6227fSArtem B. Bityutskiy 
254dae6227fSArtem B. Bityutskiy 		crc = crc32(0, rd, sizeof(*rd) - 8);
255dae6227fSArtem B. Bityutskiy 		if (unlikely(crc != je32_to_cpu(rd->node_crc))) {
256dae6227fSArtem B. Bityutskiy 			printk(KERN_WARNING "Header CRC failed on node at %#08x: read %#08x, calculated %#08x\n",
257dae6227fSArtem B. Bityutskiy 					ref_offset(ref), je32_to_cpu(rd->node_crc), crc);
258dae6227fSArtem B. Bityutskiy 			return 1;
259dae6227fSArtem B. Bityutskiy 		}
260dae6227fSArtem B. Bityutskiy 
261dae6227fSArtem B. Bityutskiy 		/* Sanity checks */
262dae6227fSArtem B. Bityutskiy 		if (unlikely(je32_to_cpu(rd->offset) > je32_to_cpu(rd->isize)) ||
263dae6227fSArtem B. Bityutskiy 		    unlikely(PAD(je32_to_cpu(rd->csize) + sizeof(*rd)) != PAD(je32_to_cpu(rd->totlen)))) {
264dae6227fSArtem B. Bityutskiy 			printk(KERN_WARNING "Inode corrupted at %#08x, totlen %d, #ino  %d, version %d, "
265dae6227fSArtem B. Bityutskiy 				"isize %d, csize %d, dsize %d \n",
266dae6227fSArtem B. Bityutskiy 				ref_offset(ref),  je32_to_cpu(rd->totlen),  je32_to_cpu(rd->ino),
267dae6227fSArtem B. Bityutskiy 				je32_to_cpu(rd->version),  je32_to_cpu(rd->isize),
268dae6227fSArtem B. Bityutskiy 				je32_to_cpu(rd->csize), je32_to_cpu(rd->dsize));
269dae6227fSArtem B. Bityutskiy 			return 1;
270dae6227fSArtem B. Bityutskiy 		}
271dae6227fSArtem B. Bityutskiy 
272dae6227fSArtem B. Bityutskiy 		if (rd->compr != JFFS2_COMPR_ZERO && je32_to_cpu(rd->csize)) {
273dae6227fSArtem B. Bityutskiy 			unsigned char *buf = NULL;
274dae6227fSArtem B. Bityutskiy 			uint32_t pointed = 0;
275dae6227fSArtem B. Bityutskiy 			int err;
276dae6227fSArtem B. Bityutskiy #ifndef __ECOS
277dae6227fSArtem B. Bityutskiy 			if (c->mtd->point) {
278dae6227fSArtem B. Bityutskiy 				err = c->mtd->point (c->mtd, ref_offset(ref) + sizeof(*rd), je32_to_cpu(rd->csize),
279dae6227fSArtem B. Bityutskiy 						     &read, &buf);
280dae6227fSArtem B. Bityutskiy 				if (unlikely(read < je32_to_cpu(rd->csize)) && likely(!err)) {
281dae6227fSArtem B. Bityutskiy 					D1(printk(KERN_DEBUG "MTD point returned len too short: 0x%zx\n", read));
282dae6227fSArtem B. Bityutskiy 					c->mtd->unpoint(c->mtd, buf, ref_offset(ref) + sizeof(*rd),
283dae6227fSArtem B. Bityutskiy 							je32_to_cpu(rd->csize));
284dae6227fSArtem B. Bityutskiy 				} else if (unlikely(err)){
285dae6227fSArtem B. Bityutskiy 					D1(printk(KERN_DEBUG "MTD point failed %d\n", err));
286dae6227fSArtem B. Bityutskiy 				} else
287dae6227fSArtem B. Bityutskiy 					pointed = 1; /* succefully pointed to device */
288dae6227fSArtem B. Bityutskiy 			}
289dae6227fSArtem B. Bityutskiy #endif
290dae6227fSArtem B. Bityutskiy 			if(!pointed){
291dae6227fSArtem B. Bityutskiy 				buf = kmalloc(je32_to_cpu(rd->csize), GFP_KERNEL);
292dae6227fSArtem B. Bityutskiy 				if (!buf)
293dae6227fSArtem B. Bityutskiy 					return -ENOMEM;
294dae6227fSArtem B. Bityutskiy 
295dae6227fSArtem B. Bityutskiy 				err = jffs2_flash_read(c, ref_offset(ref) + sizeof(*rd), je32_to_cpu(rd->csize),
296dae6227fSArtem B. Bityutskiy 							&read, buf);
297dae6227fSArtem B. Bityutskiy 				if (unlikely(read != je32_to_cpu(rd->csize)) && likely(!err))
298dae6227fSArtem B. Bityutskiy 					err = -EIO;
299dae6227fSArtem B. Bityutskiy 				if (err) {
300dae6227fSArtem B. Bityutskiy 					kfree(buf);
301dae6227fSArtem B. Bityutskiy 					return err;
302dae6227fSArtem B. Bityutskiy 				}
303dae6227fSArtem B. Bityutskiy 			}
304dae6227fSArtem B. Bityutskiy 			crc = crc32(0, buf, je32_to_cpu(rd->csize));
305dae6227fSArtem B. Bityutskiy 			if(!pointed)
306dae6227fSArtem B. Bityutskiy 				kfree(buf);
307dae6227fSArtem B. Bityutskiy #ifndef __ECOS
308dae6227fSArtem B. Bityutskiy 			else
309dae6227fSArtem B. Bityutskiy 				c->mtd->unpoint(c->mtd, buf, ref_offset(ref) + sizeof(*rd), je32_to_cpu(rd->csize));
310dae6227fSArtem B. Bityutskiy #endif
311dae6227fSArtem B. Bityutskiy 
312dae6227fSArtem B. Bityutskiy 			if (crc != je32_to_cpu(rd->data_crc)) {
313dae6227fSArtem B. Bityutskiy 				printk(KERN_NOTICE "Data CRC failed on node at %#08x: read %#08x, calculated %#08x\n",
314dae6227fSArtem B. Bityutskiy 				       ref_offset(ref), je32_to_cpu(rd->data_crc), crc);
315dae6227fSArtem B. Bityutskiy 				return 1;
316dae6227fSArtem B. Bityutskiy 			}
317dae6227fSArtem B. Bityutskiy 
318dae6227fSArtem B. Bityutskiy 		}
319dae6227fSArtem B. Bityutskiy 
320dae6227fSArtem B. Bityutskiy 		/* Mark the node as having been checked and fix the accounting accordingly */
321dae6227fSArtem B. Bityutskiy 		jeb = &c->blocks[ref->flash_offset / c->sector_size];
322dae6227fSArtem B. Bityutskiy 		len = ref_totlen(c, jeb, ref);
323dae6227fSArtem B. Bityutskiy 
324dae6227fSArtem B. Bityutskiy 		spin_lock(&c->erase_completion_lock);
325dae6227fSArtem B. Bityutskiy 		jeb->used_size += len;
326dae6227fSArtem B. Bityutskiy 		jeb->unchecked_size -= len;
327dae6227fSArtem B. Bityutskiy 		c->used_size += len;
328dae6227fSArtem B. Bityutskiy 		c->unchecked_size -= len;
329dae6227fSArtem B. Bityutskiy 
330dae6227fSArtem B. Bityutskiy 		/* If node covers at least a whole page, or if it starts at the
331dae6227fSArtem B. Bityutskiy 		   beginning of a page and runs to the end of the file, or if
332dae6227fSArtem B. Bityutskiy 		   it's a hole node, mark it REF_PRISTINE, else REF_NORMAL.
333dae6227fSArtem B. Bityutskiy 
334dae6227fSArtem B. Bityutskiy 		   If it's actually overlapped, it'll get made NORMAL (or OBSOLETE)
335dae6227fSArtem B. Bityutskiy 		   when the overlapping node(s) get added to the tree anyway.
336dae6227fSArtem B. Bityutskiy 		*/
337dae6227fSArtem B. Bityutskiy 		if ((je32_to_cpu(rd->dsize) >= PAGE_CACHE_SIZE) ||
338dae6227fSArtem B. Bityutskiy 		    ( ((je32_to_cpu(rd->offset) & (PAGE_CACHE_SIZE-1))==0) &&
339dae6227fSArtem B. Bityutskiy 		      (je32_to_cpu(rd->dsize) + je32_to_cpu(rd->offset) == je32_to_cpu(rd->isize)))) {
340dae6227fSArtem B. Bityutskiy 			D1(printk(KERN_DEBUG "Marking node at %#08x REF_PRISTINE\n", ref_offset(ref)));
341dae6227fSArtem B. Bityutskiy 			ref->flash_offset = ref_offset(ref) | REF_PRISTINE;
342dae6227fSArtem B. Bityutskiy 		} else {
343dae6227fSArtem B. Bityutskiy 			D1(printk(KERN_DEBUG "Marking node at %#08x REF_NORMAL\n", ref_offset(ref)));
344dae6227fSArtem B. Bityutskiy 			ref->flash_offset = ref_offset(ref) | REF_NORMAL;
345dae6227fSArtem B. Bityutskiy 		}
346dae6227fSArtem B. Bityutskiy 		spin_unlock(&c->erase_completion_lock);
347dae6227fSArtem B. Bityutskiy 	}
348dae6227fSArtem B. Bityutskiy 
349dae6227fSArtem B. Bityutskiy 	tn = jffs2_alloc_tmp_dnode_info();
350dae6227fSArtem B. Bityutskiy 	if (!tn) {
351dae6227fSArtem B. Bityutskiy 		D1(printk(KERN_DEBUG "alloc tn failed\n"));
352dae6227fSArtem B. Bityutskiy 		return -ENOMEM;
353dae6227fSArtem B. Bityutskiy 	}
354dae6227fSArtem B. Bityutskiy 
355dae6227fSArtem B. Bityutskiy 	tn->fn = jffs2_alloc_full_dnode();
356dae6227fSArtem B. Bityutskiy 	if (!tn->fn) {
357dae6227fSArtem B. Bityutskiy 		D1(printk(KERN_DEBUG "alloc fn failed\n"));
358dae6227fSArtem B. Bityutskiy 		jffs2_free_tmp_dnode_info(tn);
359dae6227fSArtem B. Bityutskiy 		return -ENOMEM;
360dae6227fSArtem B. Bityutskiy 	}
361dae6227fSArtem B. Bityutskiy 
362dae6227fSArtem B. Bityutskiy 	tn->version = je32_to_cpu(rd->version);
363dae6227fSArtem B. Bityutskiy 	tn->fn->ofs = je32_to_cpu(rd->offset);
364dae6227fSArtem B. Bityutskiy 	tn->fn->raw = ref;
365dae6227fSArtem B. Bityutskiy 
366dae6227fSArtem B. Bityutskiy 	/* There was a bug where we wrote hole nodes out with
367dae6227fSArtem B. Bityutskiy 	   csize/dsize swapped. Deal with it */
368dae6227fSArtem B. Bityutskiy 	if (rd->compr == JFFS2_COMPR_ZERO && !je32_to_cpu(rd->dsize) && je32_to_cpu(rd->csize))
369dae6227fSArtem B. Bityutskiy 		tn->fn->size = je32_to_cpu(rd->csize);
370dae6227fSArtem B. Bityutskiy 	else // normal case...
371dae6227fSArtem B. Bityutskiy 		tn->fn->size = je32_to_cpu(rd->dsize);
372dae6227fSArtem B. Bityutskiy 
373dae6227fSArtem B. Bityutskiy 	D1(printk(KERN_DEBUG "dnode @%08x: ver %u, offset %#04x, dsize %#04x\n",
374dae6227fSArtem B. Bityutskiy 		  ref_offset(ref), je32_to_cpu(rd->version),
375dae6227fSArtem B. Bityutskiy 		  je32_to_cpu(rd->offset), je32_to_cpu(rd->dsize)));
376dae6227fSArtem B. Bityutskiy 
377dae6227fSArtem B. Bityutskiy 	jffs2_add_tn_to_tree(tn, tnp);
378dae6227fSArtem B. Bityutskiy 
379dae6227fSArtem B. Bityutskiy 	return 0;
380dae6227fSArtem B. Bityutskiy }
381dae6227fSArtem B. Bityutskiy 
382dae6227fSArtem B. Bityutskiy /*
383dae6227fSArtem B. Bityutskiy  * Helper function for jffs2_get_inode_nodes().
384dae6227fSArtem B. Bityutskiy  * It is called every time an unknown node is found.
385dae6227fSArtem B. Bityutskiy  *
386dae6227fSArtem B. Bityutskiy  * Returns: 0 on succes;
387dae6227fSArtem B. Bityutskiy  * 	    1 if the node should be marked obsolete;
388dae6227fSArtem B. Bityutskiy  * 	    negative error code on failure.
389dae6227fSArtem B. Bityutskiy  */
390dae6227fSArtem B. Bityutskiy static inline int
391dae6227fSArtem B. Bityutskiy read_unknown(struct jffs2_sb_info *c,
392dae6227fSArtem B. Bityutskiy 	     struct jffs2_raw_node_ref *ref,
393dae6227fSArtem B. Bityutskiy 	     struct jffs2_unknown_node *un,
394dae6227fSArtem B. Bityutskiy 	     uint32_t read)
395dae6227fSArtem B. Bityutskiy {
396dae6227fSArtem B. Bityutskiy 	/* We don't mark unknown nodes as REF_UNCHECKED */
397dae6227fSArtem B. Bityutskiy 	BUG_ON(ref_flags(ref) == REF_UNCHECKED);
398dae6227fSArtem B. Bityutskiy 
399dae6227fSArtem B. Bityutskiy 	un->nodetype = cpu_to_je16(JFFS2_NODE_ACCURATE | je16_to_cpu(un->nodetype));
400dae6227fSArtem B. Bityutskiy 
401dae6227fSArtem B. Bityutskiy 	if (crc32(0, un, sizeof(struct jffs2_unknown_node) - 4) != je32_to_cpu(un->hdr_crc)) {
402dae6227fSArtem B. Bityutskiy 
403dae6227fSArtem B. Bityutskiy 		/* Hmmm. This should have been caught at scan time. */
404dae6227fSArtem B. Bityutskiy 		printk(KERN_WARNING "Warning! Node header CRC failed at %#08x. "
405dae6227fSArtem B. Bityutskiy 				"But it must have been OK earlier.\n", ref_offset(ref));
406dae6227fSArtem B. Bityutskiy 		D1(printk(KERN_DEBUG "Node was: { %#04x, %#04x, %#08x, %#08x }\n",
407dae6227fSArtem B. Bityutskiy 			je16_to_cpu(un->magic), je16_to_cpu(un->nodetype),
408dae6227fSArtem B. Bityutskiy 			je32_to_cpu(un->totlen), je32_to_cpu(un->hdr_crc)));
409dae6227fSArtem B. Bityutskiy 		return 1;
410dae6227fSArtem B. Bityutskiy 	} else {
411dae6227fSArtem B. Bityutskiy 		switch(je16_to_cpu(un->nodetype) & JFFS2_COMPAT_MASK) {
412dae6227fSArtem B. Bityutskiy 
413dae6227fSArtem B. Bityutskiy 		case JFFS2_FEATURE_INCOMPAT:
414dae6227fSArtem B. Bityutskiy 			printk(KERN_NOTICE "Unknown INCOMPAT nodetype %#04X at %#08x\n",
415dae6227fSArtem B. Bityutskiy 					je16_to_cpu(un->nodetype), ref_offset(ref));
416dae6227fSArtem B. Bityutskiy 			/* EEP */
417dae6227fSArtem B. Bityutskiy 			BUG();
418dae6227fSArtem B. Bityutskiy 			break;
419dae6227fSArtem B. Bityutskiy 
420dae6227fSArtem B. Bityutskiy 		case JFFS2_FEATURE_ROCOMPAT:
421dae6227fSArtem B. Bityutskiy 			printk(KERN_NOTICE "Unknown ROCOMPAT nodetype %#04X at %#08x\n",
422dae6227fSArtem B. Bityutskiy 					je16_to_cpu(un->nodetype), ref_offset(ref));
423dae6227fSArtem B. Bityutskiy 			BUG_ON(!(c->flags & JFFS2_SB_FLAG_RO));
424dae6227fSArtem B. Bityutskiy 			break;
425dae6227fSArtem B. Bityutskiy 
426dae6227fSArtem B. Bityutskiy 		case JFFS2_FEATURE_RWCOMPAT_COPY:
427dae6227fSArtem B. Bityutskiy 			printk(KERN_NOTICE "Unknown RWCOMPAT_COPY nodetype %#04X at %#08x\n",
428dae6227fSArtem B. Bityutskiy 					je16_to_cpu(un->nodetype), ref_offset(ref));
429dae6227fSArtem B. Bityutskiy 			break;
430dae6227fSArtem B. Bityutskiy 
431dae6227fSArtem B. Bityutskiy 		case JFFS2_FEATURE_RWCOMPAT_DELETE:
432dae6227fSArtem B. Bityutskiy 			printk(KERN_NOTICE "Unknown RWCOMPAT_DELETE nodetype %#04X at %#08x\n",
433dae6227fSArtem B. Bityutskiy 					je16_to_cpu(un->nodetype), ref_offset(ref));
434dae6227fSArtem B. Bityutskiy 			return 1;
435dae6227fSArtem B. Bityutskiy 		}
436dae6227fSArtem B. Bityutskiy 	}
437dae6227fSArtem B. Bityutskiy 
438dae6227fSArtem B. Bityutskiy 	return 0;
439dae6227fSArtem B. Bityutskiy }
440dae6227fSArtem B. Bityutskiy 
4411da177e4SLinus Torvalds /* Get tmp_dnode_info and full_dirent for all non-obsolete nodes associated
4421da177e4SLinus Torvalds    with this ino, returning the former in order of version */
4431da177e4SLinus Torvalds 
4441da177e4SLinus Torvalds int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
4459dee7503SDavid Woodhouse 			  struct rb_root *tnp, struct jffs2_full_dirent **fdp,
4461da177e4SLinus Torvalds 			  uint32_t *highest_version, uint32_t *latest_mctime,
4471da177e4SLinus Torvalds 			  uint32_t *mctime_ver)
4481da177e4SLinus Torvalds {
4491da177e4SLinus Torvalds 	struct jffs2_raw_node_ref *ref, *valid_ref;
4509dee7503SDavid Woodhouse 	struct rb_root ret_tn = RB_ROOT;
451dae6227fSArtem B. Bityutskiy 	struct jffs2_full_dirent *ret_fd = NULL;
4521da177e4SLinus Torvalds 	union jffs2_node_union node;
4531da177e4SLinus Torvalds 	size_t retlen;
4541da177e4SLinus Torvalds 	int err;
4551da177e4SLinus Torvalds 
4561da177e4SLinus Torvalds 	*mctime_ver = 0;
4571da177e4SLinus Torvalds 
4581da177e4SLinus Torvalds 	D1(printk(KERN_DEBUG "jffs2_get_inode_nodes(): ino #%u\n", f->inocache->ino));
4591da177e4SLinus Torvalds 
4601da177e4SLinus Torvalds 	spin_lock(&c->erase_completion_lock);
4611da177e4SLinus Torvalds 
4621da177e4SLinus Torvalds 	valid_ref = jffs2_first_valid_node(f->inocache->nodes);
4631da177e4SLinus Torvalds 
4648fabed4aSTodd Poynor 	if (!valid_ref && (f->inocache->ino != 1))
4651da177e4SLinus Torvalds 		printk(KERN_WARNING "Eep. No valid nodes for ino #%u\n", f->inocache->ino);
4661da177e4SLinus Torvalds 
4671da177e4SLinus Torvalds 	while (valid_ref) {
4681da177e4SLinus Torvalds 		/* We can hold a pointer to a non-obsolete node without the spinlock,
4691da177e4SLinus Torvalds 		   but _obsolete_ nodes may disappear at any time, if the block
4701da177e4SLinus Torvalds 		   they're in gets erased. So if we mark 'ref' obsolete while we're
4711da177e4SLinus Torvalds 		   not holding the lock, it can go away immediately. For that reason,
4721da177e4SLinus Torvalds 		   we find the next valid node first, before processing 'ref'.
4731da177e4SLinus Torvalds 		*/
4741da177e4SLinus Torvalds 		ref = valid_ref;
4751da177e4SLinus Torvalds 		valid_ref = jffs2_first_valid_node(ref->next_in_ino);
4761da177e4SLinus Torvalds 		spin_unlock(&c->erase_completion_lock);
4771da177e4SLinus Torvalds 
4781da177e4SLinus Torvalds 		cond_resched();
4791da177e4SLinus Torvalds 
4801da177e4SLinus Torvalds 		/* FIXME: point() */
4811da177e4SLinus Torvalds 		err = jffs2_flash_read(c, (ref_offset(ref)),
4821da177e4SLinus Torvalds 				       min_t(uint32_t, ref_totlen(c, NULL, ref), sizeof(node)),
4831da177e4SLinus Torvalds 				       &retlen, (void *)&node);
4841da177e4SLinus Torvalds 		if (err) {
4851da177e4SLinus Torvalds 			printk(KERN_WARNING "error %d reading node at 0x%08x in get_inode_nodes()\n", err, ref_offset(ref));
4861da177e4SLinus Torvalds 			goto free_out;
4871da177e4SLinus Torvalds 		}
4881da177e4SLinus Torvalds 
4891da177e4SLinus Torvalds 		switch (je16_to_cpu(node.u.nodetype)) {
490dae6227fSArtem B. Bityutskiy 
4911da177e4SLinus Torvalds 		case JFFS2_NODETYPE_DIRENT:
4921da177e4SLinus Torvalds 			D1(printk(KERN_DEBUG "Node at %08x (%d) is a dirent node\n", ref_offset(ref), ref_flags(ref)));
493dae6227fSArtem B. Bityutskiy 
4941da177e4SLinus Torvalds 			if (retlen < sizeof(node.d)) {
495dae6227fSArtem B. Bityutskiy 				printk(KERN_WARNING "Warning! Short read dirent at %#08x\n", ref_offset(ref));
4961da177e4SLinus Torvalds 				err = -EIO;
4971da177e4SLinus Torvalds 				goto free_out;
4981da177e4SLinus Torvalds 			}
499dae6227fSArtem B. Bityutskiy 
500dae6227fSArtem B. Bityutskiy 			err = read_direntry(c, ref, &node.d, retlen, &ret_fd, latest_mctime, mctime_ver);
501dae6227fSArtem B. Bityutskiy 			if (err == 1) {
5021da177e4SLinus Torvalds 				jffs2_mark_node_obsolete(c, ref);
503dae6227fSArtem B. Bityutskiy 				break;
504dae6227fSArtem B. Bityutskiy 			} else if (unlikely(err))
505dae6227fSArtem B. Bityutskiy 				goto free_out;
506dae6227fSArtem B. Bityutskiy 
5071da177e4SLinus Torvalds 			if (je32_to_cpu(node.d.version) > *highest_version)
5081da177e4SLinus Torvalds 				*highest_version = je32_to_cpu(node.d.version);
5091da177e4SLinus Torvalds 
5101da177e4SLinus Torvalds 			break;
5111da177e4SLinus Torvalds 
5121da177e4SLinus Torvalds 		case JFFS2_NODETYPE_INODE:
5131da177e4SLinus Torvalds 			D1(printk(KERN_DEBUG "Node at %08x (%d) is a data node\n", ref_offset(ref), ref_flags(ref)));
514dae6227fSArtem B. Bityutskiy 
5151da177e4SLinus Torvalds 			if (retlen < sizeof(node.i)) {
516dae6227fSArtem B. Bityutskiy 				printk(KERN_WARNING "Warning! Short read dnode at %#08x\n", ref_offset(ref));
5171da177e4SLinus Torvalds 				err = -EIO;
5181da177e4SLinus Torvalds 				goto free_out;
5191da177e4SLinus Torvalds 			}
520dae6227fSArtem B. Bityutskiy 
521dae6227fSArtem B. Bityutskiy 			err = read_dnode(c, ref, &node.i, retlen, &ret_tn, latest_mctime, mctime_ver);
522dae6227fSArtem B. Bityutskiy 			if (err == 1) {
523dae6227fSArtem B. Bityutskiy 				jffs2_mark_node_obsolete(c, ref);
524dae6227fSArtem B. Bityutskiy 				break;
525dae6227fSArtem B. Bityutskiy 			} else if (unlikely(err))
526dae6227fSArtem B. Bityutskiy 				goto free_out;
527dae6227fSArtem B. Bityutskiy 
5281da177e4SLinus Torvalds 			if (je32_to_cpu(node.i.version) > *highest_version)
5291da177e4SLinus Torvalds 				*highest_version = je32_to_cpu(node.i.version);
5301da177e4SLinus Torvalds 
531dae6227fSArtem B. Bityutskiy 			D1(printk(KERN_DEBUG "version %d, highest_version now %d\n",
532dae6227fSArtem B. Bityutskiy 					je32_to_cpu(node.i.version), *highest_version));
5331da177e4SLinus Torvalds 
5341da177e4SLinus Torvalds 			break;
5351da177e4SLinus Torvalds 
5361da177e4SLinus Torvalds 		default:
537dae6227fSArtem B. Bityutskiy 			/* Check we've managed to read at least the common node header */
538dae6227fSArtem B. Bityutskiy 			if (retlen < sizeof(struct jffs2_unknown_node)) {
539dae6227fSArtem B. Bityutskiy 				printk(KERN_WARNING "Warning! Short read unknown node at %#08x\n",
5401da177e4SLinus Torvalds 						ref_offset(ref));
541dae6227fSArtem B. Bityutskiy 				return -EIO;
5421da177e4SLinus Torvalds 			}
5431da177e4SLinus Torvalds 
544dae6227fSArtem B. Bityutskiy 			err = read_unknown(c, ref, &node.u, retlen);
545dae6227fSArtem B. Bityutskiy 			if (err == 1) {
546dae6227fSArtem B. Bityutskiy 				jffs2_mark_node_obsolete(c, ref);
547dae6227fSArtem B. Bityutskiy 				break;
548dae6227fSArtem B. Bityutskiy 			} else if (unlikely(err))
549dae6227fSArtem B. Bityutskiy 				goto free_out;
550dae6227fSArtem B. Bityutskiy 
5511da177e4SLinus Torvalds 		}
5521da177e4SLinus Torvalds 		spin_lock(&c->erase_completion_lock);
5531da177e4SLinus Torvalds 
5541da177e4SLinus Torvalds 	}
5551da177e4SLinus Torvalds 	spin_unlock(&c->erase_completion_lock);
5561da177e4SLinus Torvalds 	*tnp = ret_tn;
5571da177e4SLinus Torvalds 	*fdp = ret_fd;
5581da177e4SLinus Torvalds 
5591da177e4SLinus Torvalds 	return 0;
5601da177e4SLinus Torvalds 
5611da177e4SLinus Torvalds  free_out:
5629dee7503SDavid Woodhouse 	jffs2_free_tmp_dnode_info_list(&ret_tn);
5631da177e4SLinus Torvalds 	jffs2_free_full_dirent_list(ret_fd);
5641da177e4SLinus Torvalds 	return err;
5651da177e4SLinus Torvalds }
5661da177e4SLinus Torvalds 
5671da177e4SLinus Torvalds void jffs2_set_inocache_state(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic, int state)
5681da177e4SLinus Torvalds {
5691da177e4SLinus Torvalds 	spin_lock(&c->inocache_lock);
5701da177e4SLinus Torvalds 	ic->state = state;
5711da177e4SLinus Torvalds 	wake_up(&c->inocache_wq);
5721da177e4SLinus Torvalds 	spin_unlock(&c->inocache_lock);
5731da177e4SLinus Torvalds }
5741da177e4SLinus Torvalds 
5751da177e4SLinus Torvalds /* During mount, this needs no locking. During normal operation, its
5761da177e4SLinus Torvalds    callers want to do other stuff while still holding the inocache_lock.
5771da177e4SLinus Torvalds    Rather than introducing special case get_ino_cache functions or
5781da177e4SLinus Torvalds    callbacks, we just let the caller do the locking itself. */
5791da177e4SLinus Torvalds 
5801da177e4SLinus Torvalds struct jffs2_inode_cache *jffs2_get_ino_cache(struct jffs2_sb_info *c, uint32_t ino)
5811da177e4SLinus Torvalds {
5821da177e4SLinus Torvalds 	struct jffs2_inode_cache *ret;
5831da177e4SLinus Torvalds 
5841da177e4SLinus Torvalds 	D2(printk(KERN_DEBUG "jffs2_get_ino_cache(): ino %u\n", ino));
5851da177e4SLinus Torvalds 
5861da177e4SLinus Torvalds 	ret = c->inocache_list[ino % INOCACHE_HASHSIZE];
5871da177e4SLinus Torvalds 	while (ret && ret->ino < ino) {
5881da177e4SLinus Torvalds 		ret = ret->next;
5891da177e4SLinus Torvalds 	}
5901da177e4SLinus Torvalds 
5911da177e4SLinus Torvalds 	if (ret && ret->ino != ino)
5921da177e4SLinus Torvalds 		ret = NULL;
5931da177e4SLinus Torvalds 
5941da177e4SLinus Torvalds 	D2(printk(KERN_DEBUG "jffs2_get_ino_cache found %p for ino %u\n", ret, ino));
5951da177e4SLinus Torvalds 	return ret;
5961da177e4SLinus Torvalds }
5971da177e4SLinus Torvalds 
5981da177e4SLinus Torvalds void jffs2_add_ino_cache (struct jffs2_sb_info *c, struct jffs2_inode_cache *new)
5991da177e4SLinus Torvalds {
6001da177e4SLinus Torvalds 	struct jffs2_inode_cache **prev;
6017d27c814SThomas Gleixner 
6021da177e4SLinus Torvalds 	spin_lock(&c->inocache_lock);
6037d200960SDavid Woodhouse 	if (!new->ino)
6047d200960SDavid Woodhouse 		new->ino = ++c->highest_ino;
6057d200960SDavid Woodhouse 
6067d200960SDavid Woodhouse 	D2(printk(KERN_DEBUG "jffs2_add_ino_cache: Add %p (ino #%u)\n", new, new->ino));
6071da177e4SLinus Torvalds 
6081da177e4SLinus Torvalds 	prev = &c->inocache_list[new->ino % INOCACHE_HASHSIZE];
6091da177e4SLinus Torvalds 
6101da177e4SLinus Torvalds 	while ((*prev) && (*prev)->ino < new->ino) {
6111da177e4SLinus Torvalds 		prev = &(*prev)->next;
6121da177e4SLinus Torvalds 	}
6131da177e4SLinus Torvalds 	new->next = *prev;
6141da177e4SLinus Torvalds 	*prev = new;
6151da177e4SLinus Torvalds 
6161da177e4SLinus Torvalds 	spin_unlock(&c->inocache_lock);
6171da177e4SLinus Torvalds }
6181da177e4SLinus Torvalds 
6191da177e4SLinus Torvalds void jffs2_del_ino_cache(struct jffs2_sb_info *c, struct jffs2_inode_cache *old)
6201da177e4SLinus Torvalds {
6211da177e4SLinus Torvalds 	struct jffs2_inode_cache **prev;
62267e345d1SDavid Woodhouse 	D1(printk(KERN_DEBUG "jffs2_del_ino_cache: Del %p (ino #%u)\n", old, old->ino));
6231da177e4SLinus Torvalds 	spin_lock(&c->inocache_lock);
6241da177e4SLinus Torvalds 
6251da177e4SLinus Torvalds 	prev = &c->inocache_list[old->ino % INOCACHE_HASHSIZE];
6261da177e4SLinus Torvalds 
6271da177e4SLinus Torvalds 	while ((*prev) && (*prev)->ino < old->ino) {
6281da177e4SLinus Torvalds 		prev = &(*prev)->next;
6291da177e4SLinus Torvalds 	}
6301da177e4SLinus Torvalds 	if ((*prev) == old) {
6311da177e4SLinus Torvalds 		*prev = old->next;
6321da177e4SLinus Torvalds 	}
6331da177e4SLinus Torvalds 
63467e345d1SDavid Woodhouse 	/* Free it now unless it's in READING or CLEARING state, which
63567e345d1SDavid Woodhouse 	   are the transitions upon read_inode() and clear_inode(). The
63667e345d1SDavid Woodhouse 	   rest of the time we know nobody else is looking at it, and
63767e345d1SDavid Woodhouse 	   if it's held by read_inode() or clear_inode() they'll free it
63867e345d1SDavid Woodhouse 	   for themselves. */
63967e345d1SDavid Woodhouse 	if (old->state != INO_STATE_READING && old->state != INO_STATE_CLEARING)
64067e345d1SDavid Woodhouse 		jffs2_free_inode_cache(old);
64167e345d1SDavid Woodhouse 
6421da177e4SLinus Torvalds 	spin_unlock(&c->inocache_lock);
6431da177e4SLinus Torvalds }
6441da177e4SLinus Torvalds 
6451da177e4SLinus Torvalds void jffs2_free_ino_caches(struct jffs2_sb_info *c)
6461da177e4SLinus Torvalds {
6471da177e4SLinus Torvalds 	int i;
6481da177e4SLinus Torvalds 	struct jffs2_inode_cache *this, *next;
6491da177e4SLinus Torvalds 
6501da177e4SLinus Torvalds 	for (i=0; i<INOCACHE_HASHSIZE; i++) {
6511da177e4SLinus Torvalds 		this = c->inocache_list[i];
6521da177e4SLinus Torvalds 		while (this) {
6531da177e4SLinus Torvalds 			next = this->next;
6541da177e4SLinus Torvalds 			jffs2_free_inode_cache(this);
6551da177e4SLinus Torvalds 			this = next;
6561da177e4SLinus Torvalds 		}
6571da177e4SLinus Torvalds 		c->inocache_list[i] = NULL;
6581da177e4SLinus Torvalds 	}
6591da177e4SLinus Torvalds }
6601da177e4SLinus Torvalds 
6611da177e4SLinus Torvalds void jffs2_free_raw_node_refs(struct jffs2_sb_info *c)
6621da177e4SLinus Torvalds {
6631da177e4SLinus Torvalds 	int i;
6641da177e4SLinus Torvalds 	struct jffs2_raw_node_ref *this, *next;
6651da177e4SLinus Torvalds 
6661da177e4SLinus Torvalds 	for (i=0; i<c->nr_blocks; i++) {
6671da177e4SLinus Torvalds 		this = c->blocks[i].first_node;
6681da177e4SLinus Torvalds 		while(this) {
6691da177e4SLinus Torvalds 			next = this->next_phys;
6701da177e4SLinus Torvalds 			jffs2_free_raw_node_ref(this);
6711da177e4SLinus Torvalds 			this = next;
6721da177e4SLinus Torvalds 		}
6731da177e4SLinus Torvalds 		c->blocks[i].first_node = c->blocks[i].last_node = NULL;
6741da177e4SLinus Torvalds 	}
6751da177e4SLinus Torvalds }
6761da177e4SLinus Torvalds 
6771da177e4SLinus Torvalds struct jffs2_node_frag *jffs2_lookup_node_frag(struct rb_root *fragtree, uint32_t offset)
6781da177e4SLinus Torvalds {
6791da177e4SLinus Torvalds 	/* The common case in lookup is that there will be a node
6801da177e4SLinus Torvalds 	   which precisely matches. So we go looking for that first */
6811da177e4SLinus Torvalds 	struct rb_node *next;
6821da177e4SLinus Torvalds 	struct jffs2_node_frag *prev = NULL;
6831da177e4SLinus Torvalds 	struct jffs2_node_frag *frag = NULL;
6841da177e4SLinus Torvalds 
6851da177e4SLinus Torvalds 	D2(printk(KERN_DEBUG "jffs2_lookup_node_frag(%p, %d)\n", fragtree, offset));
6861da177e4SLinus Torvalds 
6871da177e4SLinus Torvalds 	next = fragtree->rb_node;
6881da177e4SLinus Torvalds 
6891da177e4SLinus Torvalds 	while(next) {
6901da177e4SLinus Torvalds 		frag = rb_entry(next, struct jffs2_node_frag, rb);
6911da177e4SLinus Torvalds 
6921da177e4SLinus Torvalds 		D2(printk(KERN_DEBUG "Considering frag %d-%d (%p). left %p, right %p\n",
6931da177e4SLinus Torvalds 			  frag->ofs, frag->ofs+frag->size, frag, frag->rb.rb_left, frag->rb.rb_right));
6941da177e4SLinus Torvalds 		if (frag->ofs + frag->size <= offset) {
6951da177e4SLinus Torvalds 			D2(printk(KERN_DEBUG "Going right from frag %d-%d, before the region we care about\n",
6961da177e4SLinus Torvalds 				  frag->ofs, frag->ofs+frag->size));
6971da177e4SLinus Torvalds 			/* Remember the closest smaller match on the way down */
6981da177e4SLinus Torvalds 			if (!prev || frag->ofs > prev->ofs)
6991da177e4SLinus Torvalds 				prev = frag;
7001da177e4SLinus Torvalds 			next = frag->rb.rb_right;
7011da177e4SLinus Torvalds 		} else if (frag->ofs > offset) {
7021da177e4SLinus Torvalds 			D2(printk(KERN_DEBUG "Going left from frag %d-%d, after the region we care about\n",
7031da177e4SLinus Torvalds 				  frag->ofs, frag->ofs+frag->size));
7041da177e4SLinus Torvalds 			next = frag->rb.rb_left;
7051da177e4SLinus Torvalds 		} else {
7061da177e4SLinus Torvalds 			D2(printk(KERN_DEBUG "Returning frag %d,%d, matched\n",
7071da177e4SLinus Torvalds 				  frag->ofs, frag->ofs+frag->size));
7081da177e4SLinus Torvalds 			return frag;
7091da177e4SLinus Torvalds 		}
7101da177e4SLinus Torvalds 	}
7111da177e4SLinus Torvalds 
7121da177e4SLinus Torvalds 	/* Exact match not found. Go back up looking at each parent,
7131da177e4SLinus Torvalds 	   and return the closest smaller one */
7141da177e4SLinus Torvalds 
7151da177e4SLinus Torvalds 	if (prev)
7161da177e4SLinus Torvalds 		D2(printk(KERN_DEBUG "No match. Returning frag %d,%d, closest previous\n",
7171da177e4SLinus Torvalds 			  prev->ofs, prev->ofs+prev->size));
7181da177e4SLinus Torvalds 	else
7191da177e4SLinus Torvalds 		D2(printk(KERN_DEBUG "Returning NULL, empty fragtree\n"));
7201da177e4SLinus Torvalds 
7211da177e4SLinus Torvalds 	return prev;
7221da177e4SLinus Torvalds }
7231da177e4SLinus Torvalds 
7241da177e4SLinus Torvalds /* Pass 'c' argument to indicate that nodes should be marked obsolete as
7251da177e4SLinus Torvalds    they're killed. */
7261da177e4SLinus Torvalds void jffs2_kill_fragtree(struct rb_root *root, struct jffs2_sb_info *c)
7271da177e4SLinus Torvalds {
7281da177e4SLinus Torvalds 	struct jffs2_node_frag *frag;
7291da177e4SLinus Torvalds 	struct jffs2_node_frag *parent;
7301da177e4SLinus Torvalds 
7311da177e4SLinus Torvalds 	if (!root->rb_node)
7321da177e4SLinus Torvalds 		return;
7331da177e4SLinus Torvalds 
7341da177e4SLinus Torvalds 	frag = (rb_entry(root->rb_node, struct jffs2_node_frag, rb));
7351da177e4SLinus Torvalds 
7361da177e4SLinus Torvalds 	while(frag) {
7371da177e4SLinus Torvalds 		if (frag->rb.rb_left) {
7381da177e4SLinus Torvalds 			D2(printk(KERN_DEBUG "Going left from frag (%p) %d-%d\n",
7391da177e4SLinus Torvalds 				  frag, frag->ofs, frag->ofs+frag->size));
7401da177e4SLinus Torvalds 			frag = frag_left(frag);
7411da177e4SLinus Torvalds 			continue;
7421da177e4SLinus Torvalds 		}
7431da177e4SLinus Torvalds 		if (frag->rb.rb_right) {
7441da177e4SLinus Torvalds 			D2(printk(KERN_DEBUG "Going right from frag (%p) %d-%d\n",
7451da177e4SLinus Torvalds 				  frag, frag->ofs, frag->ofs+frag->size));
7461da177e4SLinus Torvalds 			frag = frag_right(frag);
7471da177e4SLinus Torvalds 			continue;
7481da177e4SLinus Torvalds 		}
7491da177e4SLinus Torvalds 
7501da177e4SLinus Torvalds 		D2(printk(KERN_DEBUG "jffs2_kill_fragtree: frag at 0x%x-0x%x: node %p, frags %d--\n",
7511da177e4SLinus Torvalds 			  frag->ofs, frag->ofs+frag->size, frag->node,
7521da177e4SLinus Torvalds 			  frag->node?frag->node->frags:0));
7531da177e4SLinus Torvalds 
7541da177e4SLinus Torvalds 		if (frag->node && !(--frag->node->frags)) {
7551da177e4SLinus Torvalds 			/* Not a hole, and it's the final remaining frag
7561da177e4SLinus Torvalds 			   of this node. Free the node */
7571da177e4SLinus Torvalds 			if (c)
7581da177e4SLinus Torvalds 				jffs2_mark_node_obsolete(c, frag->node->raw);
7591da177e4SLinus Torvalds 
7601da177e4SLinus Torvalds 			jffs2_free_full_dnode(frag->node);
7611da177e4SLinus Torvalds 		}
7621da177e4SLinus Torvalds 		parent = frag_parent(frag);
7631da177e4SLinus Torvalds 		if (parent) {
7641da177e4SLinus Torvalds 			if (frag_left(parent) == frag)
7651da177e4SLinus Torvalds 				parent->rb.rb_left = NULL;
7661da177e4SLinus Torvalds 			else
7671da177e4SLinus Torvalds 				parent->rb.rb_right = NULL;
7681da177e4SLinus Torvalds 		}
7691da177e4SLinus Torvalds 
7701da177e4SLinus Torvalds 		jffs2_free_node_frag(frag);
7711da177e4SLinus Torvalds 		frag = parent;
7721da177e4SLinus Torvalds 
7731da177e4SLinus Torvalds 		cond_resched();
7741da177e4SLinus Torvalds 	}
7751da177e4SLinus Torvalds }
7761da177e4SLinus Torvalds 
7771da177e4SLinus Torvalds void jffs2_fragtree_insert(struct jffs2_node_frag *newfrag, struct jffs2_node_frag *base)
7781da177e4SLinus Torvalds {
7791da177e4SLinus Torvalds 	struct rb_node *parent = &base->rb;
7801da177e4SLinus Torvalds 	struct rb_node **link = &parent;
7811da177e4SLinus Torvalds 
7821da177e4SLinus Torvalds 	D2(printk(KERN_DEBUG "jffs2_fragtree_insert(%p; %d-%d, %p)\n", newfrag,
7831da177e4SLinus Torvalds 		  newfrag->ofs, newfrag->ofs+newfrag->size, base));
7841da177e4SLinus Torvalds 
7851da177e4SLinus Torvalds 	while (*link) {
7861da177e4SLinus Torvalds 		parent = *link;
7871da177e4SLinus Torvalds 		base = rb_entry(parent, struct jffs2_node_frag, rb);
7881da177e4SLinus Torvalds 
7891da177e4SLinus Torvalds 		D2(printk(KERN_DEBUG "fragtree_insert considering frag at 0x%x\n", base->ofs));
7901da177e4SLinus Torvalds 		if (newfrag->ofs > base->ofs)
7911da177e4SLinus Torvalds 			link = &base->rb.rb_right;
7921da177e4SLinus Torvalds 		else if (newfrag->ofs < base->ofs)
7931da177e4SLinus Torvalds 			link = &base->rb.rb_left;
7941da177e4SLinus Torvalds 		else {
7951da177e4SLinus Torvalds 			printk(KERN_CRIT "Duplicate frag at %08x (%p,%p)\n", newfrag->ofs, newfrag, base);
7961da177e4SLinus Torvalds 			BUG();
7971da177e4SLinus Torvalds 		}
7981da177e4SLinus Torvalds 	}
7991da177e4SLinus Torvalds 
8001da177e4SLinus Torvalds 	rb_link_node(&newfrag->rb, &base->rb, link);
8011da177e4SLinus Torvalds }
802