Home | History | Annotate | Line # | Download | only in chfs
chfs_scan.c revision 1.3
      1  1.3  ttoth /*	$NetBSD: chfs_scan.c,v 1.3 2012/08/10 09:26:58 ttoth Exp $	*/
      2  1.1  ahoka 
      3  1.1  ahoka /*-
      4  1.1  ahoka  * Copyright (c) 2010 Department of Software Engineering,
      5  1.1  ahoka  *		      University of Szeged, Hungary
      6  1.1  ahoka  * Copyright (c) 2010 David Tengeri <dtengeri (at) inf.u-szeged.hu>
      7  1.1  ahoka  * All rights reserved.
      8  1.1  ahoka  *
      9  1.1  ahoka  * This code is derived from software contributed to The NetBSD Foundation
     10  1.1  ahoka  * by the Department of Software Engineering, University of Szeged, Hungary
     11  1.1  ahoka  *
     12  1.1  ahoka  * Redistribution and use in source and binary forms, with or without
     13  1.1  ahoka  * modification, are permitted provided that the following conditions
     14  1.1  ahoka  * are met:
     15  1.1  ahoka  * 1. Redistributions of source code must retain the above copyright
     16  1.1  ahoka  *    notice, this list of conditions and the following disclaimer.
     17  1.1  ahoka  * 2. Redistributions in binary form must reproduce the above copyright
     18  1.1  ahoka  *    notice, this list of conditions and the following disclaimer in the
     19  1.1  ahoka  *    documentation and/or other materials provided with the distribution.
     20  1.1  ahoka  *
     21  1.1  ahoka  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     22  1.1  ahoka  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     23  1.1  ahoka  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     24  1.1  ahoka  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     25  1.1  ahoka  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
     26  1.1  ahoka  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     27  1.1  ahoka  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
     28  1.1  ahoka  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     29  1.1  ahoka  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     30  1.1  ahoka  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     31  1.1  ahoka  * SUCH DAMAGE.
     32  1.1  ahoka  */
     33  1.1  ahoka 
     34  1.1  ahoka /*
     35  1.1  ahoka  * chfs_scan.c
     36  1.1  ahoka  *
     37  1.1  ahoka  *  Created on: 2009.11.05.
     38  1.1  ahoka  *      Author: dtengeri
     39  1.1  ahoka  */
     40  1.1  ahoka 
     41  1.1  ahoka #include "chfs.h"
     42  1.1  ahoka 
     43  1.1  ahoka /**
     44  1.1  ahoka  * chfs_scan_make_vnode_cache - makes a new vnode cache during scan
     45  1.1  ahoka  * @chmp: CHFS main descriptor structure
     46  1.1  ahoka  * @vno: vnode identifier
     47  1.1  ahoka  * This function returns a vnode cache belonging to @vno.
     48  1.1  ahoka  */
     49  1.1  ahoka struct chfs_vnode_cache *
     50  1.1  ahoka chfs_scan_make_vnode_cache(struct chfs_mount *chmp, ino_t vno)
     51  1.1  ahoka {
     52  1.1  ahoka 	struct chfs_vnode_cache *vc;
     53  1.1  ahoka 
     54  1.1  ahoka 	KASSERT(mutex_owned(&chmp->chm_lock_vnocache));
     55  1.1  ahoka 
     56  1.1  ahoka 	vc = chfs_vnode_cache_get(chmp, vno);
     57  1.1  ahoka 	if (vc) {
     58  1.1  ahoka 		return vc;
     59  1.1  ahoka 	}
     60  1.1  ahoka 
     61  1.1  ahoka 	if (vno > chmp->chm_max_vno) {
     62  1.1  ahoka 		chmp->chm_max_vno = vno;
     63  1.1  ahoka 	}
     64  1.1  ahoka 
     65  1.1  ahoka 	vc = chfs_vnode_cache_alloc(vno);
     66  1.1  ahoka 
     67  1.1  ahoka 	chfs_vnode_cache_add(chmp, vc);
     68  1.1  ahoka 
     69  1.1  ahoka 	if (vno == CHFS_ROOTINO) {
     70  1.1  ahoka 		vc->nlink = 2;
     71  1.1  ahoka 		vc->pvno = CHFS_ROOTINO;
     72  1.3  ttoth 		vc->state = VNO_STATE_CHECKEDABSENT;
     73  1.1  ahoka 	}
     74  1.1  ahoka 
     75  1.1  ahoka 	return vc;
     76  1.1  ahoka }
     77  1.1  ahoka 
     78  1.1  ahoka /**
     79  1.1  ahoka  * chfs_scan_check_node_hdr - checks node magic and crc
     80  1.1  ahoka  * @nhdr: node header to check
     81  1.1  ahoka  * Returns 0 if everything is OK, error code otherwise.
     82  1.1  ahoka  */
     83  1.1  ahoka int
     84  1.1  ahoka chfs_scan_check_node_hdr(struct chfs_flash_node_hdr *nhdr)
     85  1.1  ahoka {
     86  1.1  ahoka 	uint16_t magic;
     87  1.1  ahoka 	uint32_t crc, hdr_crc;
     88  1.1  ahoka 
     89  1.1  ahoka 	magic = le16toh(nhdr->magic);
     90  1.1  ahoka 
     91  1.1  ahoka 	if (magic != CHFS_FS_MAGIC_BITMASK) {
     92  1.1  ahoka 		dbg("bad magic\n");
     93  1.1  ahoka 		return CHFS_NODE_BADMAGIC;
     94  1.1  ahoka 	}
     95  1.1  ahoka 
     96  1.1  ahoka 	hdr_crc = le32toh(nhdr->hdr_crc);
     97  1.1  ahoka 	crc = crc32(0, (uint8_t *)nhdr, CHFS_NODE_HDR_SIZE - 4);
     98  1.1  ahoka 
     99  1.1  ahoka 	if (crc != hdr_crc) {
    100  1.1  ahoka 		dbg("bad crc\n");
    101  1.1  ahoka 		return CHFS_NODE_BADCRC;
    102  1.1  ahoka 	}
    103  1.1  ahoka 
    104  1.1  ahoka 	return CHFS_NODE_OK;
    105  1.1  ahoka }
    106  1.1  ahoka 
    107  1.1  ahoka /**
    108  1.1  ahoka  * chfs_scan_check_vnode - check vnode crc and add to vnode cache
    109  1.1  ahoka  * @chmp: CHFS main descriptor structure
    110  1.1  ahoka  * @cheb: eraseblock informations
    111  1.1  ahoka  * @buf: vnode to check
    112  1.1  ahoka  * @ofs: offset in eraseblock where vnode starts
    113  1.1  ahoka  */
    114  1.1  ahoka int
    115  1.1  ahoka chfs_scan_check_vnode(struct chfs_mount *chmp,
    116  1.1  ahoka     struct chfs_eraseblock *cheb, void *buf, off_t ofs)
    117  1.1  ahoka {
    118  1.1  ahoka 	KASSERT(mutex_owned(&chmp->chm_lock_mountfields));
    119  1.1  ahoka 	struct chfs_vnode_cache *vc;
    120  1.1  ahoka 	struct chfs_flash_vnode *vnode = buf;
    121  1.1  ahoka 	struct chfs_node_ref *nref;
    122  1.1  ahoka 	int err;
    123  1.1  ahoka 	uint32_t crc;
    124  1.1  ahoka 	ino_t vno;
    125  1.1  ahoka 
    126  1.1  ahoka 	crc = crc32(0, (uint8_t *)vnode,
    127  1.1  ahoka 	    sizeof(struct chfs_flash_vnode) - 4);
    128  1.1  ahoka 
    129  1.1  ahoka 	if (crc != le32toh(vnode->node_crc)) {
    130  1.1  ahoka 		err = chfs_update_eb_dirty(chmp,
    131  1.1  ahoka 		    cheb, le32toh(vnode->length));
    132  1.1  ahoka 		if (err) {
    133  1.1  ahoka 			return err;
    134  1.1  ahoka 		}
    135  1.1  ahoka 
    136  1.1  ahoka 		return CHFS_NODE_BADCRC;
    137  1.1  ahoka 	}
    138  1.1  ahoka 
    139  1.1  ahoka 	vno = le64toh(vnode->vno);
    140  1.1  ahoka 
    141  1.1  ahoka 	mutex_enter(&chmp->chm_lock_vnocache);
    142  1.1  ahoka 	vc = chfs_vnode_cache_get(chmp, vno);
    143  1.1  ahoka 	if (!vc) {
    144  1.1  ahoka 		vc = chfs_scan_make_vnode_cache(chmp, vno);
    145  1.1  ahoka 		if (!vc) {
    146  1.1  ahoka 			mutex_exit(&chmp->chm_lock_vnocache);
    147  1.1  ahoka 			return ENOMEM;
    148  1.1  ahoka 		}
    149  1.1  ahoka 	}
    150  1.1  ahoka 
    151  1.1  ahoka 	nref = chfs_alloc_node_ref(cheb);
    152  1.1  ahoka 
    153  1.1  ahoka 	nref->nref_offset = ofs;
    154  1.1  ahoka 
    155  1.1  ahoka 	KASSERT(nref->nref_lnr == cheb->lnr);
    156  1.1  ahoka 
    157  1.1  ahoka 	/* Check version of vnode. */
    158  1.1  ahoka 	if ((struct chfs_vnode_cache *)vc->v != vc) {
    159  1.1  ahoka 		if (le64toh(vnode->version) > *vc->vno_version) {
    160  1.1  ahoka 			//err = chfs_update_eb_dirty(chmp, &chmp->chm_blocks[vc->v->lnr],
    161  1.1  ahoka 			//		sizeof(struct chfs_flash_vnode));
    162  1.1  ahoka 			*vc->vno_version = le64toh(vnode->version);
    163  1.1  ahoka 			chfs_add_vnode_ref_to_vc(chmp, vc, nref);
    164  1.1  ahoka 		} else {
    165  1.1  ahoka 			err = chfs_update_eb_dirty(chmp, cheb,
    166  1.1  ahoka 			    sizeof(struct chfs_flash_vnode));
    167  1.1  ahoka 			return CHFS_NODE_OK;
    168  1.1  ahoka 		}
    169  1.1  ahoka 	} else {
    170  1.1  ahoka 		vc->vno_version = kmem_alloc(sizeof(uint64_t), KM_SLEEP);
    171  1.1  ahoka 		if (!vc->vno_version)
    172  1.1  ahoka 			return ENOMEM;
    173  1.1  ahoka 		*vc->vno_version = le64toh(vnode->version);
    174  1.1  ahoka 		chfs_add_vnode_ref_to_vc(chmp, vc, nref);
    175  1.1  ahoka 	}
    176  1.3  ttoth 	mutex_exit(&chmp->chm_lock_vnocache);
    177  1.1  ahoka 
    178  1.1  ahoka 	mutex_enter(&chmp->chm_lock_sizes);
    179  1.1  ahoka 	//dbg("B:lnr: %d |free_size: %d node's size: %d\n", cheb->lnr, cheb->free_size, le32toh(vnode->length));
    180  1.1  ahoka 	chfs_change_size_free(chmp, cheb, -le32toh(vnode->length));
    181  1.1  ahoka 	chfs_change_size_used(chmp, cheb, le32toh(vnode->length));
    182  1.1  ahoka 	mutex_exit(&chmp->chm_lock_sizes);
    183  1.1  ahoka 
    184  1.1  ahoka 	KASSERT(cheb->used_size <= chmp->chm_ebh->eb_size);
    185  1.1  ahoka 
    186  1.1  ahoka 	KASSERT(cheb->used_size + cheb->free_size + cheb->dirty_size + cheb->unchecked_size + cheb->wasted_size == chmp->chm_ebh->eb_size);
    187  1.1  ahoka 
    188  1.1  ahoka 	//dbg(" A: free_size: %d\n", cheb->free_size);
    189  1.1  ahoka 
    190  1.1  ahoka 	/*dbg("vnode dump:\n");
    191  1.1  ahoka 	  dbg(" ->magic:    0x%x\n", le16toh(vnode->magic));
    192  1.1  ahoka 	  dbg(" ->type:     %d\n", le16toh(vnode->type));
    193  1.1  ahoka 	  dbg(" ->length:   %d\n", le32toh(vnode->length));
    194  1.1  ahoka 	  dbg(" ->hdr_crc:  0x%x\n", le32toh(vnode->hdr_crc));
    195  1.1  ahoka 	  dbg(" ->vno:      %d\n", le64toh(vnode->vno));
    196  1.1  ahoka 	  dbg(" ->version:  %ld\n", le64toh(vnode->version));
    197  1.1  ahoka 	  dbg(" ->uid:      %d\n", le16toh(vnode->uid));
    198  1.1  ahoka 	  dbg(" ->gid:      %d\n", le16toh(vnode->gid));
    199  1.1  ahoka 	  dbg(" ->mode:     %d\n", le32toh(vnode->mode));
    200  1.1  ahoka 	  dbg(" ->dn_size:  %d\n", le32toh(vnode->dn_size));
    201  1.1  ahoka 	  dbg(" ->atime:    %d\n", le32toh(vnode->atime));
    202  1.1  ahoka 	  dbg(" ->mtime:    %d\n", le32toh(vnode->mtime));
    203  1.1  ahoka 	  dbg(" ->ctime:    %d\n", le32toh(vnode->ctime));
    204  1.1  ahoka 	  dbg(" ->dsize:    %d\n", le32toh(vnode->dsize));
    205  1.1  ahoka 	  dbg(" ->node_crc: 0x%x\n", le32toh(vnode->node_crc));*/
    206  1.1  ahoka 
    207  1.1  ahoka 	return CHFS_NODE_OK;
    208  1.1  ahoka }
    209  1.1  ahoka 
    210  1.1  ahoka int
    211  1.1  ahoka chfs_scan_mark_dirent_obsolete(struct chfs_mount *chmp,
    212  1.1  ahoka     struct chfs_vnode_cache *vc, struct chfs_dirent *fd)
    213  1.1  ahoka {
    214  1.1  ahoka 	//int size;
    215  1.1  ahoka 	struct chfs_eraseblock *cheb;
    216  1.1  ahoka 	struct chfs_node_ref *prev, *nref;
    217  1.1  ahoka 
    218  1.1  ahoka 	nref = fd->nref;
    219  1.1  ahoka 	cheb = &chmp->chm_blocks[fd->nref->nref_lnr];
    220  1.1  ahoka 
    221  1.1  ahoka 	/* Remove dirent's node ref from vnode cache */
    222  1.1  ahoka 	prev = vc->dirents;
    223  1.1  ahoka 	if (prev && prev == nref) {
    224  1.1  ahoka 		vc->dirents = prev->nref_next;
    225  1.1  ahoka 	} else if (prev && prev != (void *)vc) {
    226  1.3  ttoth 		while (prev->nref_next && prev->nref_next != (void *)vc) {
    227  1.3  ttoth 			if (prev->nref_next == nref) {
    228  1.3  ttoth 				prev->nref_next = nref->nref_next;
    229  1.3  ttoth 				break;
    230  1.3  ttoth 			}
    231  1.1  ahoka 			prev = prev->nref_next;
    232  1.1  ahoka 		}
    233  1.3  ttoth 	}
    234  1.1  ahoka 
    235  1.1  ahoka 	/*dbg("XXX - start\n");
    236  1.1  ahoka 	//nref = vc->dirents;
    237  1.1  ahoka 	struct chfs_dirent *tmp;
    238  1.1  ahoka 	tmp = vc->scan_dirents;
    239  1.1  ahoka 	while (tmp) {
    240  1.1  ahoka 	dbg(" ->tmp->name:    %s\n", tmp->name);
    241  1.1  ahoka 	dbg(" ->tmp->version: %ld\n", tmp->version);
    242  1.1  ahoka 	dbg(" ->tmp->vno: %d\n", tmp->vno);
    243  1.1  ahoka 	tmp = tmp->next;
    244  1.1  ahoka 	}
    245  1.1  ahoka 	dbg("XXX - end\n");*/
    246  1.1  ahoka 	//size = CHFS_PAD(sizeof(struct chfs_flash_dirent_node) + fd->nsize);
    247  1.1  ahoka 
    248  1.1  ahoka 	KASSERT(cheb->used_size + cheb->free_size + cheb->dirty_size +
    249  1.1  ahoka 	    cheb->unchecked_size + cheb->wasted_size == chmp->chm_ebh->eb_size);
    250  1.1  ahoka 
    251  1.1  ahoka 	return 0;
    252  1.1  ahoka }
    253  1.1  ahoka 
    254  1.1  ahoka void
    255  1.1  ahoka chfs_add_fd_to_list(struct chfs_mount *chmp,
    256  1.1  ahoka     struct chfs_dirent *new, struct chfs_vnode_cache *pvc)
    257  1.1  ahoka {
    258  1.1  ahoka 	KASSERT(mutex_owned(&chmp->chm_lock_mountfields));
    259  1.1  ahoka 	int size;
    260  1.1  ahoka 	struct chfs_eraseblock *cheb, *oldcheb;
    261  1.1  ahoka //	struct chfs_dirent **prev;
    262  1.1  ahoka 	struct chfs_dirent *fd, *tmpfd;
    263  1.1  ahoka 
    264  1.1  ahoka 	dbg("adding fd to list: %s\n", new->name);
    265  1.1  ahoka 
    266  1.1  ahoka 	if ((new->version > pvc->highest_version))
    267  1.1  ahoka 		pvc->highest_version = new->version;
    268  1.1  ahoka 
    269  1.1  ahoka 	size = CHFS_PAD(sizeof(struct chfs_flash_dirent_node) +
    270  1.1  ahoka 	    new->nsize);
    271  1.1  ahoka 	cheb = &chmp->chm_blocks[new->nref->nref_lnr];
    272  1.1  ahoka 
    273  1.1  ahoka 	mutex_enter(&chmp->chm_lock_sizes);
    274  1.1  ahoka 	TAILQ_FOREACH_SAFE(fd, &pvc->scan_dirents, fds, tmpfd) {
    275  1.1  ahoka 		if (fd->nhash > new->nhash) {
    276  1.1  ahoka 			/* insert new before fd */
    277  1.1  ahoka 			TAILQ_INSERT_BEFORE(fd, new, fds);
    278  1.1  ahoka 			goto out;
    279  1.1  ahoka 		} else if (fd->nhash == new->nhash &&
    280  1.1  ahoka 		    !strcmp(fd->name, new->name)) {
    281  1.1  ahoka 			if (new->version > fd->version) {
    282  1.1  ahoka //				new->next = fd->next;
    283  1.1  ahoka 				/* replace fd with new */
    284  1.1  ahoka 				TAILQ_INSERT_BEFORE(fd, new, fds);
    285  1.1  ahoka 				chfs_change_size_free(chmp, cheb, -size);
    286  1.1  ahoka 				chfs_change_size_used(chmp, cheb, size);
    287  1.1  ahoka 
    288  1.1  ahoka 				TAILQ_REMOVE(&pvc->scan_dirents, fd, fds);
    289  1.1  ahoka 				if (fd->nref) {
    290  1.1  ahoka 					size = CHFS_PAD(sizeof(struct chfs_flash_dirent_node) + fd->nsize);
    291  1.1  ahoka 					chfs_scan_mark_dirent_obsolete(chmp, pvc, fd);
    292  1.1  ahoka 					oldcheb = &chmp->chm_blocks[fd->nref->nref_lnr];
    293  1.1  ahoka 					chfs_change_size_used(chmp, oldcheb, -size);
    294  1.1  ahoka 					chfs_change_size_dirty(chmp, oldcheb, size);
    295  1.1  ahoka 				}
    296  1.1  ahoka 				chfs_free_dirent(fd);
    297  1.1  ahoka //				*prev = new;//XXX
    298  1.1  ahoka 			} else {
    299  1.1  ahoka 				chfs_scan_mark_dirent_obsolete(chmp, pvc, new);
    300  1.1  ahoka 				chfs_change_size_free(chmp, cheb, -size);
    301  1.1  ahoka 				chfs_change_size_dirty(chmp, cheb, size);
    302  1.1  ahoka 				chfs_free_dirent(new);
    303  1.1  ahoka 			}
    304  1.1  ahoka 			/*dbg("START\n");
    305  1.1  ahoka 			  fd = pvc->scan_dirents;
    306  1.1  ahoka 			  while (fd) {
    307  1.1  ahoka 			  dbg("dirent dump:\n");
    308  1.1  ahoka 			  dbg(" ->vno:     %d\n", fd->vno);
    309  1.1  ahoka 			  dbg(" ->version: %ld\n", fd->version);
    310  1.1  ahoka 			  dbg(" ->nhash:   0x%x\n", fd->nhash);
    311  1.1  ahoka 			  dbg(" ->nsize:   %d\n", fd->nsize);
    312  1.1  ahoka 			  dbg(" ->name:    %s\n", fd->name);
    313  1.1  ahoka 			  dbg(" ->type:    %d\n", fd->type);
    314  1.1  ahoka 			  fd = fd->next;
    315  1.1  ahoka 			  }
    316  1.1  ahoka 			  dbg("END\n");*/
    317  1.1  ahoka 			mutex_exit(&chmp->chm_lock_sizes);
    318  1.1  ahoka 			return;
    319  1.1  ahoka 		}
    320  1.1  ahoka 	}
    321  1.1  ahoka 	/* if we couldnt fit it elsewhere, lets add to the end */
    322  1.1  ahoka 	TAILQ_INSERT_TAIL(&pvc->scan_dirents, new, fds);
    323  1.1  ahoka 
    324  1.1  ahoka out:
    325  1.1  ahoka 	//dbg("B:lnr: %d |free_size: %d size: %d\n", cheb->lnr, cheb->free_size, size);
    326  1.1  ahoka 	chfs_change_size_free(chmp, cheb, -size);
    327  1.1  ahoka 	chfs_change_size_used(chmp, cheb, size);
    328  1.1  ahoka 	mutex_exit(&chmp->chm_lock_sizes);
    329  1.1  ahoka 
    330  1.1  ahoka 	KASSERT(cheb->used_size <= chmp->chm_ebh->eb_size);
    331  1.1  ahoka 	//dbg(" A: free_size: %d\n", cheb->free_size);
    332  1.1  ahoka 
    333  1.1  ahoka 	KASSERT(cheb->used_size + cheb->free_size + cheb->dirty_size + cheb->unchecked_size + cheb->wasted_size == chmp->chm_ebh->eb_size);
    334  1.1  ahoka 
    335  1.1  ahoka 
    336  1.1  ahoka //	fd = pvc->scan_dirents;
    337  1.1  ahoka 	/*dbg("START\n");
    338  1.1  ahoka 	  while (fd) {
    339  1.1  ahoka 	  dbg("dirent dump:\n");
    340  1.1  ahoka 	  dbg(" ->vno:     %d\n", fd->vno);
    341  1.1  ahoka 	  dbg(" ->version: %ld\n", fd->version);
    342  1.1  ahoka 	  dbg(" ->nhash:   0x%x\n", fd->nhash);
    343  1.1  ahoka 	  dbg(" ->nsize:   %d\n", fd->nsize);
    344  1.1  ahoka 	  dbg(" ->name:    %s\n", fd->name);
    345  1.1  ahoka 	  dbg(" ->type:    %d\n", fd->type);
    346  1.1  ahoka 	  fd = fd->next;
    347  1.1  ahoka 	  }
    348  1.1  ahoka 	  dbg("END\n");*/
    349  1.1  ahoka }
    350  1.1  ahoka /**
    351  1.1  ahoka  * chfs_scan_check_dirent_node - check vnode crc and add to vnode cache
    352  1.1  ahoka  * @chmp: CHFS main descriptor structure
    353  1.1  ahoka  * @cheb: eraseblock informations
    354  1.1  ahoka  * @buf: directory entry to check
    355  1.1  ahoka  * @ofs: offset in eraseblock where dirent starts
    356  1.1  ahoka  */
    357  1.1  ahoka int
    358  1.1  ahoka chfs_scan_check_dirent_node(struct chfs_mount *chmp,
    359  1.1  ahoka     struct chfs_eraseblock *cheb, void *buf, off_t ofs)
    360  1.1  ahoka {
    361  1.1  ahoka 	int err, namelen;
    362  1.1  ahoka 	uint32_t crc;
    363  1.1  ahoka 	struct chfs_dirent *fd;
    364  1.3  ttoth 	struct chfs_vnode_cache *parentvc;
    365  1.1  ahoka 	struct chfs_flash_dirent_node *dirent = buf;
    366  1.1  ahoka 
    367  1.1  ahoka 	//struct chfs_node_ref *tmp;
    368  1.1  ahoka 
    369  1.1  ahoka 	crc = crc32(0, (uint8_t *)dirent, sizeof(*dirent) - 4);
    370  1.1  ahoka 	if (crc != le32toh(dirent->node_crc)) {
    371  1.1  ahoka 		err = chfs_update_eb_dirty(chmp, cheb, le32toh(dirent->length));
    372  1.1  ahoka 		if (err)
    373  1.1  ahoka 			return err;
    374  1.1  ahoka 		return CHFS_NODE_BADCRC;
    375  1.1  ahoka 	}
    376  1.1  ahoka 	namelen = dirent->nsize;
    377  1.1  ahoka 
    378  1.1  ahoka 	fd = chfs_alloc_dirent(namelen + 1);
    379  1.1  ahoka 	if (!fd)
    380  1.1  ahoka 		return ENOMEM;
    381  1.1  ahoka 
    382  1.1  ahoka 	fd->nref = chfs_alloc_node_ref(cheb);
    383  1.1  ahoka 	if (!fd->nref)
    384  1.1  ahoka 		return ENOMEM;
    385  1.1  ahoka 
    386  1.1  ahoka 	KASSERT(fd->nref->nref_lnr == cheb->lnr);
    387  1.1  ahoka 
    388  1.1  ahoka 	memcpy(&fd->name, dirent->name, namelen);
    389  1.1  ahoka 	fd->nsize = namelen;
    390  1.1  ahoka 	fd->name[namelen] = 0;
    391  1.1  ahoka 	crc = crc32(0, fd->name, dirent->nsize);
    392  1.1  ahoka 	if (crc != le32toh(dirent->name_crc)) {
    393  1.1  ahoka 		chfs_err("Directory entry's name has bad crc: read: 0x%x, "
    394  1.1  ahoka 		    "calculated: 0x%x\n", le32toh(dirent->name_crc), crc);
    395  1.1  ahoka 		chfs_free_dirent(fd);
    396  1.1  ahoka 		err = chfs_update_eb_dirty(chmp, cheb, le32toh(dirent->length));
    397  1.1  ahoka 		if (err)
    398  1.1  ahoka 			return err;
    399  1.1  ahoka 		return CHFS_NODE_BADNAMECRC;
    400  1.1  ahoka 	}
    401  1.1  ahoka 
    402  1.1  ahoka 	/* Check vnode_cache of parent node */
    403  1.1  ahoka 	mutex_enter(&chmp->chm_lock_vnocache);
    404  1.3  ttoth 	parentvc = chfs_scan_make_vnode_cache(chmp, le64toh(dirent->pvno));
    405  1.3  ttoth 	if (!parentvc) {
    406  1.1  ahoka 		chfs_free_dirent(fd);
    407  1.1  ahoka 		return ENOMEM;
    408  1.1  ahoka 	}
    409  1.1  ahoka 
    410  1.1  ahoka 	fd->nref->nref_offset = ofs;
    411  1.1  ahoka 
    412  1.3  ttoth 	dbg("add dirent to #%llu\n", (unsigned long long)parentvc->vno);
    413  1.3  ttoth 	chfs_add_node_to_list(chmp, parentvc, fd->nref, &parentvc->dirents);
    414  1.3  ttoth 	mutex_exit(&chmp->chm_lock_vnocache);
    415  1.1  ahoka 	/*tmp = vc->dirents;
    416  1.1  ahoka 	  dbg("START|vno: %d dirents dump\n", vc->vno);
    417  1.1  ahoka 	  while (tmp) {
    418  1.1  ahoka 	  dbg(" ->nref->nref_lnr:    %d\n", tmp->lnr);
    419  1.1  ahoka 	  dbg(" ->nref->nref_offset: %d\n", tmp->offset);
    420  1.1  ahoka 	  tmp = tmp->next;
    421  1.1  ahoka 	  }
    422  1.1  ahoka 	  dbg("  END|vno: %d dirents dump\n", vc->vno);*/
    423  1.1  ahoka 
    424  1.1  ahoka //	fd->next = NULL;
    425  1.1  ahoka 	fd->vno = le64toh(dirent->vno);
    426  1.1  ahoka 	fd->version = le64toh(dirent->version);
    427  1.1  ahoka 	fd->nhash = hash32_buf(fd->name, namelen, HASH32_BUF_INIT);
    428  1.1  ahoka 	fd->type = dirent->dtype;
    429  1.1  ahoka 
    430  1.1  ahoka 	/*dbg("dirent dump:\n");
    431  1.1  ahoka 	  dbg(" ->vno:     %d\n", fd->vno);
    432  1.1  ahoka 	  dbg(" ->version: %ld\n", fd->version);
    433  1.1  ahoka 	  dbg(" ->nhash:   0x%x\n", fd->nhash);
    434  1.1  ahoka 	  dbg(" ->nsize:   %d\n", fd->nsize);
    435  1.1  ahoka 	  dbg(" ->name:    %s\n", fd->name);
    436  1.1  ahoka 	  dbg(" ->type:    %d\n", fd->type);*/
    437  1.1  ahoka 
    438  1.3  ttoth 	chfs_add_fd_to_list(chmp, fd, parentvc);
    439  1.1  ahoka 
    440  1.1  ahoka 	/*struct chfs_node_ref *tmp;
    441  1.1  ahoka 	  tmp = vc->dirents;
    442  1.1  ahoka 	  dbg("START|vno: %d dirents dump\n", vc->vno);
    443  1.1  ahoka 	  while (tmp) {
    444  1.1  ahoka 	  dbg(" ->nref->nref_lnr:    %d\n", tmp->lnr);
    445  1.1  ahoka 	  dbg(" ->nref->nref_offset: %d\n", tmp->offset);
    446  1.1  ahoka 	  tmp = tmp->next;
    447  1.1  ahoka 	  }
    448  1.1  ahoka 	  dbg("  END|vno: %d dirents dump\n", vc->vno);*/
    449  1.1  ahoka 
    450  1.1  ahoka 	/*dbg("dirent dump:\n");
    451  1.1  ahoka 	  dbg(" ->magic:    0x%x\n", le16toh(dirent->magic));
    452  1.1  ahoka 	  dbg(" ->type:     %d\n", le16toh(dirent->type));
    453  1.1  ahoka 	  dbg(" ->length:   %d\n", le32toh(dirent->length));
    454  1.1  ahoka 	  dbg(" ->hdr_crc:  0x%x\n", le32toh(dirent->hdr_crc));
    455  1.1  ahoka 	  dbg(" ->vno:      %d\n", le64toh(dirent->vno));
    456  1.1  ahoka 	  dbg(" ->pvno:     %d\n", le64toh(dirent->pvno));
    457  1.1  ahoka 	  dbg(" ->version:  %ld\n", le64toh(dirent->version));
    458  1.1  ahoka 	  dbg(" ->mctime:   %d\n", le32toh(dirent->mctime));
    459  1.1  ahoka 	  dbg(" ->nsize:    %d\n", dirent->nsize);
    460  1.1  ahoka 	  dbg(" ->dtype:    %d\n", dirent->dtype);
    461  1.1  ahoka 	  dbg(" ->name_crc: 0x%x\n", le32toh(dirent->name_crc));
    462  1.1  ahoka 	  dbg(" ->node_crc: 0x%x\n", le32toh(dirent->node_crc));
    463  1.1  ahoka 	  dbg(" ->name:     %s\n", dirent->name);*/
    464  1.1  ahoka 
    465  1.1  ahoka 	return CHFS_NODE_OK;
    466  1.1  ahoka }
    467  1.1  ahoka 
    468  1.1  ahoka /**
    469  1.1  ahoka  * chfs_scan_check_data_node - check vnode crc and add to vnode cache
    470  1.1  ahoka  * @chmp: CHFS main descriptor structure
    471  1.1  ahoka  * @cheb: eraseblock informations
    472  1.1  ahoka  * @buf: data node to check
    473  1.1  ahoka  * @ofs: offset in eraseblock where data node starts
    474  1.1  ahoka  */
    475  1.1  ahoka int
    476  1.1  ahoka chfs_scan_check_data_node(struct chfs_mount *chmp,
    477  1.1  ahoka     struct chfs_eraseblock *cheb, void *buf, off_t ofs)
    478  1.1  ahoka {
    479  1.1  ahoka 	KASSERT(mutex_owned(&chmp->chm_lock_mountfields));
    480  1.1  ahoka 	int err;
    481  1.1  ahoka 	uint32_t crc, vno;
    482  1.1  ahoka 	struct chfs_node_ref *nref;
    483  1.1  ahoka 	struct chfs_vnode_cache *vc;
    484  1.1  ahoka 	struct chfs_flash_data_node *dnode = buf;
    485  1.1  ahoka 
    486  1.1  ahoka 	crc = crc32(0, (uint8_t *)dnode, sizeof(struct chfs_flash_data_node) - 4);
    487  1.1  ahoka 	if (crc != le32toh(dnode->node_crc)) {
    488  1.1  ahoka 		err = chfs_update_eb_dirty(chmp, cheb, le32toh(dnode->length));
    489  1.1  ahoka 		if (err)
    490  1.1  ahoka 			return err;
    491  1.1  ahoka 		return CHFS_NODE_BADCRC;
    492  1.1  ahoka 	}
    493  1.1  ahoka 	/**
    494  1.1  ahoka 	 * Don't check data nodes crc and version here, it will be done in
    495  1.1  ahoka 	 * the background GC thread.
    496  1.1  ahoka 	 */
    497  1.1  ahoka 	nref = chfs_alloc_node_ref(cheb);
    498  1.1  ahoka 	if (!nref)
    499  1.1  ahoka 		return ENOMEM;
    500  1.1  ahoka 
    501  1.3  ttoth 	nref->nref_offset = CHFS_GET_OFS(ofs) | CHFS_UNCHECKED_NODE_MASK;
    502  1.1  ahoka 
    503  1.1  ahoka 	KASSERT(nref->nref_lnr == cheb->lnr);
    504  1.1  ahoka 
    505  1.1  ahoka 	vno = le64toh(dnode->vno);
    506  1.1  ahoka 	mutex_enter(&chmp->chm_lock_vnocache);
    507  1.1  ahoka 	vc = chfs_vnode_cache_get(chmp, vno);
    508  1.1  ahoka 	if (!vc) {
    509  1.1  ahoka 		vc = chfs_scan_make_vnode_cache(chmp, vno);
    510  1.1  ahoka 		if (!vc)
    511  1.1  ahoka 			return ENOMEM;
    512  1.1  ahoka 	}
    513  1.3  ttoth 	chfs_add_node_to_list(chmp, vc, nref, &vc->dnode);
    514  1.1  ahoka 	mutex_exit(&chmp->chm_lock_vnocache);
    515  1.1  ahoka 
    516  1.1  ahoka 	dbg("chmpfree: %u, chebfree: %u, dnode: %u\n", chmp->chm_free_size, cheb->free_size, dnode->length);
    517  1.1  ahoka 
    518  1.1  ahoka 	mutex_enter(&chmp->chm_lock_sizes);
    519  1.1  ahoka 	chfs_change_size_free(chmp, cheb, -dnode->length);
    520  1.1  ahoka 	chfs_change_size_unchecked(chmp, cheb, dnode->length);
    521  1.1  ahoka 	mutex_exit(&chmp->chm_lock_sizes);
    522  1.1  ahoka 	return CHFS_NODE_OK;
    523  1.1  ahoka }
    524  1.1  ahoka 
    525  1.1  ahoka /**
    526  1.1  ahoka  * chfs_scan_classify_cheb - determine eraseblock's state
    527  1.1  ahoka  * @chmp: CHFS main descriptor structure
    528  1.1  ahoka  * @cheb: eraseblock to classify
    529  1.1  ahoka  */
    530  1.1  ahoka int
    531  1.1  ahoka chfs_scan_classify_cheb(struct chfs_mount *chmp,
    532  1.1  ahoka     struct chfs_eraseblock *cheb)
    533  1.1  ahoka {
    534  1.1  ahoka 	if (cheb->free_size == chmp->chm_ebh->eb_size)
    535  1.1  ahoka 		return CHFS_BLK_STATE_FREE;
    536  1.1  ahoka 	else if (cheb->dirty_size < MAX_DIRTY_TO_CLEAN)
    537  1.1  ahoka 		return CHFS_BLK_STATE_CLEAN;
    538  1.1  ahoka 	else if (cheb->used_size || cheb->unchecked_size)
    539  1.1  ahoka 		return CHFS_BLK_STATE_PARTDIRTY;
    540  1.1  ahoka 	else
    541  1.1  ahoka 		return CHFS_BLK_STATE_ALLDIRTY;
    542  1.1  ahoka }
    543  1.1  ahoka 
    544  1.1  ahoka 
    545  1.1  ahoka /**
    546  1.1  ahoka  * chfs_scan_eraseblock - scans an eraseblock and looking for nodes
    547  1.1  ahoka  * @chmp: CHFS main descriptor structure
    548  1.1  ahoka  * @cheb: eraseblock to scan
    549  1.1  ahoka  *
    550  1.1  ahoka  * This function scans a whole eraseblock, checks the nodes on it and add them
    551  1.1  ahoka  * to the vnode cache.
    552  1.1  ahoka  * Returns eraseblock state on success, error code if fails.
    553  1.1  ahoka  */
    554  1.1  ahoka int
    555  1.1  ahoka chfs_scan_eraseblock(struct chfs_mount *chmp,
    556  1.1  ahoka     struct chfs_eraseblock *cheb) {
    557  1.1  ahoka 
    558  1.1  ahoka 	int err;
    559  1.1  ahoka 	size_t len, retlen;
    560  1.1  ahoka 	off_t ofs = 0;
    561  1.1  ahoka 	int lnr = cheb->lnr;
    562  1.1  ahoka 	u_char *buf;
    563  1.1  ahoka 	struct chfs_flash_node_hdr *nhdr;
    564  1.1  ahoka 	int read_free = 0;
    565  1.1  ahoka 	struct chfs_node_ref *nref;
    566  1.1  ahoka 
    567  1.1  ahoka 
    568  1.1  ahoka 	dbg("scanning eraseblock content: %d free_size: %d\n", cheb->lnr, cheb->free_size);
    569  1.1  ahoka 	dbg("scanned physical block: %d\n", chmp->chm_ebh->lmap[lnr]);
    570  1.1  ahoka 	buf = kmem_alloc(CHFS_MAX_NODE_SIZE, KM_SLEEP);
    571  1.1  ahoka 
    572  1.1  ahoka 	while((ofs + CHFS_NODE_HDR_SIZE) < chmp->chm_ebh->eb_size) {
    573  1.1  ahoka 		memset(buf, 0 , CHFS_MAX_NODE_SIZE);
    574  1.1  ahoka 		err = chfs_read_leb(chmp,
    575  1.1  ahoka 		    lnr, buf, ofs, CHFS_NODE_HDR_SIZE, &retlen);
    576  1.1  ahoka 		if (err) {
    577  1.1  ahoka 			return err;
    578  1.1  ahoka 		}
    579  1.1  ahoka 
    580  1.1  ahoka 		if (retlen != CHFS_NODE_HDR_SIZE) {
    581  1.1  ahoka 			chfs_err("Error reading node header: "
    582  1.1  ahoka 			    "read: %zu instead of: %zu\n",
    583  1.1  ahoka 			    CHFS_NODE_HDR_SIZE, retlen);
    584  1.1  ahoka 			return EIO;
    585  1.1  ahoka 		}
    586  1.1  ahoka 
    587  1.1  ahoka 		/* first we check if the buffer we read is full with 0xff, if yes maybe
    588  1.1  ahoka 		 * the blocks remaining area is free. We increase read_free and if it
    589  1.1  ahoka 		 * reaches MAX_READ_FREE we stop reading the block*/
    590  1.1  ahoka 		if (check_pattern(buf, 0xff, 0, CHFS_NODE_HDR_SIZE)) {
    591  1.1  ahoka 			read_free += CHFS_NODE_HDR_SIZE;
    592  1.1  ahoka 			if (read_free >= MAX_READ_FREE(chmp)) {
    593  1.1  ahoka 				dbg("rest of the block is free. Size: %d\n", cheb->free_size);
    594  1.1  ahoka 				return chfs_scan_classify_cheb(chmp, cheb);
    595  1.1  ahoka 			}
    596  1.1  ahoka 			ofs += CHFS_NODE_HDR_SIZE;
    597  1.1  ahoka 			continue;
    598  1.1  ahoka 		} else {
    599  1.1  ahoka 			chfs_update_eb_dirty(chmp, cheb, read_free);
    600  1.1  ahoka 			read_free = 0;
    601  1.1  ahoka 		}
    602  1.1  ahoka 
    603  1.1  ahoka 		nhdr = (struct chfs_flash_node_hdr *)buf;
    604  1.1  ahoka 
    605  1.1  ahoka 		err = chfs_scan_check_node_hdr(nhdr);
    606  1.1  ahoka 		if (err) {
    607  1.1  ahoka 			dbg("node hdr error\n");
    608  1.1  ahoka 			err = chfs_update_eb_dirty(chmp, cheb, 4);
    609  1.1  ahoka 			if (err) {
    610  1.1  ahoka 				return err;
    611  1.1  ahoka 			}
    612  1.1  ahoka 
    613  1.1  ahoka 			ofs += 4;
    614  1.1  ahoka 			continue;
    615  1.1  ahoka 		}
    616  1.1  ahoka 		ofs += CHFS_NODE_HDR_SIZE;
    617  1.1  ahoka 		if (ofs > chmp->chm_ebh->eb_size) {
    618  1.1  ahoka 			chfs_err("Second part of node is on the next eraseblock.\n");
    619  1.1  ahoka 			return EIO;
    620  1.1  ahoka 		}
    621  1.1  ahoka 		switch (le16toh(nhdr->type)) {
    622  1.1  ahoka 		case CHFS_NODETYPE_VNODE:
    623  1.1  ahoka 			/* Read up the node */
    624  1.1  ahoka 			//dbg("nodetype vnode\n");
    625  1.1  ahoka 			len = le32toh(nhdr->length) - CHFS_NODE_HDR_SIZE;
    626  1.1  ahoka 			err = chfs_read_leb(chmp,
    627  1.1  ahoka 			    lnr, buf + CHFS_NODE_HDR_SIZE,
    628  1.1  ahoka 			    ofs, len,  &retlen);
    629  1.1  ahoka 			if (err) {
    630  1.1  ahoka 				return err;
    631  1.1  ahoka 			}
    632  1.1  ahoka 
    633  1.1  ahoka 			if (retlen != len) {
    634  1.1  ahoka 				chfs_err("Error reading vnode: read: %zu instead of: %zu\n",
    635  1.1  ahoka 				    len, retlen);
    636  1.1  ahoka 				return EIO;
    637  1.1  ahoka 			}
    638  1.1  ahoka 			KASSERT(lnr == cheb->lnr);
    639  1.1  ahoka 			err = chfs_scan_check_vnode(chmp,
    640  1.1  ahoka 			    cheb, buf, ofs - CHFS_NODE_HDR_SIZE);
    641  1.1  ahoka 			if (err) {
    642  1.1  ahoka 				return err;
    643  1.1  ahoka 			}
    644  1.1  ahoka 
    645  1.1  ahoka 			//dbg("XXX5end\n");
    646  1.1  ahoka 			break;
    647  1.1  ahoka 		case CHFS_NODETYPE_DIRENT:
    648  1.1  ahoka 			/* Read up the node */
    649  1.1  ahoka 			//dbg("nodetype dirent\n");
    650  1.1  ahoka 			len = le32toh(nhdr->length) - CHFS_NODE_HDR_SIZE;
    651  1.1  ahoka 
    652  1.1  ahoka 			err = chfs_read_leb(chmp,
    653  1.1  ahoka 			    lnr, buf + CHFS_NODE_HDR_SIZE,
    654  1.1  ahoka 			    ofs, len, &retlen);
    655  1.1  ahoka 			if (err) {
    656  1.1  ahoka 				return err;
    657  1.1  ahoka 			}
    658  1.1  ahoka 
    659  1.1  ahoka 			if (retlen != len) {
    660  1.1  ahoka 				chfs_err("Error reading dirent node: read: %zu "
    661  1.1  ahoka 				    "instead of: %zu\n", len, retlen);
    662  1.1  ahoka 				return EIO;
    663  1.1  ahoka 			}
    664  1.1  ahoka 
    665  1.1  ahoka 			KASSERT(lnr == cheb->lnr);
    666  1.1  ahoka 
    667  1.1  ahoka 			err = chfs_scan_check_dirent_node(chmp,
    668  1.1  ahoka 			    cheb, buf, ofs - CHFS_NODE_HDR_SIZE);
    669  1.1  ahoka 			if (err) {
    670  1.1  ahoka 				return err;
    671  1.1  ahoka 			}
    672  1.1  ahoka 
    673  1.1  ahoka 			//dbg("XXX6end\n");
    674  1.1  ahoka 			break;
    675  1.1  ahoka 		case CHFS_NODETYPE_DATA:
    676  1.1  ahoka 			//dbg("nodetype data\n");
    677  1.1  ahoka 			len = sizeof(struct chfs_flash_data_node) -
    678  1.1  ahoka 			    CHFS_NODE_HDR_SIZE;
    679  1.1  ahoka 			err = chfs_read_leb(chmp,
    680  1.1  ahoka 			    lnr, buf + CHFS_NODE_HDR_SIZE,
    681  1.1  ahoka 			    ofs, len, &retlen);
    682  1.1  ahoka 			if (err) {
    683  1.1  ahoka 				return err;
    684  1.1  ahoka 			}
    685  1.1  ahoka 
    686  1.1  ahoka 			if (retlen != len) {
    687  1.1  ahoka 				chfs_err("Error reading data node: read: %zu "
    688  1.1  ahoka 				    "instead of: %zu\n", len, retlen);
    689  1.1  ahoka 				return EIO;
    690  1.1  ahoka 			}
    691  1.1  ahoka 			KASSERT(lnr == cheb->lnr);
    692  1.1  ahoka 			err = chfs_scan_check_data_node(chmp,
    693  1.1  ahoka 			    cheb, buf, ofs - CHFS_NODE_HDR_SIZE);
    694  1.1  ahoka 			if (err)
    695  1.1  ahoka 				return err;
    696  1.1  ahoka 
    697  1.1  ahoka 			//dbg("XXX7end\n");
    698  1.1  ahoka 			break;
    699  1.1  ahoka 		case CHFS_NODETYPE_PADDING:
    700  1.1  ahoka 			//dbg("nodetype padding\n");
    701  1.1  ahoka 			//dbg("padding len: %d\n", le32toh(nhdr->length));
    702  1.1  ahoka 			//dbg("BEF: cheb->free_size: %d\n", cheb->free_size);
    703  1.1  ahoka 			nref = chfs_alloc_node_ref(cheb);
    704  1.1  ahoka 			nref->nref_offset = ofs - CHFS_NODE_HDR_SIZE;
    705  1.1  ahoka 			nref->nref_offset = CHFS_GET_OFS(nref->nref_offset) |
    706  1.1  ahoka 			    CHFS_OBSOLETE_NODE_MASK;
    707  1.1  ahoka 
    708  1.1  ahoka 			err = chfs_update_eb_dirty(chmp, cheb,
    709  1.1  ahoka 			    le32toh(nhdr->length));
    710  1.1  ahoka 			//dbg("AFT: cheb->free_size: %d\n", cheb->free_size);
    711  1.1  ahoka 			if (err)
    712  1.1  ahoka 				return err;
    713  1.1  ahoka 
    714  1.1  ahoka 			//dbg("XXX8end\n");
    715  1.1  ahoka 			break;
    716  1.1  ahoka 		default:
    717  1.1  ahoka 			//dbg("nodetype ? (default)\n");
    718  1.1  ahoka 			/* Unknown node type, update dirty and skip */
    719  1.1  ahoka 			err = chfs_update_eb_dirty(chmp, cheb,
    720  1.1  ahoka 			    le32toh(nhdr->length));
    721  1.1  ahoka 			if (err)
    722  1.1  ahoka 				return err;
    723  1.1  ahoka 
    724  1.1  ahoka 			//dbg("XXX9end\n");
    725  1.1  ahoka 			break;
    726  1.1  ahoka 		}
    727  1.1  ahoka 		ofs += le32toh(nhdr->length) - CHFS_NODE_HDR_SIZE;
    728  1.1  ahoka 	}
    729  1.1  ahoka 
    730  1.1  ahoka 	KASSERT(cheb->used_size + cheb->free_size + cheb->dirty_size +
    731  1.1  ahoka 	    cheb->unchecked_size + cheb->wasted_size == chmp->chm_ebh->eb_size);
    732  1.1  ahoka 
    733  1.1  ahoka 	//dbg("XXX10\n");
    734  1.1  ahoka 	return chfs_scan_classify_cheb(chmp, cheb);
    735  1.1  ahoka }
    736