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