xref: /minix3/sys/ufs/chfs/chfs_readinode.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1*0a6a1f1dSLionel Sambuc /*	$NetBSD: chfs_readinode.c,v 1.9 2014/09/01 16:31:17 he Exp $	*/
2d65f6f70SBen Gras 
3d65f6f70SBen Gras /*-
4d65f6f70SBen Gras  * Copyright (c) 2010 Department of Software Engineering,
5d65f6f70SBen Gras  *		      University of Szeged, Hungary
6d65f6f70SBen Gras  * Copyright (C) 2010 David Tengeri <dtengeri@inf.u-szeged.hu>
7d65f6f70SBen Gras  * Copyright (C) 2010 Tamas Toth <ttoth@inf.u-szeged.hu>
8d65f6f70SBen Gras  * Copyright (C) 2010 Adam Hoka <ahoka@NetBSD.org>
9d65f6f70SBen Gras  * All rights reserved.
10d65f6f70SBen Gras  *
11d65f6f70SBen Gras  * This code is derived from software contributed to The NetBSD Foundation
12d65f6f70SBen Gras  * by the Department of Software Engineering, University of Szeged, Hungary
13d65f6f70SBen Gras  *
14d65f6f70SBen Gras  * Redistribution and use in source and binary forms, with or without
15d65f6f70SBen Gras  * modification, are permitted provided that the following conditions
16d65f6f70SBen Gras  * are met:
17d65f6f70SBen Gras  * 1. Redistributions of source code must retain the above copyright
18d65f6f70SBen Gras  *    notice, this list of conditions and the following disclaimer.
19d65f6f70SBen Gras  * 2. Redistributions in binary form must reproduce the above copyright
20d65f6f70SBen Gras  *    notice, this list of conditions and the following disclaimer in the
21d65f6f70SBen Gras  *    documentation and/or other materials provided with the distribution.
22d65f6f70SBen Gras  *
23d65f6f70SBen Gras  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24d65f6f70SBen Gras  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25d65f6f70SBen Gras  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26d65f6f70SBen Gras  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27d65f6f70SBen Gras  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28d65f6f70SBen Gras  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29d65f6f70SBen Gras  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
30d65f6f70SBen Gras  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31d65f6f70SBen Gras  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32d65f6f70SBen Gras  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33d65f6f70SBen Gras  * SUCH DAMAGE.
34d65f6f70SBen Gras  */
35d65f6f70SBen Gras 
36d65f6f70SBen Gras #include <sys/buf.h>
37d65f6f70SBen Gras 
38d65f6f70SBen Gras #include "chfs.h"
39d65f6f70SBen Gras 
40d65f6f70SBen Gras /* tmp node operations */
41d65f6f70SBen Gras int chfs_check_td_data(struct chfs_mount *,
42d65f6f70SBen Gras     struct chfs_tmp_dnode *);
43d65f6f70SBen Gras int chfs_check_td_node(struct chfs_mount *,
44d65f6f70SBen Gras     struct chfs_tmp_dnode *);
45d65f6f70SBen Gras struct chfs_node_ref *chfs_first_valid_data_ref(struct chfs_node_ref *);
46d65f6f70SBen Gras int chfs_add_tmp_dnode_to_tree(struct chfs_mount *,
47d65f6f70SBen Gras     struct chfs_readinode_info *,
48d65f6f70SBen Gras     struct chfs_tmp_dnode *);
49d65f6f70SBen Gras void chfs_add_tmp_dnode_to_tdi(struct chfs_tmp_dnode_info *,
50d65f6f70SBen Gras 	struct chfs_tmp_dnode *);
51d65f6f70SBen Gras void chfs_remove_tmp_dnode_from_tdi(struct chfs_tmp_dnode_info *,
52d65f6f70SBen Gras 	struct chfs_tmp_dnode *);
53d65f6f70SBen Gras static void chfs_kill_td(struct chfs_mount *,
54d65f6f70SBen Gras     struct chfs_tmp_dnode *);
55d65f6f70SBen Gras static void chfs_kill_tdi(struct chfs_mount *,
56d65f6f70SBen Gras     struct chfs_tmp_dnode_info *);
57d65f6f70SBen Gras /* frag node operations */
58d65f6f70SBen Gras struct chfs_node_frag *new_fragment(struct chfs_full_dnode *,
59d65f6f70SBen Gras     uint32_t,
60d65f6f70SBen Gras     uint32_t);
61d65f6f70SBen Gras int no_overlapping_node(struct rb_tree *, struct chfs_node_frag *,
62d65f6f70SBen Gras     struct chfs_node_frag *, uint32_t);
63d65f6f70SBen Gras int chfs_add_frag_to_fragtree(struct chfs_mount *,
64d65f6f70SBen Gras     struct rb_tree *,
65d65f6f70SBen Gras     struct chfs_node_frag *);
66d65f6f70SBen Gras void chfs_obsolete_node_frag(struct chfs_mount *,
67d65f6f70SBen Gras     struct chfs_node_frag *);
68d65f6f70SBen Gras /* general node operations */
69d65f6f70SBen Gras int chfs_get_data_nodes(struct chfs_mount *,
70d65f6f70SBen Gras     struct chfs_inode *,
71d65f6f70SBen Gras     struct chfs_readinode_info *);
72d65f6f70SBen Gras int chfs_build_fragtree(struct chfs_mount *,
73d65f6f70SBen Gras     struct chfs_inode *,
74d65f6f70SBen Gras     struct chfs_readinode_info *);
75d65f6f70SBen Gras 
76d65f6f70SBen Gras 
77d65f6f70SBen Gras 
7884d9c625SLionel Sambuc /* tmp node rbtree operations */
79d65f6f70SBen Gras static signed int
tmp_node_compare_nodes(void * ctx,const void * n1,const void * n2)80d65f6f70SBen Gras tmp_node_compare_nodes(void *ctx, const void *n1, const void *n2)
81d65f6f70SBen Gras {
82d65f6f70SBen Gras 	const struct chfs_tmp_dnode_info *tdi1 = n1;
83d65f6f70SBen Gras 	const struct chfs_tmp_dnode_info *tdi2 = n2;
84d65f6f70SBen Gras 
85d65f6f70SBen Gras 	return (tdi1->tmpnode->node->ofs - tdi2->tmpnode->node->ofs);
86d65f6f70SBen Gras }
87d65f6f70SBen Gras 
88d65f6f70SBen Gras static signed int
tmp_node_compare_key(void * ctx,const void * n,const void * key)89d65f6f70SBen Gras tmp_node_compare_key(void *ctx, const void *n, const void *key)
90d65f6f70SBen Gras {
91d65f6f70SBen Gras 	const struct chfs_tmp_dnode_info *tdi = n;
92d65f6f70SBen Gras 	uint64_t ofs =  *(const uint64_t *)key;
93d65f6f70SBen Gras 
94d65f6f70SBen Gras 	return (tdi->tmpnode->node->ofs - ofs);
95d65f6f70SBen Gras }
96d65f6f70SBen Gras 
97d65f6f70SBen Gras const rb_tree_ops_t tmp_node_rbtree_ops = {
98d65f6f70SBen Gras 	.rbto_compare_nodes = tmp_node_compare_nodes,
99d65f6f70SBen Gras 	.rbto_compare_key = tmp_node_compare_key,
100d65f6f70SBen Gras 	.rbto_node_offset = offsetof(struct chfs_tmp_dnode_info, rb_node),
101d65f6f70SBen Gras 	.rbto_context = NULL
102d65f6f70SBen Gras };
103d65f6f70SBen Gras 
104d65f6f70SBen Gras 
10584d9c625SLionel Sambuc /* frag node rbtree operations */
106d65f6f70SBen Gras static signed int
frag_compare_nodes(void * ctx,const void * n1,const void * n2)107d65f6f70SBen Gras frag_compare_nodes(void *ctx, const void *n1, const void *n2)
108d65f6f70SBen Gras {
109d65f6f70SBen Gras 	const struct chfs_node_frag *frag1 = n1;
110d65f6f70SBen Gras 	const struct chfs_node_frag *frag2 = n2;
111d65f6f70SBen Gras 
112d65f6f70SBen Gras 	return (frag1->ofs - frag2->ofs);
113d65f6f70SBen Gras }
114d65f6f70SBen Gras 
115d65f6f70SBen Gras static signed int
frag_compare_key(void * ctx,const void * n,const void * key)116d65f6f70SBen Gras frag_compare_key(void *ctx, const void *n, const void *key)
117d65f6f70SBen Gras {
118d65f6f70SBen Gras 	const struct chfs_node_frag *frag = n;
119d65f6f70SBen Gras 	uint64_t ofs = *(const uint64_t *)key;
120d65f6f70SBen Gras 
121d65f6f70SBen Gras 	return (frag->ofs - ofs);
122d65f6f70SBen Gras }
123d65f6f70SBen Gras 
124d65f6f70SBen Gras const rb_tree_ops_t frag_rbtree_ops = {
125d65f6f70SBen Gras 	.rbto_compare_nodes = frag_compare_nodes,
126d65f6f70SBen Gras 	.rbto_compare_key   = frag_compare_key,
127d65f6f70SBen Gras 	.rbto_node_offset = offsetof(struct chfs_node_frag, rb_node),
128d65f6f70SBen Gras 	.rbto_context = NULL
129d65f6f70SBen Gras };
130d65f6f70SBen Gras 
131d65f6f70SBen Gras 
132d65f6f70SBen Gras /*
13384d9c625SLionel Sambuc  * chfs_check_td_data - checks the data CRC of the node
134d65f6f70SBen Gras  *
135d65f6f70SBen Gras  * Returns: 0 - if everything OK;
136d65f6f70SBen Gras  * 	    	1 - if CRC is incorrect;
137d65f6f70SBen Gras  * 	    	2 - else;
138d65f6f70SBen Gras  *	    	error code if an error occured.
139d65f6f70SBen Gras  */
140d65f6f70SBen Gras int
chfs_check_td_data(struct chfs_mount * chmp,struct chfs_tmp_dnode * td)141d65f6f70SBen Gras chfs_check_td_data(struct chfs_mount *chmp,
142d65f6f70SBen Gras     struct chfs_tmp_dnode *td)
143d65f6f70SBen Gras {
144d65f6f70SBen Gras 	int err;
145d65f6f70SBen Gras 	size_t retlen, len, totlen;
146d65f6f70SBen Gras 	uint32_t crc;
147d65f6f70SBen Gras 	uint64_t ofs;
148d65f6f70SBen Gras 	char *buf;
149d65f6f70SBen Gras 	struct chfs_node_ref *nref = td->node->nref;
150d65f6f70SBen Gras 
151d65f6f70SBen Gras 	KASSERT(mutex_owned(&chmp->chm_lock_mountfields));
152d65f6f70SBen Gras 	KASSERT(!mutex_owned(&chmp->chm_lock_sizes));
153d65f6f70SBen Gras 
154d65f6f70SBen Gras 	ofs = CHFS_GET_OFS(nref->nref_offset) + sizeof(struct chfs_flash_data_node);
155d65f6f70SBen Gras 	len = td->node->size;
156d65f6f70SBen Gras 	if (!len)
157d65f6f70SBen Gras 		return 0;
158d65f6f70SBen Gras 
15984d9c625SLionel Sambuc 	/* Read data. */
160d65f6f70SBen Gras 	buf = kmem_alloc(len, KM_SLEEP);
161d65f6f70SBen Gras 	if (!buf) {
162d65f6f70SBen Gras 		dbg("allocating error\n");
163d65f6f70SBen Gras 		return 2;
164d65f6f70SBen Gras 	}
165d65f6f70SBen Gras 	err = chfs_read_leb(chmp, nref->nref_lnr, buf, ofs, len, &retlen);
166d65f6f70SBen Gras 	if (err) {
16784d9c625SLionel Sambuc 		dbg("error while reading: %d\n", err);
168d65f6f70SBen Gras 		err = 2;
169d65f6f70SBen Gras 		goto out;
170d65f6f70SBen Gras 	}
171d65f6f70SBen Gras 
17284d9c625SLionel Sambuc 	/* Check crc. */
173d65f6f70SBen Gras 	if (len != retlen) {
174d65f6f70SBen Gras 		dbg("len:%zu, retlen:%zu\n", len, retlen);
175d65f6f70SBen Gras 		err = 2;
176d65f6f70SBen Gras 		goto out;
177d65f6f70SBen Gras 	}
178d65f6f70SBen Gras 	crc = crc32(0, (uint8_t *)buf, len);
179d65f6f70SBen Gras 
180d65f6f70SBen Gras 	if (crc != td->data_crc) {
181d65f6f70SBen Gras 		dbg("crc failed, calculated: 0x%x, orig: 0x%x\n", crc, td->data_crc);
182d65f6f70SBen Gras 		kmem_free(buf, len);
183d65f6f70SBen Gras 		return 1;
184d65f6f70SBen Gras 	}
185d65f6f70SBen Gras 
18684d9c625SLionel Sambuc 	/* Correct sizes. */
18784d9c625SLionel Sambuc 	CHFS_MARK_REF_NORMAL(nref);
188d65f6f70SBen Gras 	totlen = CHFS_PAD(sizeof(struct chfs_flash_data_node) + len);
189d65f6f70SBen Gras 
190d65f6f70SBen Gras 	mutex_enter(&chmp->chm_lock_sizes);
191d65f6f70SBen Gras 	chfs_change_size_unchecked(chmp, &chmp->chm_blocks[nref->nref_lnr], -totlen);
192d65f6f70SBen Gras 	chfs_change_size_used(chmp, &chmp->chm_blocks[nref->nref_lnr], totlen);
193d65f6f70SBen Gras 	mutex_exit(&chmp->chm_lock_sizes);
194d65f6f70SBen Gras 	KASSERT(chmp->chm_blocks[nref->nref_lnr].used_size <= chmp->chm_ebh->eb_size);
195d65f6f70SBen Gras 
196d65f6f70SBen Gras 	err = 0;
197d65f6f70SBen Gras out:
198d65f6f70SBen Gras 	kmem_free(buf, len);
199d65f6f70SBen Gras 	return err;
200d65f6f70SBen Gras }
201d65f6f70SBen Gras 
20284d9c625SLionel Sambuc /* chfs_check_td_node - checks a temporary node */
203d65f6f70SBen Gras int
chfs_check_td_node(struct chfs_mount * chmp,struct chfs_tmp_dnode * td)204d65f6f70SBen Gras chfs_check_td_node(struct chfs_mount *chmp, struct chfs_tmp_dnode *td)
205d65f6f70SBen Gras {
206d65f6f70SBen Gras 	int ret;
207d65f6f70SBen Gras 
208d65f6f70SBen Gras 	if (CHFS_REF_FLAGS(td->node->nref) != CHFS_UNCHECKED_NODE_MASK)
209d65f6f70SBen Gras 		return 0;
210d65f6f70SBen Gras 
211d65f6f70SBen Gras 	ret = chfs_check_td_data(chmp, td);
212d65f6f70SBen Gras 	return ret;
213d65f6f70SBen Gras }
214d65f6f70SBen Gras 
21584d9c625SLionel Sambuc /*
21684d9c625SLionel Sambuc  * chfs_first_valid_data_ref -
21784d9c625SLionel Sambuc  * returns the first valid nref after the given nref
21884d9c625SLionel Sambuc  */
219d65f6f70SBen Gras struct chfs_node_ref *
chfs_first_valid_data_ref(struct chfs_node_ref * nref)220d65f6f70SBen Gras chfs_first_valid_data_ref(struct chfs_node_ref *nref)
221d65f6f70SBen Gras {
222d65f6f70SBen Gras 	while (nref) {
223d65f6f70SBen Gras 		if (!CHFS_REF_OBSOLETE(nref)) {
224d65f6f70SBen Gras #ifdef DGB_MSG_GC
225d65f6f70SBen Gras 			if (nref->nref_lnr == REF_EMPTY_NODE) {
226d65f6f70SBen Gras 				dbg("FIRST VALID IS EMPTY!\n");
227d65f6f70SBen Gras 			}
228d65f6f70SBen Gras #endif
229d65f6f70SBen Gras 			return nref;
230d65f6f70SBen Gras 		}
231d65f6f70SBen Gras 
232d65f6f70SBen Gras 		if (nref->nref_next) {
233d65f6f70SBen Gras 			nref = nref->nref_next;
234d65f6f70SBen Gras 		} else
235d65f6f70SBen Gras 			break;
236d65f6f70SBen Gras 	}
237d65f6f70SBen Gras 	return NULL;
238d65f6f70SBen Gras }
239d65f6f70SBen Gras 
24084d9c625SLionel Sambuc /*
24184d9c625SLionel Sambuc  * chfs_add_tmp_dnode_to_tdi -
24284d9c625SLionel Sambuc  * adds a temporary node to a temporary node descriptor
24384d9c625SLionel Sambuc  */
244d65f6f70SBen Gras void
chfs_add_tmp_dnode_to_tdi(struct chfs_tmp_dnode_info * tdi,struct chfs_tmp_dnode * td)245d65f6f70SBen Gras chfs_add_tmp_dnode_to_tdi(struct chfs_tmp_dnode_info *tdi,
246d65f6f70SBen Gras 	struct chfs_tmp_dnode *td)
247d65f6f70SBen Gras {
248d65f6f70SBen Gras 	if (!tdi->tmpnode) {
24984d9c625SLionel Sambuc 	/* The chain is empty. */
250d65f6f70SBen Gras 		tdi->tmpnode = td;
251d65f6f70SBen Gras 	} else {
25284d9c625SLionel Sambuc 	/* Insert into the chain. */
253d65f6f70SBen Gras 		struct chfs_tmp_dnode *tmp = tdi->tmpnode;
254d65f6f70SBen Gras 		while (tmp->next) {
255d65f6f70SBen Gras 			tmp = tmp->next;
256d65f6f70SBen Gras 		}
257d65f6f70SBen Gras 		tmp->next = td;
258d65f6f70SBen Gras 	}
259d65f6f70SBen Gras }
260d65f6f70SBen Gras 
26184d9c625SLionel Sambuc /*
26284d9c625SLionel Sambuc  * chfs_remove_tmp_dnode_from_tdi -
26384d9c625SLionel Sambuc  * removes a temporary node from its descriptor
26484d9c625SLionel Sambuc  */
265d65f6f70SBen Gras void
chfs_remove_tmp_dnode_from_tdi(struct chfs_tmp_dnode_info * tdi,struct chfs_tmp_dnode * td)266d65f6f70SBen Gras chfs_remove_tmp_dnode_from_tdi(struct chfs_tmp_dnode_info *tdi,
267d65f6f70SBen Gras 	struct chfs_tmp_dnode *td)
268d65f6f70SBen Gras {
269d65f6f70SBen Gras 	if (tdi->tmpnode == td) {
27084d9c625SLionel Sambuc 	/* It's the first in the chain. */
271d65f6f70SBen Gras 		tdi->tmpnode = tdi->tmpnode->next;
272d65f6f70SBen Gras 	} else {
27384d9c625SLionel Sambuc 	/* Remove from the middle of the chain. */
274d65f6f70SBen Gras 		struct chfs_tmp_dnode *tmp = tdi->tmpnode->next;
275d65f6f70SBen Gras 		while (tmp->next && tmp->next != td) {
276d65f6f70SBen Gras 			tmp = tmp->next;
277d65f6f70SBen Gras 		}
278d65f6f70SBen Gras 		if (tmp->next) {
279d65f6f70SBen Gras 			tmp->next = td->next;
280d65f6f70SBen Gras 		}
281d65f6f70SBen Gras 	}
282d65f6f70SBen Gras }
283d65f6f70SBen Gras 
28484d9c625SLionel Sambuc /* chfs_kill_td - removes all components of a temporary node */
285d65f6f70SBen Gras static void
chfs_kill_td(struct chfs_mount * chmp,struct chfs_tmp_dnode * td)286d65f6f70SBen Gras chfs_kill_td(struct chfs_mount *chmp,
287d65f6f70SBen Gras     struct chfs_tmp_dnode *td)
288d65f6f70SBen Gras {
28984d9c625SLionel Sambuc 	struct chfs_vnode_cache *vc;
29084d9c625SLionel Sambuc 	if (td->node) {
29184d9c625SLionel Sambuc 		mutex_enter(&chmp->chm_lock_vnocache);
29284d9c625SLionel Sambuc 		/* Remove the node from the vnode cache's data node chain. */
29384d9c625SLionel Sambuc 		vc = chfs_nref_to_vc(td->node->nref);
29484d9c625SLionel Sambuc 		chfs_remove_and_obsolete(chmp, vc, td->node->nref, &vc->dnode);
29584d9c625SLionel Sambuc 		mutex_exit(&chmp->chm_lock_vnocache);
296d65f6f70SBen Gras 	}
297d65f6f70SBen Gras 
298d65f6f70SBen Gras 	chfs_free_tmp_dnode(td);
299d65f6f70SBen Gras }
300d65f6f70SBen Gras 
30184d9c625SLionel Sambuc /* chfs_kill_tdi - removes a temporary node descriptor */
302d65f6f70SBen Gras static void
chfs_kill_tdi(struct chfs_mount * chmp,struct chfs_tmp_dnode_info * tdi)303d65f6f70SBen Gras chfs_kill_tdi(struct chfs_mount *chmp,
304d65f6f70SBen Gras     struct chfs_tmp_dnode_info *tdi)
305d65f6f70SBen Gras {
306d65f6f70SBen Gras 	struct chfs_tmp_dnode *next, *tmp = tdi->tmpnode;
307d65f6f70SBen Gras 
30884d9c625SLionel Sambuc 	/* Iterate the chain and remove all temporary node from it. */
309d65f6f70SBen Gras 	while (tmp) {
310d65f6f70SBen Gras 		next = tmp->next;
311d65f6f70SBen Gras 		chfs_kill_td(chmp, tmp);
312d65f6f70SBen Gras 		tmp = next;
313d65f6f70SBen Gras 	}
314d65f6f70SBen Gras 
315d65f6f70SBen Gras 	chfs_free_tmp_dnode_info(tdi);
316d65f6f70SBen Gras }
317d65f6f70SBen Gras 
31884d9c625SLionel Sambuc /*
31984d9c625SLionel Sambuc  * chfs_add_tmp_dnode_to_tree -
32084d9c625SLionel Sambuc  * adds a temporary node to the temporary tree
32184d9c625SLionel Sambuc  */
322d65f6f70SBen Gras int
chfs_add_tmp_dnode_to_tree(struct chfs_mount * chmp,struct chfs_readinode_info * rii,struct chfs_tmp_dnode * newtd)323d65f6f70SBen Gras chfs_add_tmp_dnode_to_tree(struct chfs_mount *chmp,
324d65f6f70SBen Gras     struct chfs_readinode_info *rii,
325d65f6f70SBen Gras     struct chfs_tmp_dnode *newtd)
326d65f6f70SBen Gras {
327d65f6f70SBen Gras 	uint64_t end_ofs = newtd->node->ofs + newtd->node->size;
328d65f6f70SBen Gras 	struct chfs_tmp_dnode_info *this;
329d65f6f70SBen Gras 	struct rb_node *node, *prev_node;
330d65f6f70SBen Gras 	struct chfs_tmp_dnode_info *newtdi;
331d65f6f70SBen Gras 
332d65f6f70SBen Gras 	node = rb_tree_find_node(&rii->tdi_root, &newtd->node->ofs);
333d65f6f70SBen Gras 	if (node) {
334d65f6f70SBen Gras 		this = (struct chfs_tmp_dnode_info *)node;
335d65f6f70SBen Gras 		while (this->tmpnode->overlapped) {
336d65f6f70SBen Gras 			prev_node = rb_tree_iterate(&rii->tdi_root, node, RB_DIR_LEFT);
337d65f6f70SBen Gras 			if (!prev_node) {
338d65f6f70SBen Gras 				this->tmpnode->overlapped = 0;
339d65f6f70SBen Gras 				break;
340d65f6f70SBen Gras 			}
341d65f6f70SBen Gras 			node = prev_node;
342d65f6f70SBen Gras 			this = (struct chfs_tmp_dnode_info *)node;
343d65f6f70SBen Gras 		}
344d65f6f70SBen Gras 	}
34584d9c625SLionel Sambuc 
346d65f6f70SBen Gras 	while (node) {
347d65f6f70SBen Gras 		this = (struct chfs_tmp_dnode_info *)node;
348d65f6f70SBen Gras 		if (this->tmpnode->node->ofs > end_ofs)
349d65f6f70SBen Gras 			break;
350d65f6f70SBen Gras 
351d65f6f70SBen Gras 		struct chfs_tmp_dnode *tmp_td = this->tmpnode;
352d65f6f70SBen Gras 		while (tmp_td) {
353d65f6f70SBen Gras 			if (tmp_td->version == newtd->version) {
35484d9c625SLionel Sambuc 				/* This is a new version of an old node. */
355d65f6f70SBen Gras 				if (!chfs_check_td_node(chmp, tmp_td)) {
356d65f6f70SBen Gras 					dbg("calling kill td 0\n");
357d65f6f70SBen Gras 					chfs_kill_td(chmp, newtd);
358d65f6f70SBen Gras 					return 0;
359d65f6f70SBen Gras 				} else {
360d65f6f70SBen Gras 					chfs_remove_tmp_dnode_from_tdi(this, tmp_td);
361d65f6f70SBen Gras 					chfs_kill_td(chmp, tmp_td);
362d65f6f70SBen Gras 					chfs_add_tmp_dnode_to_tdi(this, newtd);
363d65f6f70SBen Gras 					return 0;
364d65f6f70SBen Gras 				}
365d65f6f70SBen Gras 			}
366d65f6f70SBen Gras 			if (tmp_td->version < newtd->version &&
367d65f6f70SBen Gras 				tmp_td->node->ofs >= newtd->node->ofs &&
368d65f6f70SBen Gras 				tmp_td->node->ofs + tmp_td->node->size <= end_ofs) {
369d65f6f70SBen Gras 				/* New node entirely overlaps 'this' */
370d65f6f70SBen Gras 				if (chfs_check_td_node(chmp, newtd)) {
371d65f6f70SBen Gras 					dbg("calling kill td 2\n");
372d65f6f70SBen Gras 					chfs_kill_td(chmp, newtd);
373d65f6f70SBen Gras 					return 0;
374d65f6f70SBen Gras 				}
375d65f6f70SBen Gras 				/* ... and is good. Kill 'this' and any subsequent nodes which are also overlapped */
376d65f6f70SBen Gras 				while (tmp_td && tmp_td->node->ofs + tmp_td->node->size <= end_ofs) {
377d65f6f70SBen Gras 					struct rb_node *next = rb_tree_iterate(&rii->tdi_root, this, RB_DIR_RIGHT);
378d65f6f70SBen Gras 					struct chfs_tmp_dnode_info *next_tdi = (struct chfs_tmp_dnode_info *)next;
379d65f6f70SBen Gras 					struct chfs_tmp_dnode *next_td = NULL;
380d65f6f70SBen Gras 					if (tmp_td->next) {
381d65f6f70SBen Gras 						next_td = tmp_td->next;
382d65f6f70SBen Gras 					} else if (next_tdi) {
383d65f6f70SBen Gras 						next_td = next_tdi->tmpnode;
384d65f6f70SBen Gras 					}
385d65f6f70SBen Gras 					if (tmp_td->version < newtd->version) {
386d65f6f70SBen Gras 						chfs_remove_tmp_dnode_from_tdi(this, tmp_td);
387d65f6f70SBen Gras 						chfs_kill_td(chmp, tmp_td);
388d65f6f70SBen Gras 						if (!this->tmpnode) {
389d65f6f70SBen Gras 							rb_tree_remove_node(&rii->tdi_root, this);
390d65f6f70SBen Gras 							chfs_kill_tdi(chmp, this);
391d65f6f70SBen Gras 							this = next_tdi;
392d65f6f70SBen Gras 						}
393d65f6f70SBen Gras 					}
394d65f6f70SBen Gras 					tmp_td = next_td;
395d65f6f70SBen Gras 				}
396d65f6f70SBen Gras 				continue;
397d65f6f70SBen Gras 			}
398d65f6f70SBen Gras 			if (tmp_td->version > newtd->version &&
399d65f6f70SBen Gras 				tmp_td->node->ofs <= newtd->node->ofs &&
400d65f6f70SBen Gras 				tmp_td->node->ofs + tmp_td->node->size >= end_ofs) {
401d65f6f70SBen Gras 				/* New node entirely overlapped by 'this' */
402d65f6f70SBen Gras 				if (!chfs_check_td_node(chmp, tmp_td)) {
403d65f6f70SBen Gras 					dbg("this version: %llu\n",
404d65f6f70SBen Gras 						(unsigned long long)tmp_td->version);
405d65f6f70SBen Gras 					dbg("this ofs: %llu, size: %u\n",
406d65f6f70SBen Gras 						(unsigned long long)tmp_td->node->ofs,
407d65f6f70SBen Gras 						tmp_td->node->size);
408d65f6f70SBen Gras 					dbg("calling kill td 4\n");
409d65f6f70SBen Gras 					chfs_kill_td(chmp, newtd);
410d65f6f70SBen Gras 					return 0;
411d65f6f70SBen Gras 				}
412d65f6f70SBen Gras 				/* ... but 'this' was bad. Replace it... */
413d65f6f70SBen Gras 				chfs_remove_tmp_dnode_from_tdi(this, tmp_td);
414d65f6f70SBen Gras 				chfs_kill_td(chmp, tmp_td);
415d65f6f70SBen Gras 				if (!this->tmpnode) {
416d65f6f70SBen Gras 					rb_tree_remove_node(&rii->tdi_root, this);
417d65f6f70SBen Gras 					chfs_kill_tdi(chmp, this);
418d65f6f70SBen Gras 				}
419d65f6f70SBen Gras 				dbg("calling kill td 5\n");
420d65f6f70SBen Gras 				chfs_kill_td(chmp, newtd);
421d65f6f70SBen Gras 				break;
422d65f6f70SBen Gras 			}
423d65f6f70SBen Gras 			tmp_td = tmp_td->next;
424d65f6f70SBen Gras 		}
425d65f6f70SBen Gras 		node = rb_tree_iterate(&rii->tdi_root, node, RB_DIR_RIGHT);
426d65f6f70SBen Gras 	}
427d65f6f70SBen Gras 
428d65f6f70SBen Gras 	newtdi = chfs_alloc_tmp_dnode_info();
429d65f6f70SBen Gras 	chfs_add_tmp_dnode_to_tdi(newtdi, newtd);
430d65f6f70SBen Gras 	/* We neither completely obsoleted nor were completely
431d65f6f70SBen Gras 	   obsoleted by an earlier node. Insert into the tree */
432d65f6f70SBen Gras 	struct chfs_tmp_dnode_info *tmp_tdi = rb_tree_insert_node(&rii->tdi_root, newtdi);
433d65f6f70SBen Gras 	if (tmp_tdi != newtdi) {
43484d9c625SLionel Sambuc 		chfs_remove_tmp_dnode_from_tdi(newtdi, newtd);
435d65f6f70SBen Gras 		chfs_add_tmp_dnode_to_tdi(tmp_tdi, newtd);
436d65f6f70SBen Gras 		chfs_kill_tdi(chmp, newtdi);
437d65f6f70SBen Gras 	}
438d65f6f70SBen Gras 
439d65f6f70SBen Gras 	/* If there's anything behind that overlaps us, note it */
440d65f6f70SBen Gras 	node = rb_tree_iterate(&rii->tdi_root, node, RB_DIR_LEFT);
441d65f6f70SBen Gras 	if (node) {
442d65f6f70SBen Gras 		while (1) {
443d65f6f70SBen Gras 			this = (struct chfs_tmp_dnode_info *)node;
444d65f6f70SBen Gras 			if (this->tmpnode->node->ofs + this->tmpnode->node->size > newtd->node->ofs) {
445d65f6f70SBen Gras 				newtd->overlapped = 1;
446d65f6f70SBen Gras 			}
447d65f6f70SBen Gras 			if (!this->tmpnode->overlapped)
448d65f6f70SBen Gras 				break;
449d65f6f70SBen Gras 
450d65f6f70SBen Gras 			prev_node = rb_tree_iterate(&rii->tdi_root, node, RB_DIR_LEFT);
451d65f6f70SBen Gras 			if (!prev_node) {
452d65f6f70SBen Gras 				this->tmpnode->overlapped = 0;
453d65f6f70SBen Gras 				break;
454d65f6f70SBen Gras 			}
455d65f6f70SBen Gras 			node = prev_node;
456d65f6f70SBen Gras 		}
457d65f6f70SBen Gras 	}
458d65f6f70SBen Gras 
459d65f6f70SBen Gras 	/* If the new node overlaps anything ahead, note it */
460d65f6f70SBen Gras 	node = rb_tree_iterate(&rii->tdi_root, node, RB_DIR_RIGHT);
461d65f6f70SBen Gras 	this = (struct chfs_tmp_dnode_info *)node;
462d65f6f70SBen Gras 	while (this && this->tmpnode->node->ofs < end_ofs) {
463d65f6f70SBen Gras 		this->tmpnode->overlapped = 1;
464d65f6f70SBen Gras 		node = rb_tree_iterate(&rii->tdi_root, node, RB_DIR_RIGHT);
465d65f6f70SBen Gras 		this = (struct chfs_tmp_dnode_info *)node;
466d65f6f70SBen Gras 	}
467d65f6f70SBen Gras 	return 0;
468d65f6f70SBen Gras }
469d65f6f70SBen Gras 
470d65f6f70SBen Gras 
47184d9c625SLionel Sambuc /* new_fragment - creates a new fragment for a data node */
472d65f6f70SBen Gras struct chfs_node_frag *
new_fragment(struct chfs_full_dnode * fdn,uint32_t ofs,uint32_t size)473d65f6f70SBen Gras new_fragment(struct chfs_full_dnode *fdn, uint32_t ofs, uint32_t size)
474d65f6f70SBen Gras {
475d65f6f70SBen Gras 	struct chfs_node_frag *newfrag;
476d65f6f70SBen Gras 	newfrag = chfs_alloc_node_frag();
477d65f6f70SBen Gras 	if (newfrag) {
47884d9c625SLionel Sambuc 		/* Initialize fragment. */
479d65f6f70SBen Gras 		newfrag->ofs = ofs;
480d65f6f70SBen Gras 		newfrag->size = size;
481d65f6f70SBen Gras 		newfrag->node = fdn;
48284d9c625SLionel Sambuc 		if (newfrag->node) {
48384d9c625SLionel Sambuc 			newfrag->node->frags++;
48484d9c625SLionel Sambuc 		}
485d65f6f70SBen Gras 	} else {
486d65f6f70SBen Gras 		chfs_err("cannot allocate a chfs_node_frag object\n");
487d65f6f70SBen Gras 	}
488d65f6f70SBen Gras 	return newfrag;
489d65f6f70SBen Gras }
490d65f6f70SBen Gras 
49184d9c625SLionel Sambuc /*
49284d9c625SLionel Sambuc  * no_overlapping_node - inserts a node to the fragtree
49384d9c625SLionel Sambuc  * Puts hole frag into the holes between fragments.
49484d9c625SLionel Sambuc  */
495d65f6f70SBen Gras int
no_overlapping_node(struct rb_tree * fragtree,struct chfs_node_frag * newfrag,struct chfs_node_frag * this,uint32_t lastend)496d65f6f70SBen Gras no_overlapping_node(struct rb_tree *fragtree,
497d65f6f70SBen Gras     struct chfs_node_frag *newfrag,
498d65f6f70SBen Gras     struct chfs_node_frag *this, uint32_t lastend)
499d65f6f70SBen Gras {
500d65f6f70SBen Gras 	if (lastend < newfrag->node->ofs) {
501d65f6f70SBen Gras 		struct chfs_node_frag *holefrag;
502d65f6f70SBen Gras 
503d65f6f70SBen Gras 		holefrag = new_fragment(NULL, lastend, newfrag->node->ofs - lastend);
504d65f6f70SBen Gras 		if (!holefrag) {
505d65f6f70SBen Gras 			chfs_free_node_frag(newfrag);
506d65f6f70SBen Gras 			return ENOMEM;
507d65f6f70SBen Gras 		}
508d65f6f70SBen Gras 
509d65f6f70SBen Gras 		rb_tree_insert_node(fragtree, holefrag);
510d65f6f70SBen Gras 	}
511d65f6f70SBen Gras 
512d65f6f70SBen Gras 	rb_tree_insert_node(fragtree, newfrag);
513d65f6f70SBen Gras 
514d65f6f70SBen Gras 	return 0;
515d65f6f70SBen Gras }
516d65f6f70SBen Gras 
51784d9c625SLionel Sambuc /*
51884d9c625SLionel Sambuc  * chfs_add_frag_to_fragtree -
51984d9c625SLionel Sambuc  * adds a fragment to a data node's fragtree
52084d9c625SLionel Sambuc  */
521d65f6f70SBen Gras int
chfs_add_frag_to_fragtree(struct chfs_mount * chmp,struct rb_tree * fragtree,struct chfs_node_frag * newfrag)522d65f6f70SBen Gras chfs_add_frag_to_fragtree(struct chfs_mount *chmp,
523d65f6f70SBen Gras     struct rb_tree *fragtree,
524d65f6f70SBen Gras     struct chfs_node_frag *newfrag)
525d65f6f70SBen Gras {
526d65f6f70SBen Gras 	struct chfs_node_frag *this;
527d65f6f70SBen Gras 	uint32_t lastend;
528d65f6f70SBen Gras 	KASSERT(mutex_owned(&chmp->chm_lock_mountfields));
529d65f6f70SBen Gras 
53084d9c625SLionel Sambuc 	/* Find the offset of frag which is before the new one. */
531d65f6f70SBen Gras 	this = (struct chfs_node_frag *)rb_tree_find_node_leq(fragtree, &newfrag->ofs);
532d65f6f70SBen Gras 
533d65f6f70SBen Gras 	if (this) {
534d65f6f70SBen Gras 		lastend = this->ofs + this->size;
535d65f6f70SBen Gras 	} else {
536d65f6f70SBen Gras 		lastend = 0;
537d65f6f70SBen Gras 	}
538d65f6f70SBen Gras 
53984d9c625SLionel Sambuc 	/* New fragment is end of the file and there is no overlapping. */
540d65f6f70SBen Gras 	if (lastend <= newfrag->ofs) {
541d65f6f70SBen Gras 		if (lastend && (lastend - 1) >> PAGE_SHIFT == newfrag->ofs >> PAGE_SHIFT) {
542d65f6f70SBen Gras 			if (this->node)
543d65f6f70SBen Gras 				CHFS_MARK_REF_NORMAL(this->node->nref);
544d65f6f70SBen Gras 			CHFS_MARK_REF_NORMAL(newfrag->node->nref);
545d65f6f70SBen Gras 		}
546d65f6f70SBen Gras 		return no_overlapping_node(fragtree, newfrag, this, lastend);
547d65f6f70SBen Gras 	}
548d65f6f70SBen Gras 
549d65f6f70SBen Gras 	if (newfrag->ofs > this->ofs) {
550d65f6f70SBen Gras 		CHFS_MARK_REF_NORMAL(newfrag->node->nref);
551d65f6f70SBen Gras 		if (this->node)
552d65f6f70SBen Gras 			CHFS_MARK_REF_NORMAL(this->node->nref);
553d65f6f70SBen Gras 
554d65f6f70SBen Gras 		if (this->ofs + this->size > newfrag->ofs + newfrag->size) {
55584d9c625SLionel Sambuc 			/* Newfrag is inside of this. */
556d65f6f70SBen Gras 			struct chfs_node_frag *newfrag2;
557d65f6f70SBen Gras 
558d65f6f70SBen Gras 			newfrag2 = new_fragment(this->node, newfrag->ofs + newfrag->size,
559d65f6f70SBen Gras 			    this->ofs + this->size - newfrag->ofs - newfrag->size);
560d65f6f70SBen Gras 			if (!newfrag2)
561d65f6f70SBen Gras 				return ENOMEM;
562d65f6f70SBen Gras 
563d65f6f70SBen Gras 			this->size = newfrag->ofs - this->ofs;
564d65f6f70SBen Gras 
565d65f6f70SBen Gras 			rb_tree_insert_node(fragtree, newfrag);
566d65f6f70SBen Gras 			rb_tree_insert_node(fragtree, newfrag2);
567d65f6f70SBen Gras 
568d65f6f70SBen Gras 			return 0;
569d65f6f70SBen Gras 		}
57084d9c625SLionel Sambuc 		/* Newfrag is bottom of this. */
571d65f6f70SBen Gras 		this->size = newfrag->ofs - this->ofs;
572d65f6f70SBen Gras 		rb_tree_insert_node(fragtree, newfrag);
573d65f6f70SBen Gras 	} else {
57484d9c625SLionel Sambuc 		/* Newfrag start at same point */
575d65f6f70SBen Gras 		//TODO replace instead of remove and insert
576d65f6f70SBen Gras 		rb_tree_remove_node(fragtree, this);
577d65f6f70SBen Gras 		rb_tree_insert_node(fragtree, newfrag);
578d65f6f70SBen Gras 
579d65f6f70SBen Gras 		if (newfrag->ofs + newfrag->size >= this->ofs+this->size) {
580d65f6f70SBen Gras 			chfs_obsolete_node_frag(chmp, this);
581d65f6f70SBen Gras 		} else {
582d65f6f70SBen Gras 			this->ofs += newfrag->size;
583d65f6f70SBen Gras 			this->size -= newfrag->size;
584d65f6f70SBen Gras 
585d65f6f70SBen Gras 			rb_tree_insert_node(fragtree, this);
586d65f6f70SBen Gras 			return 0;
587d65f6f70SBen Gras 		}
588d65f6f70SBen Gras 	}
589d65f6f70SBen Gras 	/* OK, now we have newfrag added in the correct place in the tree, but
590d65f6f70SBen Gras 	   frag_next(newfrag) may be a fragment which is overlapped by it
591d65f6f70SBen Gras 	*/
592d65f6f70SBen Gras 	while ((this = frag_next(fragtree, newfrag)) && newfrag->ofs + newfrag->size >= this->ofs + this->size) {
593d65f6f70SBen Gras 		rb_tree_remove_node(fragtree, this);
594d65f6f70SBen Gras 		chfs_obsolete_node_frag(chmp, this);
595d65f6f70SBen Gras 	}
596d65f6f70SBen Gras 
597d65f6f70SBen Gras 	if (!this || newfrag->ofs + newfrag->size == this->ofs)
598d65f6f70SBen Gras 		return 0;
599d65f6f70SBen Gras 
600d65f6f70SBen Gras 	this->size = (this->ofs + this->size) - (newfrag->ofs + newfrag->size);
601d65f6f70SBen Gras 	this->ofs = newfrag->ofs + newfrag->size;
602d65f6f70SBen Gras 
603d65f6f70SBen Gras 	if (this->node)
604d65f6f70SBen Gras 		CHFS_MARK_REF_NORMAL(this->node->nref);
605d65f6f70SBen Gras 	CHFS_MARK_REF_NORMAL(newfrag->node->nref);
606d65f6f70SBen Gras 
607d65f6f70SBen Gras 	return 0;
608d65f6f70SBen Gras }
609d65f6f70SBen Gras 
61084d9c625SLionel Sambuc /*
61184d9c625SLionel Sambuc  * chfs_remove_frags_of_node -
61284d9c625SLionel Sambuc  * removes all fragments from a fragtree and DOESN'T OBSOLETE them
61384d9c625SLionel Sambuc  */
614d65f6f70SBen Gras void
chfs_remove_frags_of_node(struct chfs_mount * chmp,struct rb_tree * fragtree,struct chfs_node_ref * nref)61584d9c625SLionel Sambuc chfs_remove_frags_of_node(struct chfs_mount *chmp, struct rb_tree *fragtree,
61684d9c625SLionel Sambuc 	struct chfs_node_ref *nref)
617d65f6f70SBen Gras {
61884d9c625SLionel Sambuc 	KASSERT(mutex_owned(&chmp->chm_lock_mountfields));
619d65f6f70SBen Gras 	struct chfs_node_frag *this, *next;
620d65f6f70SBen Gras 
62184d9c625SLionel Sambuc 	if (nref == NULL) {
62284d9c625SLionel Sambuc 		return;
62384d9c625SLionel Sambuc 	}
62484d9c625SLionel Sambuc 
62584d9c625SLionel Sambuc 	/* Iterate the tree and clean all elements. */
626d65f6f70SBen Gras 	this = (struct chfs_node_frag *)RB_TREE_MIN(fragtree);
627d65f6f70SBen Gras 	while (this) {
628d65f6f70SBen Gras 		next = frag_next(fragtree, this);
62984d9c625SLionel Sambuc 		if (this->node->nref == nref) {
630d65f6f70SBen Gras 			rb_tree_remove_node(fragtree, this);
631d65f6f70SBen Gras 			chfs_free_node_frag(this);
63284d9c625SLionel Sambuc 		}
633d65f6f70SBen Gras 		this = next;
634d65f6f70SBen Gras 	}
635d65f6f70SBen Gras }
636d65f6f70SBen Gras 
63784d9c625SLionel Sambuc /*
63884d9c625SLionel Sambuc  * chfs_kill_fragtree -
63984d9c625SLionel Sambuc  * removes all fragments from a fragtree and OBSOLETES them
64084d9c625SLionel Sambuc  */
64184d9c625SLionel Sambuc void
chfs_kill_fragtree(struct chfs_mount * chmp,struct rb_tree * fragtree)64284d9c625SLionel Sambuc chfs_kill_fragtree(struct chfs_mount *chmp, struct rb_tree *fragtree)
64384d9c625SLionel Sambuc {
64484d9c625SLionel Sambuc 	KASSERT(mutex_owned(&chmp->chm_lock_mountfields));
64584d9c625SLionel Sambuc 	struct chfs_node_frag *this, *next;
64684d9c625SLionel Sambuc 
64784d9c625SLionel Sambuc 	/* Iterate the tree and clean all elements. */
64884d9c625SLionel Sambuc 	this = (struct chfs_node_frag *)RB_TREE_MIN(fragtree);
64984d9c625SLionel Sambuc 	while (this) {
65084d9c625SLionel Sambuc 		next = frag_next(fragtree, this);
65184d9c625SLionel Sambuc 		rb_tree_remove_node(fragtree, this);
65284d9c625SLionel Sambuc 		chfs_obsolete_node_frag(chmp, this);
65384d9c625SLionel Sambuc 		this = next;
65484d9c625SLionel Sambuc 	}
65584d9c625SLionel Sambuc }
65684d9c625SLionel Sambuc 
65784d9c625SLionel Sambuc /* chfs_truncate_fragtree - truncates the tree to a specified size */
658d65f6f70SBen Gras uint32_t
chfs_truncate_fragtree(struct chfs_mount * chmp,struct rb_tree * fragtree,uint32_t size)659d65f6f70SBen Gras chfs_truncate_fragtree(struct chfs_mount *chmp,
660d65f6f70SBen Gras 	struct rb_tree *fragtree, uint32_t size)
661d65f6f70SBen Gras {
662d65f6f70SBen Gras 	KASSERT(mutex_owned(&chmp->chm_lock_mountfields));
66384d9c625SLionel Sambuc 	struct chfs_node_frag *frag;
664d65f6f70SBen Gras 
665d65f6f70SBen Gras 	dbg("truncate to size: %u\n", size);
666d65f6f70SBen Gras 
667d65f6f70SBen Gras 	frag = (struct chfs_node_frag *)rb_tree_find_node_leq(fragtree, &size);
668d65f6f70SBen Gras 
669d65f6f70SBen Gras 	/* Find the last frag before size and set its new size. */
670d65f6f70SBen Gras 	if (frag && frag->ofs != size) {
671d65f6f70SBen Gras 		if (frag->ofs + frag->size > size) {
672d65f6f70SBen Gras 			frag->size = size - frag->ofs;
673d65f6f70SBen Gras 		}
674d65f6f70SBen Gras 		frag = frag_next(fragtree, frag);
675d65f6f70SBen Gras 	}
676d65f6f70SBen Gras 
677d65f6f70SBen Gras 	/* Delete frags after new size. */
678d65f6f70SBen Gras 	while (frag && frag->ofs >= size) {
679d65f6f70SBen Gras 		struct chfs_node_frag *next = frag_next(fragtree, frag);
680d65f6f70SBen Gras 
681d65f6f70SBen Gras 		rb_tree_remove_node(fragtree, frag);
682d65f6f70SBen Gras 		chfs_obsolete_node_frag(chmp, frag);
683d65f6f70SBen Gras 		frag = next;
684d65f6f70SBen Gras 	}
685d65f6f70SBen Gras 
686d65f6f70SBen Gras 	if (size == 0) {
687d65f6f70SBen Gras 		return 0;
688d65f6f70SBen Gras 	}
689d65f6f70SBen Gras 
690d65f6f70SBen Gras 	frag = frag_last(fragtree);
691d65f6f70SBen Gras 
692d65f6f70SBen Gras 	if (!frag) {
693d65f6f70SBen Gras 		return 0;
694d65f6f70SBen Gras 	}
695d65f6f70SBen Gras 
696d65f6f70SBen Gras 	if (frag->ofs + frag->size < size) {
697d65f6f70SBen Gras 		return frag->ofs + frag->size;
698d65f6f70SBen Gras 	}
699d65f6f70SBen Gras 
700d65f6f70SBen Gras 	/* FIXME Should we check the postion of the last node? (PAGE_CACHE size, etc.) */
701d65f6f70SBen Gras 	if (frag->node && (frag->ofs & (PAGE_SIZE - 1)) == 0) {
70284d9c625SLionel Sambuc 		frag->node->nref->nref_offset =
70384d9c625SLionel Sambuc 			CHFS_GET_OFS(frag->node->nref->nref_offset) | CHFS_PRISTINE_NODE_MASK;
704d65f6f70SBen Gras 	}
705d65f6f70SBen Gras 
706d65f6f70SBen Gras 	return size;
707d65f6f70SBen Gras }
708d65f6f70SBen Gras 
70984d9c625SLionel Sambuc /* chfs_obsolete_node_frag - obsoletes a fragment of a node */
710d65f6f70SBen Gras void
chfs_obsolete_node_frag(struct chfs_mount * chmp,struct chfs_node_frag * this)711d65f6f70SBen Gras chfs_obsolete_node_frag(struct chfs_mount *chmp,
712d65f6f70SBen Gras     struct chfs_node_frag *this)
713d65f6f70SBen Gras {
71484d9c625SLionel Sambuc 	struct chfs_vnode_cache *vc;
715d65f6f70SBen Gras 	KASSERT(mutex_owned(&chmp->chm_lock_mountfields));
716d65f6f70SBen Gras 	if (this->node) {
71784d9c625SLionel Sambuc 	/* The fragment is in a node. */
71884d9c625SLionel Sambuc 		KASSERT(this->node->frags != 0);
719d65f6f70SBen Gras 		this->node->frags--;
72084d9c625SLionel Sambuc 		if (this->node->frags == 0) {
72184d9c625SLionel Sambuc 		/* This is the last fragment. (There is no more.) */
72284d9c625SLionel Sambuc 			KASSERT(!CHFS_REF_OBSOLETE(this->node->nref));
72384d9c625SLionel Sambuc 			mutex_enter(&chmp->chm_lock_vnocache);
72484d9c625SLionel Sambuc 			vc = chfs_nref_to_vc(this->node->nref);
72584d9c625SLionel Sambuc 			dbg("[MARK] lnr: %u ofs: %u\n", this->node->nref->nref_lnr,
72684d9c625SLionel Sambuc 				this->node->nref->nref_offset);
727d65f6f70SBen Gras 
72884d9c625SLionel Sambuc 			chfs_remove_and_obsolete(chmp, vc, this->node->nref, &vc->dnode);
72984d9c625SLionel Sambuc 			mutex_exit(&chmp->chm_lock_vnocache);
730d65f6f70SBen Gras 
731d65f6f70SBen Gras 			chfs_free_full_dnode(this->node);
732d65f6f70SBen Gras 		} else {
73384d9c625SLionel Sambuc 		/* There is more frags in the node. */
734d65f6f70SBen Gras 			CHFS_MARK_REF_NORMAL(this->node->nref);
735d65f6f70SBen Gras 		}
736d65f6f70SBen Gras 	}
737d65f6f70SBen Gras 	chfs_free_node_frag(this);
738d65f6f70SBen Gras }
739d65f6f70SBen Gras 
74084d9c625SLionel Sambuc /* chfs_add_full_dnode_to_inode - adds a data node to an inode */
741d65f6f70SBen Gras int
chfs_add_full_dnode_to_inode(struct chfs_mount * chmp,struct chfs_inode * ip,struct chfs_full_dnode * fd)742d65f6f70SBen Gras chfs_add_full_dnode_to_inode(struct chfs_mount *chmp,
743d65f6f70SBen Gras     struct chfs_inode *ip,
744d65f6f70SBen Gras     struct chfs_full_dnode *fd)
745d65f6f70SBen Gras {
746d65f6f70SBen Gras 	int ret;
747d65f6f70SBen Gras 	struct chfs_node_frag *newfrag;
748d65f6f70SBen Gras 	KASSERT(mutex_owned(&chmp->chm_lock_mountfields));
749d65f6f70SBen Gras 
750d65f6f70SBen Gras 	if (unlikely(!fd->size))
751d65f6f70SBen Gras 		return 0;
752d65f6f70SBen Gras 
75384d9c625SLionel Sambuc 	/* Create a new fragment from the data node and add it to the fragtree. */
754d65f6f70SBen Gras 	newfrag = new_fragment(fd, fd->ofs, fd->size);
755d65f6f70SBen Gras 	if (unlikely(!newfrag))
756d65f6f70SBen Gras 		return ENOMEM;
757d65f6f70SBen Gras 
758d65f6f70SBen Gras 	ret = chfs_add_frag_to_fragtree(chmp, &ip->fragtree, newfrag);
759d65f6f70SBen Gras 	if (ret)
760d65f6f70SBen Gras 		return ret;
761d65f6f70SBen Gras 
76284d9c625SLionel Sambuc 	/* Check previous fragment. */
763d65f6f70SBen Gras 	if (newfrag->ofs & (PAGE_SIZE - 1)) {
764d65f6f70SBen Gras 		struct chfs_node_frag *prev = frag_prev(&ip->fragtree, newfrag);
765d65f6f70SBen Gras 
766d65f6f70SBen Gras 		CHFS_MARK_REF_NORMAL(fd->nref);
767d65f6f70SBen Gras 		if (prev->node)
768d65f6f70SBen Gras 			CHFS_MARK_REF_NORMAL(prev->node->nref);
769d65f6f70SBen Gras 	}
770d65f6f70SBen Gras 
77184d9c625SLionel Sambuc 	/* Check next fragment. */
772d65f6f70SBen Gras 	if ((newfrag->ofs+newfrag->size) & (PAGE_SIZE - 1)) {
773d65f6f70SBen Gras 		struct chfs_node_frag *next = frag_next(&ip->fragtree, newfrag);
774d65f6f70SBen Gras 
775d65f6f70SBen Gras 		if (next) {
776d65f6f70SBen Gras 			CHFS_MARK_REF_NORMAL(fd->nref);
777d65f6f70SBen Gras 			if (next->node)
778d65f6f70SBen Gras 				CHFS_MARK_REF_NORMAL(next->node->nref);
779d65f6f70SBen Gras 		}
780d65f6f70SBen Gras 	}
781d65f6f70SBen Gras 
782d65f6f70SBen Gras 	return 0;
783d65f6f70SBen Gras }
784d65f6f70SBen Gras 
785d65f6f70SBen Gras 
78684d9c625SLionel Sambuc /* chfs_get_data_nodes - get temporary nodes of an inode */
787d65f6f70SBen Gras int
chfs_get_data_nodes(struct chfs_mount * chmp,struct chfs_inode * ip,struct chfs_readinode_info * rii)788d65f6f70SBen Gras chfs_get_data_nodes(struct chfs_mount *chmp,
789d65f6f70SBen Gras     struct chfs_inode *ip,
790d65f6f70SBen Gras     struct chfs_readinode_info *rii)
791d65f6f70SBen Gras {
792d65f6f70SBen Gras 	uint32_t crc;
793d65f6f70SBen Gras 	int err;
794d65f6f70SBen Gras 	size_t len, retlen;
795d65f6f70SBen Gras 	struct chfs_node_ref *nref;
796d65f6f70SBen Gras 	struct chfs_flash_data_node *dnode;
797d65f6f70SBen Gras 	struct chfs_tmp_dnode *td;
798d65f6f70SBen Gras 	char* buf;
799d65f6f70SBen Gras 
800d65f6f70SBen Gras 	len = sizeof(struct chfs_flash_data_node);
801d65f6f70SBen Gras 	buf = kmem_alloc(len, KM_SLEEP);
802d65f6f70SBen Gras 
803d65f6f70SBen Gras 	dnode = kmem_alloc(len, KM_SLEEP);
804*0a6a1f1dSLionel Sambuc 	if (!dnode) {
805*0a6a1f1dSLionel Sambuc 		kmem_free(buf, len);
806d65f6f70SBen Gras 		return ENOMEM;
807*0a6a1f1dSLionel Sambuc 	}
808d65f6f70SBen Gras 
809d65f6f70SBen Gras 	nref = chfs_first_valid_data_ref(ip->chvc->dnode);
810d65f6f70SBen Gras 
81184d9c625SLionel Sambuc 	/* Update highest version. */
812d65f6f70SBen Gras 	rii->highest_version = ip->chvc->highest_version;
813d65f6f70SBen Gras 
814d65f6f70SBen Gras 	while(nref && (struct chfs_vnode_cache *)nref != ip->chvc) {
815d65f6f70SBen Gras 		err = chfs_read_leb(chmp, nref->nref_lnr, buf, CHFS_GET_OFS(nref->nref_offset), len, &retlen);
816d65f6f70SBen Gras 		if (err || len != retlen)
817d65f6f70SBen Gras 			goto out;
818d65f6f70SBen Gras 		dnode = (struct chfs_flash_data_node*)buf;
819d65f6f70SBen Gras 
82084d9c625SLionel Sambuc 		/* Check header crc. */
821d65f6f70SBen Gras 		crc = crc32(0, (uint8_t *)dnode, CHFS_NODE_HDR_SIZE - 4);
822d65f6f70SBen Gras 		if (crc != le32toh(dnode->hdr_crc)) {
823d65f6f70SBen Gras 			chfs_err("CRC check failed. calc: 0x%x orig: 0x%x\n", crc, le32toh(dnode->hdr_crc));
824d65f6f70SBen Gras 			goto cont;
825d65f6f70SBen Gras 		}
82684d9c625SLionel Sambuc 
82784d9c625SLionel Sambuc 		/* Check header magic bitmask. */
828d65f6f70SBen Gras 		if (le16toh(dnode->magic) != CHFS_FS_MAGIC_BITMASK) {
829d65f6f70SBen Gras 			chfs_err("Wrong magic bitmask.\n");
830d65f6f70SBen Gras 			goto cont;
831d65f6f70SBen Gras 		}
83284d9c625SLionel Sambuc 
83384d9c625SLionel Sambuc 		/* Check node crc. */
834d65f6f70SBen Gras 		crc = crc32(0, (uint8_t *)dnode, sizeof(*dnode) - 4);
835d65f6f70SBen Gras 		if (crc != le32toh(dnode->node_crc)) {
836d65f6f70SBen Gras 			chfs_err("Node CRC check failed. calc: 0x%x orig: 0x%x\n", crc, le32toh(dnode->node_crc));
837d65f6f70SBen Gras 			goto cont;
838d65f6f70SBen Gras 		}
83984d9c625SLionel Sambuc 
840d65f6f70SBen Gras 		td = chfs_alloc_tmp_dnode();
841d65f6f70SBen Gras 		if (!td) {
842d65f6f70SBen Gras 			chfs_err("Can't allocate tmp dnode info.\n");
843d65f6f70SBen Gras 			err = ENOMEM;
844d65f6f70SBen Gras 			goto out;
845d65f6f70SBen Gras 		}
84684d9c625SLionel Sambuc 
847d65f6f70SBen Gras 		/* We don't check data crc here, just add nodes to tmp frag tree, because
848d65f6f70SBen Gras 		 * we don't want to check nodes which have been overlapped by a new node
849d65f6f70SBen Gras 		 * with a higher version number.
850d65f6f70SBen Gras 		 */
851d65f6f70SBen Gras 		td->node = chfs_alloc_full_dnode();
852d65f6f70SBen Gras 		if (!td->node) {
853d65f6f70SBen Gras 			chfs_err("Can't allocate full dnode info.\n");
854d65f6f70SBen Gras 			err = ENOMEM;
855d65f6f70SBen Gras 			goto out_tmp_dnode;
856d65f6f70SBen Gras 		}
857d65f6f70SBen Gras 		td->version = le64toh(dnode->version);
858d65f6f70SBen Gras 		td->node->ofs = le64toh(dnode->offset);
859d65f6f70SBen Gras 		td->data_crc = le32toh(dnode->data_crc);
860d65f6f70SBen Gras 		td->node->nref = nref;
861d65f6f70SBen Gras 		td->node->size = le32toh(dnode->data_length);
86284d9c625SLionel Sambuc 		td->node->frags = 1;
863d65f6f70SBen Gras 		td->overlapped = 0;
864d65f6f70SBen Gras 
865d65f6f70SBen Gras 		if (td->version > rii->highest_version) {
866d65f6f70SBen Gras 			rii->highest_version = td->version;
867d65f6f70SBen Gras 		}
868d65f6f70SBen Gras 
86984d9c625SLionel Sambuc 		/* Add node to the tree. */
870d65f6f70SBen Gras 		err = chfs_add_tmp_dnode_to_tree(chmp, rii, td);
871d65f6f70SBen Gras 		if (err)
872d65f6f70SBen Gras 			goto out_full_dnode;
873d65f6f70SBen Gras 
874d65f6f70SBen Gras cont:
875d65f6f70SBen Gras 		nref = chfs_first_valid_data_ref(nref->nref_next);
876d65f6f70SBen Gras 	}
877d65f6f70SBen Gras 
878d65f6f70SBen Gras 	ip->chvc->highest_version = rii->highest_version;
879d65f6f70SBen Gras 	return 0;
880d65f6f70SBen Gras 
881d65f6f70SBen Gras out_full_dnode:
882d65f6f70SBen Gras 	chfs_free_full_dnode(td->node);
883d65f6f70SBen Gras out_tmp_dnode:
884d65f6f70SBen Gras 	chfs_free_tmp_dnode(td);
885d65f6f70SBen Gras out:
886d65f6f70SBen Gras 	kmem_free(buf, len);
887d65f6f70SBen Gras 	kmem_free(dnode, len);
888d65f6f70SBen Gras 	return err;
889d65f6f70SBen Gras }
890d65f6f70SBen Gras 
891d65f6f70SBen Gras 
89284d9c625SLionel Sambuc /* chfs_build_fragtree - builds fragtree from temporary tree */
893d65f6f70SBen Gras int
chfs_build_fragtree(struct chfs_mount * chmp,struct chfs_inode * ip,struct chfs_readinode_info * rii)894d65f6f70SBen Gras chfs_build_fragtree(struct chfs_mount *chmp, struct chfs_inode *ip,
895d65f6f70SBen Gras     struct chfs_readinode_info *rii)
896d65f6f70SBen Gras {
897d65f6f70SBen Gras 	struct chfs_tmp_dnode_info *pen, *last, *this;
89884d9c625SLionel Sambuc 	struct rb_tree ver_tree;    /* version tree, used only temporary */
899d65f6f70SBen Gras 	uint64_t high_ver = 0;
900d65f6f70SBen Gras 	KASSERT(mutex_owned(&chmp->chm_lock_mountfields));
901d65f6f70SBen Gras 
902d65f6f70SBen Gras 	rb_tree_init(&ver_tree, &tmp_node_rbtree_ops);
903d65f6f70SBen Gras 
90484d9c625SLionel Sambuc 	/* Update highest version and latest node reference. */
905d65f6f70SBen Gras 	if (rii->mdata_tn) {
906d65f6f70SBen Gras 		high_ver = rii->mdata_tn->tmpnode->version;
907d65f6f70SBen Gras 		rii->latest_ref = rii->mdata_tn->tmpnode->node->nref;
908d65f6f70SBen Gras 	}
909d65f6f70SBen Gras 
91084d9c625SLionel Sambuc 	/* Iterate the temporary tree in reverse order. */
911d65f6f70SBen Gras 	pen = (struct chfs_tmp_dnode_info *)RB_TREE_MAX(&rii->tdi_root);
912d65f6f70SBen Gras 
913d65f6f70SBen Gras 	while((last = pen)) {
914d65f6f70SBen Gras 		pen = (struct chfs_tmp_dnode_info *)rb_tree_iterate(&rii->tdi_root, last, RB_DIR_LEFT);
915d65f6f70SBen Gras 
91684d9c625SLionel Sambuc 		/* We build here a version tree from overlapped nodes. */
917d65f6f70SBen Gras 		rb_tree_remove_node(&rii->tdi_root, last);
918d65f6f70SBen Gras 		rb_tree_insert_node(&ver_tree, last);
919d65f6f70SBen Gras 
920d65f6f70SBen Gras 		if (last->tmpnode->overlapped) {
921d65f6f70SBen Gras 			if (pen)
922d65f6f70SBen Gras 				continue;
923d65f6f70SBen Gras 
924d65f6f70SBen Gras 			last->tmpnode->overlapped = 0;
925d65f6f70SBen Gras 		}
926d65f6f70SBen Gras 
927d65f6f70SBen Gras 		this = (struct chfs_tmp_dnode_info *)RB_TREE_MAX(&ver_tree);
928d65f6f70SBen Gras 
92984d9c625SLionel Sambuc 		/* Start to build the fragtree. */
930d65f6f70SBen Gras 		while (this) {
931d65f6f70SBen Gras 			struct chfs_tmp_dnode_info *vers_next;
932d65f6f70SBen Gras 			int ret;
933d65f6f70SBen Gras 
934d65f6f70SBen Gras 			vers_next = (struct chfs_tmp_dnode_info *)rb_tree_iterate(&ver_tree, this, RB_DIR_LEFT);
935d65f6f70SBen Gras 			rb_tree_remove_node(&ver_tree, this);
936d65f6f70SBen Gras 
937d65f6f70SBen Gras 			struct chfs_tmp_dnode *tmp_td = this->tmpnode;
938d65f6f70SBen Gras 			while (tmp_td) {
939d65f6f70SBen Gras 				struct chfs_tmp_dnode *next_td = tmp_td->next;
940d65f6f70SBen Gras 
94184d9c625SLionel Sambuc 				/* Check temporary node. */
942d65f6f70SBen Gras 				if (chfs_check_td_node(chmp, tmp_td)) {
943d65f6f70SBen Gras 					if (next_td) {
944d65f6f70SBen Gras 						chfs_remove_tmp_dnode_from_tdi(this, tmp_td);
94584d9c625SLionel Sambuc 						chfs_kill_td(chmp, tmp_td);
946d65f6f70SBen Gras 					} else {
947d65f6f70SBen Gras 						break;
948d65f6f70SBen Gras 					}
949d65f6f70SBen Gras 				} else {
950d65f6f70SBen Gras 					if (tmp_td->version > high_ver) {
951d65f6f70SBen Gras 						high_ver = tmp_td->version;
952d65f6f70SBen Gras 						dbg("highver: %llu\n", (unsigned long long)high_ver);
953d65f6f70SBen Gras 						rii->latest_ref = tmp_td->node->nref;
954d65f6f70SBen Gras 					}
955d65f6f70SBen Gras 
95684d9c625SLionel Sambuc 					/* Add node to inode and its fragtree. */
957d65f6f70SBen Gras 					ret = chfs_add_full_dnode_to_inode(chmp, ip, tmp_td->node);
958d65f6f70SBen Gras 					if (ret) {
95984d9c625SLionel Sambuc 						/* On error, clean the whole version tree. */
960d65f6f70SBen Gras 						while (1) {
961d65f6f70SBen Gras 							vers_next = (struct chfs_tmp_dnode_info *)rb_tree_iterate(&ver_tree, this, RB_DIR_LEFT);
962d65f6f70SBen Gras 							while (tmp_td) {
963d65f6f70SBen Gras 								next_td = tmp_td->next;
96484d9c625SLionel Sambuc 
965d65f6f70SBen Gras 								chfs_free_full_dnode(tmp_td->node);
966d65f6f70SBen Gras 								chfs_remove_tmp_dnode_from_tdi(this, tmp_td);
96784d9c625SLionel Sambuc 								chfs_kill_td(chmp, tmp_td);
968d65f6f70SBen Gras 								tmp_td = next_td;
969d65f6f70SBen Gras 							}
970d65f6f70SBen Gras 							chfs_free_tmp_dnode_info(this);
971d65f6f70SBen Gras 							this = vers_next;
972d65f6f70SBen Gras 							if (!this)
973d65f6f70SBen Gras 								break;
974d65f6f70SBen Gras 							rb_tree_remove_node(&ver_tree, vers_next);
97584d9c625SLionel Sambuc 							chfs_kill_tdi(chmp, vers_next);
976d65f6f70SBen Gras 						}
977d65f6f70SBen Gras 						return ret;
978d65f6f70SBen Gras 					}
979d65f6f70SBen Gras 
98084d9c625SLionel Sambuc 					/* Remove temporary node from temporary descriptor.
98184d9c625SLionel Sambuc 					 * Shouldn't obsolete tmp_td here, because tmp_td->node
98284d9c625SLionel Sambuc 					 * was added to the inode. */
983d65f6f70SBen Gras 					chfs_remove_tmp_dnode_from_tdi(this, tmp_td);
984d65f6f70SBen Gras 					chfs_free_tmp_dnode(tmp_td);
985d65f6f70SBen Gras 				}
986d65f6f70SBen Gras 				tmp_td = next_td;
987d65f6f70SBen Gras 			}
98884d9c625SLionel Sambuc 			/* Continue with the previous element of version tree. */
989d65f6f70SBen Gras 			chfs_kill_tdi(chmp, this);
990d65f6f70SBen Gras 			this = vers_next;
991d65f6f70SBen Gras 		}
992d65f6f70SBen Gras 	}
993d65f6f70SBen Gras 
994d65f6f70SBen Gras 	return 0;
995d65f6f70SBen Gras }
996d65f6f70SBen Gras 
99784d9c625SLionel Sambuc /* chfs_read_inode - checks the state of the inode then reads and builds it */
chfs_read_inode(struct chfs_mount * chmp,struct chfs_inode * ip)998d65f6f70SBen Gras int chfs_read_inode(struct chfs_mount *chmp, struct chfs_inode *ip)
999d65f6f70SBen Gras {
1000d65f6f70SBen Gras 	struct chfs_vnode_cache *vc = ip->chvc;
1001d65f6f70SBen Gras 
1002d65f6f70SBen Gras 	KASSERT(mutex_owned(&chmp->chm_lock_mountfields));
1003d65f6f70SBen Gras 
1004d65f6f70SBen Gras retry:
100584d9c625SLionel Sambuc 	mutex_enter(&chmp->chm_lock_vnocache);
1006d65f6f70SBen Gras 	switch (vc->state) {
1007d65f6f70SBen Gras 		case VNO_STATE_UNCHECKED:
100884d9c625SLionel Sambuc 			/* FALLTHROUGH */
1009d65f6f70SBen Gras 		case VNO_STATE_CHECKEDABSENT:
1010d65f6f70SBen Gras 			vc->state = VNO_STATE_READING;
1011d65f6f70SBen Gras 			break;
1012d65f6f70SBen Gras 		case VNO_STATE_CHECKING:
101384d9c625SLionel Sambuc 			/* FALLTHROUGH */
1014d65f6f70SBen Gras 		case VNO_STATE_GC:
101584d9c625SLionel Sambuc 			mutex_exit(&chmp->chm_lock_vnocache);
1016d65f6f70SBen Gras 			goto retry;
1017d65f6f70SBen Gras 			break;
1018d65f6f70SBen Gras 		case VNO_STATE_PRESENT:
101984d9c625SLionel Sambuc 			/* FALLTHROUGH */
1020d65f6f70SBen Gras 		case VNO_STATE_READING:
1021d65f6f70SBen Gras 			chfs_err("Reading inode #%llu in state %d!\n",
1022d65f6f70SBen Gras 				(unsigned long long)vc->vno, vc->state);
1023d65f6f70SBen Gras 			chfs_err("wants to read a nonexistent ino %llu\n",
1024d65f6f70SBen Gras 				(unsigned long long)vc->vno);
1025d65f6f70SBen Gras 			return ENOENT;
1026d65f6f70SBen Gras 		default:
1027d65f6f70SBen Gras 			panic("BUG() Bad vno cache state.");
1028d65f6f70SBen Gras 	}
102984d9c625SLionel Sambuc 	mutex_exit(&chmp->chm_lock_vnocache);
1030d65f6f70SBen Gras 
1031d65f6f70SBen Gras 	return chfs_read_inode_internal(chmp, ip);
1032d65f6f70SBen Gras }
1033d65f6f70SBen Gras 
1034d65f6f70SBen Gras /*
103584d9c625SLionel Sambuc  * chfs_read_inode_internal - reads and builds an inode
103684d9c625SLionel Sambuc  * Firstly get temporary nodes then build fragtree.
1037d65f6f70SBen Gras  */
1038d65f6f70SBen Gras int
chfs_read_inode_internal(struct chfs_mount * chmp,struct chfs_inode * ip)1039d65f6f70SBen Gras chfs_read_inode_internal(struct chfs_mount *chmp, struct chfs_inode *ip)
1040d65f6f70SBen Gras {
1041d65f6f70SBen Gras 	int err;
1042d65f6f70SBen Gras 	size_t len, retlen;
1043d65f6f70SBen Gras 	char* buf;
1044d65f6f70SBen Gras 	struct chfs_readinode_info rii;
1045d65f6f70SBen Gras 	struct chfs_flash_vnode *fvnode;
1046d65f6f70SBen Gras 
1047d65f6f70SBen Gras 	KASSERT(mutex_owned(&chmp->chm_lock_mountfields));
1048d65f6f70SBen Gras 
1049d65f6f70SBen Gras 	len = sizeof(*fvnode);
1050d65f6f70SBen Gras 
1051d65f6f70SBen Gras 	memset(&rii, 0, sizeof(rii));
1052d65f6f70SBen Gras 
1053d65f6f70SBen Gras 	rb_tree_init(&rii.tdi_root, &tmp_node_rbtree_ops);
1054d65f6f70SBen Gras 
105584d9c625SLionel Sambuc 	/* Build a temporary node tree. */
1056d65f6f70SBen Gras 	err = chfs_get_data_nodes(chmp, ip, &rii);
1057d65f6f70SBen Gras 	if (err) {
1058d65f6f70SBen Gras 		if (ip->chvc->state == VNO_STATE_READING)
1059d65f6f70SBen Gras 			ip->chvc->state = VNO_STATE_CHECKEDABSENT;
1060d65f6f70SBen Gras 		/* FIXME Should we kill fragtree or something here? */
1061d65f6f70SBen Gras 		return err;
1062d65f6f70SBen Gras 	}
1063d65f6f70SBen Gras 
106484d9c625SLionel Sambuc 	/* Build fragtree from temp nodes. */
1065d65f6f70SBen Gras 	rb_tree_init(&ip->fragtree, &frag_rbtree_ops);
106684d9c625SLionel Sambuc 
1067d65f6f70SBen Gras 	err = chfs_build_fragtree(chmp, ip, &rii);
1068d65f6f70SBen Gras 	if (err) {
1069d65f6f70SBen Gras 		if (ip->chvc->state == VNO_STATE_READING)
1070d65f6f70SBen Gras 			ip->chvc->state = VNO_STATE_CHECKEDABSENT;
1071d65f6f70SBen Gras 		/* FIXME Should we kill fragtree or something here? */
1072d65f6f70SBen Gras 		return err;
1073d65f6f70SBen Gras 	}
1074d65f6f70SBen Gras 
1075d65f6f70SBen Gras 	if (!rii.latest_ref) {
1076d65f6f70SBen Gras 		return 0;
1077d65f6f70SBen Gras 	}
1078d65f6f70SBen Gras 
1079d65f6f70SBen Gras 	buf = kmem_alloc(len, KM_SLEEP);
1080d65f6f70SBen Gras 	if (!buf)
1081d65f6f70SBen Gras 		return ENOMEM;
1082d65f6f70SBen Gras 
108384d9c625SLionel Sambuc 	/* Set inode size from its vnode information node. */
1084d65f6f70SBen Gras 	err = chfs_read_leb(chmp, ip->chvc->v->nref_lnr, buf, CHFS_GET_OFS(ip->chvc->v->nref_offset), len, &retlen);
1085d65f6f70SBen Gras 	if (err || retlen != len) {
1086d65f6f70SBen Gras 		kmem_free(buf, len);
1087d65f6f70SBen Gras 		return err?err:EIO;
1088d65f6f70SBen Gras 	}
1089d65f6f70SBen Gras 
1090d65f6f70SBen Gras 	fvnode = (struct chfs_flash_vnode*)buf;
1091d65f6f70SBen Gras 
1092d65f6f70SBen Gras 	dbg("set size from v: %u\n", fvnode->dn_size);
1093d65f6f70SBen Gras 	chfs_set_vnode_size(ITOV(ip), fvnode->dn_size);
1094d65f6f70SBen Gras 	uint32_t retsize = chfs_truncate_fragtree(chmp, &ip->fragtree, fvnode->dn_size);
1095d65f6f70SBen Gras 	if (retsize != fvnode->dn_size) {
1096d65f6f70SBen Gras 		dbg("Truncating failed. It is %u instead of %u\n", retsize, fvnode->dn_size);
1097d65f6f70SBen Gras 	}
1098d65f6f70SBen Gras 
1099d65f6f70SBen Gras 	kmem_free(buf, len);
1100d65f6f70SBen Gras 
1101d65f6f70SBen Gras 	if (ip->chvc->state == VNO_STATE_READING) {
1102d65f6f70SBen Gras 		ip->chvc->state = VNO_STATE_PRESENT;
1103d65f6f70SBen Gras 	}
1104d65f6f70SBen Gras 
1105d65f6f70SBen Gras 	return 0;
1106d65f6f70SBen Gras }
1107d65f6f70SBen Gras 
110884d9c625SLionel Sambuc /* chfs_read_data - reads and checks data of a file */
1109d65f6f70SBen Gras int
chfs_read_data(struct chfs_mount * chmp,struct vnode * vp,struct buf * bp)1110d65f6f70SBen Gras chfs_read_data(struct chfs_mount* chmp, struct vnode *vp,
1111d65f6f70SBen Gras     struct buf *bp)
1112d65f6f70SBen Gras {
1113d65f6f70SBen Gras 	off_t ofs;
1114d65f6f70SBen Gras 	struct chfs_node_frag *frag;
1115d65f6f70SBen Gras 	char * buf;
1116d65f6f70SBen Gras 	int err = 0;
1117d65f6f70SBen Gras 	size_t size, retlen;
1118d65f6f70SBen Gras 	uint32_t crc;
1119d65f6f70SBen Gras 	struct chfs_inode *ip = VTOI(vp);
1120d65f6f70SBen Gras 	struct chfs_flash_data_node *dnode;
1121d65f6f70SBen Gras 	struct chfs_node_ref *nref;
1122d65f6f70SBen Gras 
1123d65f6f70SBen Gras 	memset(bp->b_data, 0, bp->b_bcount);
1124d65f6f70SBen Gras 
112584d9c625SLionel Sambuc 	/* Calculate the size of the file from its fragtree. */
1126d65f6f70SBen Gras 	ofs = bp->b_blkno * PAGE_SIZE;
1127d65f6f70SBen Gras 	frag = (struct chfs_node_frag *)rb_tree_find_node_leq(&ip->fragtree, &ofs);
1128d65f6f70SBen Gras 
1129d65f6f70SBen Gras 	if (!frag || frag->ofs > ofs || frag->ofs + frag->size <= ofs) {
113084d9c625SLionel Sambuc 		bp->b_resid = 0;
1131d65f6f70SBen Gras 		dbg("not found in frag tree\n");
1132d65f6f70SBen Gras 		return 0;
1133d65f6f70SBen Gras 	}
1134d65f6f70SBen Gras 
1135d65f6f70SBen Gras 	if (!frag->node) {
1136d65f6f70SBen Gras 		dbg("no node in frag\n");
1137d65f6f70SBen Gras 		return 0;
1138d65f6f70SBen Gras 	}
1139d65f6f70SBen Gras 
1140d65f6f70SBen Gras 	nref = frag->node->nref;
1141d65f6f70SBen Gras 	size = sizeof(*dnode) + frag->size;
1142d65f6f70SBen Gras 
1143d65f6f70SBen Gras 	buf = kmem_alloc(size, KM_SLEEP);
1144d65f6f70SBen Gras 
114584d9c625SLionel Sambuc 	/* Read node from flash. */
1146d65f6f70SBen Gras 	dbg("reading from lnr: %u, offset: %u, size: %zu\n", nref->nref_lnr, CHFS_GET_OFS(nref->nref_offset), size);
1147d65f6f70SBen Gras 	err = chfs_read_leb(chmp, nref->nref_lnr, buf, CHFS_GET_OFS(nref->nref_offset), size, &retlen);
1148d65f6f70SBen Gras 	if (err) {
1149d65f6f70SBen Gras 		chfs_err("error after reading: %d\n", err);
1150d65f6f70SBen Gras 		goto out;
1151d65f6f70SBen Gras 	}
1152d65f6f70SBen Gras 	if (retlen != size) {
1153d65f6f70SBen Gras 		chfs_err("retlen: %zu != size: %zu\n", retlen, size);
1154d65f6f70SBen Gras 		err = EIO;
1155d65f6f70SBen Gras 		goto out;
1156d65f6f70SBen Gras 	}
1157d65f6f70SBen Gras 
115884d9c625SLionel Sambuc 	/* Read data from flash. */
1159d65f6f70SBen Gras 	dnode = (struct chfs_flash_data_node *)buf;
1160d65f6f70SBen Gras 	crc = crc32(0, (uint8_t *)dnode, CHFS_NODE_HDR_SIZE - 4);
1161d65f6f70SBen Gras 	if (crc != le32toh(dnode->hdr_crc)) {
1162d65f6f70SBen Gras 		chfs_err("CRC check failed. calc: 0x%x orig: 0x%x\n", crc, le32toh(dnode->hdr_crc));
1163d65f6f70SBen Gras 		err = EIO;
1164d65f6f70SBen Gras 		goto out;
1165d65f6f70SBen Gras 	}
116684d9c625SLionel Sambuc 
116784d9c625SLionel Sambuc 	/* Check header magic bitmask. */
1168d65f6f70SBen Gras 	if (le16toh(dnode->magic) != CHFS_FS_MAGIC_BITMASK) {
1169d65f6f70SBen Gras 		chfs_err("Wrong magic bitmask.\n");
1170d65f6f70SBen Gras 		err = EIO;
1171d65f6f70SBen Gras 		goto out;
1172d65f6f70SBen Gras 	}
117384d9c625SLionel Sambuc 
117484d9c625SLionel Sambuc 	/* Check crc of node. */
1175d65f6f70SBen Gras 	crc = crc32(0, (uint8_t *)dnode, sizeof(*dnode) - 4);
1176d65f6f70SBen Gras 	if (crc != le32toh(dnode->node_crc)) {
1177d65f6f70SBen Gras 		chfs_err("Node CRC check failed. calc: 0x%x orig: 0x%x\n", crc, le32toh(dnode->node_crc));
1178d65f6f70SBen Gras 		err = EIO;
1179d65f6f70SBen Gras 		goto out;
1180d65f6f70SBen Gras 	}
118184d9c625SLionel Sambuc 
118284d9c625SLionel Sambuc 	/* Check crc of data. */
1183d65f6f70SBen Gras 	crc = crc32(0, (uint8_t *)dnode->data, dnode->data_length);
1184d65f6f70SBen Gras 	if (crc != le32toh(dnode->data_crc)) {
1185d65f6f70SBen Gras 		chfs_err("Data CRC check failed. calc: 0x%x orig: 0x%x\n", crc, le32toh(dnode->data_crc));
1186d65f6f70SBen Gras 		err = EIO;
1187d65f6f70SBen Gras 		goto out;
1188d65f6f70SBen Gras 	}
1189d65f6f70SBen Gras 
1190d65f6f70SBen Gras 	memcpy(bp->b_data, dnode->data, dnode->data_length);
1191d65f6f70SBen Gras 	bp->b_resid = 0;
1192d65f6f70SBen Gras 
1193d65f6f70SBen Gras out:
1194d65f6f70SBen Gras 	kmem_free(buf, size);
1195d65f6f70SBen Gras 	return err;
1196d65f6f70SBen Gras }
1197