Home | History | Annotate | Line # | Download | only in chfs
chfs_scan.c revision 1.6
      1  1.6  christos /*	$NetBSD: chfs_scan.c,v 1.6 2015/02/07 04:19:52 christos 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 #include "chfs.h"
     35  1.1     ahoka 
     36  1.4     ttoth /*
     37  1.1     ahoka  * chfs_scan_make_vnode_cache - makes a new vnode cache during scan
     38  1.1     ahoka  * This function returns a vnode cache belonging to @vno.
     39  1.1     ahoka  */
     40  1.1     ahoka struct chfs_vnode_cache *
     41  1.1     ahoka chfs_scan_make_vnode_cache(struct chfs_mount *chmp, ino_t vno)
     42  1.1     ahoka {
     43  1.1     ahoka 	struct chfs_vnode_cache *vc;
     44  1.1     ahoka 
     45  1.1     ahoka 	KASSERT(mutex_owned(&chmp->chm_lock_vnocache));
     46  1.1     ahoka 
     47  1.4     ttoth 	/* vnode cache already exists */
     48  1.1     ahoka 	vc = chfs_vnode_cache_get(chmp, vno);
     49  1.1     ahoka 	if (vc) {
     50  1.1     ahoka 		return vc;
     51  1.1     ahoka 	}
     52  1.1     ahoka 
     53  1.4     ttoth 	/* update max vnode number if needed */
     54  1.1     ahoka 	if (vno > chmp->chm_max_vno) {
     55  1.1     ahoka 		chmp->chm_max_vno = vno;
     56  1.1     ahoka 	}
     57  1.1     ahoka 
     58  1.4     ttoth 	/* create new vnode cache */
     59  1.1     ahoka 	vc = chfs_vnode_cache_alloc(vno);
     60  1.1     ahoka 
     61  1.1     ahoka 	chfs_vnode_cache_add(chmp, vc);
     62  1.1     ahoka 
     63  1.1     ahoka 	if (vno == CHFS_ROOTINO) {
     64  1.1     ahoka 		vc->nlink = 2;
     65  1.1     ahoka 		vc->pvno = CHFS_ROOTINO;
     66  1.3     ttoth 		vc->state = VNO_STATE_CHECKEDABSENT;
     67  1.1     ahoka 	}
     68  1.1     ahoka 
     69  1.1     ahoka 	return vc;
     70  1.1     ahoka }
     71  1.1     ahoka 
     72  1.4     ttoth /*
     73  1.1     ahoka  * chfs_scan_check_node_hdr - checks node magic and crc
     74  1.1     ahoka  * Returns 0 if everything is OK, error code otherwise.
     75  1.1     ahoka  */
     76  1.1     ahoka int
     77  1.1     ahoka chfs_scan_check_node_hdr(struct chfs_flash_node_hdr *nhdr)
     78  1.1     ahoka {
     79  1.1     ahoka 	uint16_t magic;
     80  1.1     ahoka 	uint32_t crc, hdr_crc;
     81  1.1     ahoka 
     82  1.1     ahoka 	magic = le16toh(nhdr->magic);
     83  1.1     ahoka 
     84  1.1     ahoka 	if (magic != CHFS_FS_MAGIC_BITMASK) {
     85  1.1     ahoka 		dbg("bad magic\n");
     86  1.1     ahoka 		return CHFS_NODE_BADMAGIC;
     87  1.1     ahoka 	}
     88  1.1     ahoka 
     89  1.1     ahoka 	hdr_crc = le32toh(nhdr->hdr_crc);
     90  1.1     ahoka 	crc = crc32(0, (uint8_t *)nhdr, CHFS_NODE_HDR_SIZE - 4);
     91  1.1     ahoka 
     92  1.1     ahoka 	if (crc != hdr_crc) {
     93  1.1     ahoka 		dbg("bad crc\n");
     94  1.1     ahoka 		return CHFS_NODE_BADCRC;
     95  1.1     ahoka 	}
     96  1.1     ahoka 
     97  1.1     ahoka 	return CHFS_NODE_OK;
     98  1.1     ahoka }
     99  1.1     ahoka 
    100  1.4     ttoth /* chfs_scan_check_vnode - check vnode crc and add it to vnode cache */
    101  1.1     ahoka int
    102  1.1     ahoka chfs_scan_check_vnode(struct chfs_mount *chmp,
    103  1.1     ahoka     struct chfs_eraseblock *cheb, void *buf, off_t ofs)
    104  1.1     ahoka {
    105  1.1     ahoka 	KASSERT(mutex_owned(&chmp->chm_lock_mountfields));
    106  1.1     ahoka 	struct chfs_vnode_cache *vc;
    107  1.1     ahoka 	struct chfs_flash_vnode *vnode = buf;
    108  1.1     ahoka 	struct chfs_node_ref *nref;
    109  1.1     ahoka 	int err;
    110  1.1     ahoka 	uint32_t crc;
    111  1.1     ahoka 	ino_t vno;
    112  1.1     ahoka 
    113  1.1     ahoka 	crc = crc32(0, (uint8_t *)vnode,
    114  1.1     ahoka 	    sizeof(struct chfs_flash_vnode) - 4);
    115  1.1     ahoka 
    116  1.4     ttoth 	/* check node crc */
    117  1.1     ahoka 	if (crc != le32toh(vnode->node_crc)) {
    118  1.1     ahoka 		err = chfs_update_eb_dirty(chmp,
    119  1.1     ahoka 		    cheb, le32toh(vnode->length));
    120  1.1     ahoka 		if (err) {
    121  1.1     ahoka 			return err;
    122  1.1     ahoka 		}
    123  1.1     ahoka 
    124  1.1     ahoka 		return CHFS_NODE_BADCRC;
    125  1.1     ahoka 	}
    126  1.1     ahoka 
    127  1.1     ahoka 	vno = le64toh(vnode->vno);
    128  1.1     ahoka 
    129  1.4     ttoth 	/* find the corresponding vnode cache */
    130  1.1     ahoka 	mutex_enter(&chmp->chm_lock_vnocache);
    131  1.1     ahoka 	vc = chfs_vnode_cache_get(chmp, vno);
    132  1.1     ahoka 	if (!vc) {
    133  1.1     ahoka 		vc = chfs_scan_make_vnode_cache(chmp, vno);
    134  1.1     ahoka 		if (!vc) {
    135  1.1     ahoka 			mutex_exit(&chmp->chm_lock_vnocache);
    136  1.1     ahoka 			return ENOMEM;
    137  1.1     ahoka 		}
    138  1.1     ahoka 	}
    139  1.1     ahoka 
    140  1.1     ahoka 	nref = chfs_alloc_node_ref(cheb);
    141  1.1     ahoka 
    142  1.1     ahoka 	nref->nref_offset = ofs;
    143  1.1     ahoka 
    144  1.1     ahoka 	KASSERT(nref->nref_lnr == cheb->lnr);
    145  1.1     ahoka 
    146  1.4     ttoth 	/* check version of vnode */
    147  1.1     ahoka 	if ((struct chfs_vnode_cache *)vc->v != vc) {
    148  1.1     ahoka 		if (le64toh(vnode->version) > *vc->vno_version) {
    149  1.1     ahoka 			*vc->vno_version = le64toh(vnode->version);
    150  1.1     ahoka 			chfs_add_vnode_ref_to_vc(chmp, vc, nref);
    151  1.1     ahoka 		} else {
    152  1.1     ahoka 			err = chfs_update_eb_dirty(chmp, cheb,
    153  1.1     ahoka 			    sizeof(struct chfs_flash_vnode));
    154  1.1     ahoka 			return CHFS_NODE_OK;
    155  1.1     ahoka 		}
    156  1.1     ahoka 	} else {
    157  1.1     ahoka 		vc->vno_version = kmem_alloc(sizeof(uint64_t), KM_SLEEP);
    158  1.1     ahoka 		if (!vc->vno_version)
    159  1.1     ahoka 			return ENOMEM;
    160  1.1     ahoka 		*vc->vno_version = le64toh(vnode->version);
    161  1.1     ahoka 		chfs_add_vnode_ref_to_vc(chmp, vc, nref);
    162  1.1     ahoka 	}
    163  1.3     ttoth 	mutex_exit(&chmp->chm_lock_vnocache);
    164  1.1     ahoka 
    165  1.4     ttoth 	/* update sizes */
    166  1.1     ahoka 	mutex_enter(&chmp->chm_lock_sizes);
    167  1.1     ahoka 	chfs_change_size_free(chmp, cheb, -le32toh(vnode->length));
    168  1.1     ahoka 	chfs_change_size_used(chmp, cheb, le32toh(vnode->length));
    169  1.1     ahoka 	mutex_exit(&chmp->chm_lock_sizes);
    170  1.1     ahoka 
    171  1.1     ahoka 	KASSERT(cheb->used_size <= chmp->chm_ebh->eb_size);
    172  1.1     ahoka 
    173  1.1     ahoka 	KASSERT(cheb->used_size + cheb->free_size + cheb->dirty_size + cheb->unchecked_size + cheb->wasted_size == chmp->chm_ebh->eb_size);
    174  1.1     ahoka 
    175  1.1     ahoka 	return CHFS_NODE_OK;
    176  1.1     ahoka }
    177  1.1     ahoka 
    178  1.4     ttoth /* chfs_scan_mark_dirent_obsolete - marks a directory entry "obsolete" */
    179  1.1     ahoka int
    180  1.1     ahoka chfs_scan_mark_dirent_obsolete(struct chfs_mount *chmp,
    181  1.1     ahoka     struct chfs_vnode_cache *vc, struct chfs_dirent *fd)
    182  1.1     ahoka {
    183  1.1     ahoka 	struct chfs_eraseblock *cheb;
    184  1.1     ahoka 	struct chfs_node_ref *prev, *nref;
    185  1.1     ahoka 
    186  1.1     ahoka 	nref = fd->nref;
    187  1.1     ahoka 	cheb = &chmp->chm_blocks[fd->nref->nref_lnr];
    188  1.1     ahoka 
    189  1.4     ttoth 	/* remove dirent's node ref from vnode cache */
    190  1.1     ahoka 	prev = vc->dirents;
    191  1.1     ahoka 	if (prev && prev == nref) {
    192  1.1     ahoka 		vc->dirents = prev->nref_next;
    193  1.1     ahoka 	} else if (prev && prev != (void *)vc) {
    194  1.3     ttoth 		while (prev->nref_next && prev->nref_next != (void *)vc) {
    195  1.3     ttoth 			if (prev->nref_next == nref) {
    196  1.3     ttoth 				prev->nref_next = nref->nref_next;
    197  1.3     ttoth 				break;
    198  1.3     ttoth 			}
    199  1.1     ahoka 			prev = prev->nref_next;
    200  1.1     ahoka 		}
    201  1.3     ttoth 	}
    202  1.1     ahoka 
    203  1.1     ahoka 	KASSERT(cheb->used_size + cheb->free_size + cheb->dirty_size +
    204  1.1     ahoka 	    cheb->unchecked_size + cheb->wasted_size == chmp->chm_ebh->eb_size);
    205  1.1     ahoka 
    206  1.1     ahoka 	return 0;
    207  1.1     ahoka }
    208  1.1     ahoka 
    209  1.4     ttoth /* chfs_add_fd_to_list - adds a directory entry to its parent's vnode cache */
    210  1.1     ahoka void
    211  1.1     ahoka chfs_add_fd_to_list(struct chfs_mount *chmp,
    212  1.1     ahoka     struct chfs_dirent *new, struct chfs_vnode_cache *pvc)
    213  1.1     ahoka {
    214  1.1     ahoka 	KASSERT(mutex_owned(&chmp->chm_lock_mountfields));
    215  1.1     ahoka 	int size;
    216  1.1     ahoka 	struct chfs_eraseblock *cheb, *oldcheb;
    217  1.1     ahoka 	struct chfs_dirent *fd, *tmpfd;
    218  1.1     ahoka 
    219  1.1     ahoka 	dbg("adding fd to list: %s\n", new->name);
    220  1.1     ahoka 
    221  1.4     ttoth 	/* update highest version if needed */
    222  1.1     ahoka 	if ((new->version > pvc->highest_version))
    223  1.1     ahoka 		pvc->highest_version = new->version;
    224  1.1     ahoka 
    225  1.1     ahoka 	size = CHFS_PAD(sizeof(struct chfs_flash_dirent_node) +
    226  1.1     ahoka 	    new->nsize);
    227  1.1     ahoka 	cheb = &chmp->chm_blocks[new->nref->nref_lnr];
    228  1.1     ahoka 
    229  1.1     ahoka 	mutex_enter(&chmp->chm_lock_sizes);
    230  1.1     ahoka 	TAILQ_FOREACH_SAFE(fd, &pvc->scan_dirents, fds, tmpfd) {
    231  1.1     ahoka 		if (fd->nhash > new->nhash) {
    232  1.1     ahoka 			/* insert new before fd */
    233  1.1     ahoka 			TAILQ_INSERT_BEFORE(fd, new, fds);
    234  1.1     ahoka 			goto out;
    235  1.1     ahoka 		} else if (fd->nhash == new->nhash &&
    236  1.1     ahoka 		    !strcmp(fd->name, new->name)) {
    237  1.1     ahoka 			if (new->version > fd->version) {
    238  1.1     ahoka 				/* replace fd with new */
    239  1.1     ahoka 				TAILQ_INSERT_BEFORE(fd, new, fds);
    240  1.1     ahoka 				chfs_change_size_free(chmp, cheb, -size);
    241  1.1     ahoka 				chfs_change_size_used(chmp, cheb, size);
    242  1.1     ahoka 
    243  1.1     ahoka 				TAILQ_REMOVE(&pvc->scan_dirents, fd, fds);
    244  1.1     ahoka 				if (fd->nref) {
    245  1.1     ahoka 					size = CHFS_PAD(sizeof(struct chfs_flash_dirent_node) + fd->nsize);
    246  1.1     ahoka 					chfs_scan_mark_dirent_obsolete(chmp, pvc, fd);
    247  1.1     ahoka 					oldcheb = &chmp->chm_blocks[fd->nref->nref_lnr];
    248  1.1     ahoka 					chfs_change_size_used(chmp, oldcheb, -size);
    249  1.1     ahoka 					chfs_change_size_dirty(chmp, oldcheb, size);
    250  1.1     ahoka 				}
    251  1.1     ahoka 				chfs_free_dirent(fd);
    252  1.1     ahoka 			} else {
    253  1.4     ttoth 				/* new dirent is older */
    254  1.1     ahoka 				chfs_scan_mark_dirent_obsolete(chmp, pvc, new);
    255  1.1     ahoka 				chfs_change_size_free(chmp, cheb, -size);
    256  1.1     ahoka 				chfs_change_size_dirty(chmp, cheb, size);
    257  1.1     ahoka 				chfs_free_dirent(new);
    258  1.1     ahoka 			}
    259  1.1     ahoka 			mutex_exit(&chmp->chm_lock_sizes);
    260  1.1     ahoka 			return;
    261  1.1     ahoka 		}
    262  1.1     ahoka 	}
    263  1.1     ahoka 	/* if we couldnt fit it elsewhere, lets add to the end */
    264  1.1     ahoka 	TAILQ_INSERT_TAIL(&pvc->scan_dirents, new, fds);
    265  1.1     ahoka 
    266  1.1     ahoka out:
    267  1.4     ttoth 	/* update sizes */
    268  1.1     ahoka 	chfs_change_size_free(chmp, cheb, -size);
    269  1.1     ahoka 	chfs_change_size_used(chmp, cheb, size);
    270  1.1     ahoka 	mutex_exit(&chmp->chm_lock_sizes);
    271  1.1     ahoka 
    272  1.1     ahoka 	KASSERT(cheb->used_size <= chmp->chm_ebh->eb_size);
    273  1.1     ahoka 
    274  1.1     ahoka 	KASSERT(cheb->used_size + cheb->free_size + cheb->dirty_size + cheb->unchecked_size + cheb->wasted_size == chmp->chm_ebh->eb_size);
    275  1.4     ttoth }
    276  1.1     ahoka 
    277  1.4     ttoth /* chfs_scan_check_dirent_node - check vnode crc and add to vnode cache */
    278  1.1     ahoka int
    279  1.1     ahoka chfs_scan_check_dirent_node(struct chfs_mount *chmp,
    280  1.1     ahoka     struct chfs_eraseblock *cheb, void *buf, off_t ofs)
    281  1.1     ahoka {
    282  1.1     ahoka 	int err, namelen;
    283  1.1     ahoka 	uint32_t crc;
    284  1.1     ahoka 	struct chfs_dirent *fd;
    285  1.3     ttoth 	struct chfs_vnode_cache *parentvc;
    286  1.1     ahoka 	struct chfs_flash_dirent_node *dirent = buf;
    287  1.1     ahoka 
    288  1.4     ttoth 	/* check crc */
    289  1.1     ahoka 	crc = crc32(0, (uint8_t *)dirent, sizeof(*dirent) - 4);
    290  1.1     ahoka 	if (crc != le32toh(dirent->node_crc)) {
    291  1.1     ahoka 		err = chfs_update_eb_dirty(chmp, cheb, le32toh(dirent->length));
    292  1.1     ahoka 		if (err)
    293  1.1     ahoka 			return err;
    294  1.1     ahoka 		return CHFS_NODE_BADCRC;
    295  1.1     ahoka 	}
    296  1.4     ttoth 
    297  1.4     ttoth 	/* allocate space for name */
    298  1.1     ahoka 	namelen = dirent->nsize;
    299  1.1     ahoka 
    300  1.1     ahoka 	fd = chfs_alloc_dirent(namelen + 1);
    301  1.1     ahoka 	if (!fd)
    302  1.1     ahoka 		return ENOMEM;
    303  1.1     ahoka 
    304  1.4     ttoth 	/* allocate an nref */
    305  1.1     ahoka 	fd->nref = chfs_alloc_node_ref(cheb);
    306  1.1     ahoka 	if (!fd->nref)
    307  1.1     ahoka 		return ENOMEM;
    308  1.1     ahoka 
    309  1.1     ahoka 	KASSERT(fd->nref->nref_lnr == cheb->lnr);
    310  1.1     ahoka 
    311  1.1     ahoka 	memcpy(&fd->name, dirent->name, namelen);
    312  1.1     ahoka 	fd->nsize = namelen;
    313  1.1     ahoka 	fd->name[namelen] = 0;
    314  1.1     ahoka 	crc = crc32(0, fd->name, dirent->nsize);
    315  1.1     ahoka 	if (crc != le32toh(dirent->name_crc)) {
    316  1.1     ahoka 		chfs_err("Directory entry's name has bad crc: read: 0x%x, "
    317  1.1     ahoka 		    "calculated: 0x%x\n", le32toh(dirent->name_crc), crc);
    318  1.1     ahoka 		chfs_free_dirent(fd);
    319  1.1     ahoka 		err = chfs_update_eb_dirty(chmp, cheb, le32toh(dirent->length));
    320  1.1     ahoka 		if (err)
    321  1.1     ahoka 			return err;
    322  1.1     ahoka 		return CHFS_NODE_BADNAMECRC;
    323  1.1     ahoka 	}
    324  1.1     ahoka 
    325  1.4     ttoth 	/* check vnode_cache of parent node */
    326  1.1     ahoka 	mutex_enter(&chmp->chm_lock_vnocache);
    327  1.3     ttoth 	parentvc = chfs_scan_make_vnode_cache(chmp, le64toh(dirent->pvno));
    328  1.3     ttoth 	if (!parentvc) {
    329  1.1     ahoka 		chfs_free_dirent(fd);
    330  1.1     ahoka 		return ENOMEM;
    331  1.1     ahoka 	}
    332  1.1     ahoka 
    333  1.1     ahoka 	fd->nref->nref_offset = ofs;
    334  1.1     ahoka 
    335  1.3     ttoth 	dbg("add dirent to #%llu\n", (unsigned long long)parentvc->vno);
    336  1.3     ttoth 	chfs_add_node_to_list(chmp, parentvc, fd->nref, &parentvc->dirents);
    337  1.3     ttoth 	mutex_exit(&chmp->chm_lock_vnocache);
    338  1.1     ahoka 
    339  1.1     ahoka 	fd->vno = le64toh(dirent->vno);
    340  1.1     ahoka 	fd->version = le64toh(dirent->version);
    341  1.1     ahoka 	fd->nhash = hash32_buf(fd->name, namelen, HASH32_BUF_INIT);
    342  1.1     ahoka 	fd->type = dirent->dtype;
    343  1.1     ahoka 
    344  1.3     ttoth 	chfs_add_fd_to_list(chmp, fd, parentvc);
    345  1.1     ahoka 
    346  1.1     ahoka 	return CHFS_NODE_OK;
    347  1.1     ahoka }
    348  1.1     ahoka 
    349  1.4     ttoth /* chfs_scan_check_data_node - check vnode crc and add to vnode cache */
    350  1.1     ahoka int
    351  1.1     ahoka chfs_scan_check_data_node(struct chfs_mount *chmp,
    352  1.1     ahoka     struct chfs_eraseblock *cheb, void *buf, off_t ofs)
    353  1.1     ahoka {
    354  1.1     ahoka 	KASSERT(mutex_owned(&chmp->chm_lock_mountfields));
    355  1.1     ahoka 	int err;
    356  1.1     ahoka 	uint32_t crc, vno;
    357  1.1     ahoka 	struct chfs_node_ref *nref;
    358  1.1     ahoka 	struct chfs_vnode_cache *vc;
    359  1.1     ahoka 	struct chfs_flash_data_node *dnode = buf;
    360  1.1     ahoka 
    361  1.4     ttoth 	/* check crc */
    362  1.1     ahoka 	crc = crc32(0, (uint8_t *)dnode, sizeof(struct chfs_flash_data_node) - 4);
    363  1.1     ahoka 	if (crc != le32toh(dnode->node_crc)) {
    364  1.1     ahoka 		err = chfs_update_eb_dirty(chmp, cheb, le32toh(dnode->length));
    365  1.1     ahoka 		if (err)
    366  1.1     ahoka 			return err;
    367  1.1     ahoka 		return CHFS_NODE_BADCRC;
    368  1.1     ahoka 	}
    369  1.4     ttoth 	/*
    370  1.1     ahoka 	 * Don't check data nodes crc and version here, it will be done in
    371  1.1     ahoka 	 * the background GC thread.
    372  1.1     ahoka 	 */
    373  1.1     ahoka 	nref = chfs_alloc_node_ref(cheb);
    374  1.1     ahoka 	if (!nref)
    375  1.1     ahoka 		return ENOMEM;
    376  1.1     ahoka 
    377  1.3     ttoth 	nref->nref_offset = CHFS_GET_OFS(ofs) | CHFS_UNCHECKED_NODE_MASK;
    378  1.1     ahoka 
    379  1.1     ahoka 	KASSERT(nref->nref_lnr == cheb->lnr);
    380  1.1     ahoka 
    381  1.1     ahoka 	vno = le64toh(dnode->vno);
    382  1.1     ahoka 	mutex_enter(&chmp->chm_lock_vnocache);
    383  1.1     ahoka 	vc = chfs_vnode_cache_get(chmp, vno);
    384  1.1     ahoka 	if (!vc) {
    385  1.1     ahoka 		vc = chfs_scan_make_vnode_cache(chmp, vno);
    386  1.1     ahoka 		if (!vc)
    387  1.1     ahoka 			return ENOMEM;
    388  1.1     ahoka 	}
    389  1.3     ttoth 	chfs_add_node_to_list(chmp, vc, nref, &vc->dnode);
    390  1.1     ahoka 	mutex_exit(&chmp->chm_lock_vnocache);
    391  1.1     ahoka 
    392  1.1     ahoka 	dbg("chmpfree: %u, chebfree: %u, dnode: %u\n", chmp->chm_free_size, cheb->free_size, dnode->length);
    393  1.1     ahoka 
    394  1.4     ttoth 	/* update sizes */
    395  1.1     ahoka 	mutex_enter(&chmp->chm_lock_sizes);
    396  1.1     ahoka 	chfs_change_size_free(chmp, cheb, -dnode->length);
    397  1.1     ahoka 	chfs_change_size_unchecked(chmp, cheb, dnode->length);
    398  1.1     ahoka 	mutex_exit(&chmp->chm_lock_sizes);
    399  1.1     ahoka 	return CHFS_NODE_OK;
    400  1.1     ahoka }
    401  1.1     ahoka 
    402  1.4     ttoth /* chfs_scan_classify_cheb - determine eraseblock's state */
    403  1.1     ahoka int
    404  1.1     ahoka chfs_scan_classify_cheb(struct chfs_mount *chmp,
    405  1.1     ahoka     struct chfs_eraseblock *cheb)
    406  1.1     ahoka {
    407  1.1     ahoka 	if (cheb->free_size == chmp->chm_ebh->eb_size)
    408  1.1     ahoka 		return CHFS_BLK_STATE_FREE;
    409  1.1     ahoka 	else if (cheb->dirty_size < MAX_DIRTY_TO_CLEAN)
    410  1.1     ahoka 		return CHFS_BLK_STATE_CLEAN;
    411  1.1     ahoka 	else if (cheb->used_size || cheb->unchecked_size)
    412  1.1     ahoka 		return CHFS_BLK_STATE_PARTDIRTY;
    413  1.1     ahoka 	else
    414  1.1     ahoka 		return CHFS_BLK_STATE_ALLDIRTY;
    415  1.1     ahoka }
    416  1.1     ahoka 
    417  1.1     ahoka 
    418  1.4     ttoth /*
    419  1.1     ahoka  * chfs_scan_eraseblock - scans an eraseblock and looking for nodes
    420  1.1     ahoka  *
    421  1.1     ahoka  * This function scans a whole eraseblock, checks the nodes on it and add them
    422  1.1     ahoka  * to the vnode cache.
    423  1.1     ahoka  * Returns eraseblock state on success, error code if fails.
    424  1.1     ahoka  */
    425  1.1     ahoka int
    426  1.1     ahoka chfs_scan_eraseblock(struct chfs_mount *chmp,
    427  1.4     ttoth     struct chfs_eraseblock *cheb)
    428  1.4     ttoth {
    429  1.1     ahoka 	int err;
    430  1.1     ahoka 	size_t len, retlen;
    431  1.1     ahoka 	off_t ofs = 0;
    432  1.1     ahoka 	int lnr = cheb->lnr;
    433  1.1     ahoka 	u_char *buf;
    434  1.1     ahoka 	struct chfs_flash_node_hdr *nhdr;
    435  1.1     ahoka 	int read_free = 0;
    436  1.1     ahoka 	struct chfs_node_ref *nref;
    437  1.1     ahoka 
    438  1.1     ahoka 	dbg("scanning eraseblock content: %d free_size: %d\n", cheb->lnr, cheb->free_size);
    439  1.1     ahoka 	dbg("scanned physical block: %d\n", chmp->chm_ebh->lmap[lnr]);
    440  1.1     ahoka 	buf = kmem_alloc(CHFS_MAX_NODE_SIZE, KM_SLEEP);
    441  1.1     ahoka 
    442  1.1     ahoka 	while((ofs + CHFS_NODE_HDR_SIZE) < chmp->chm_ebh->eb_size) {
    443  1.1     ahoka 		memset(buf, 0 , CHFS_MAX_NODE_SIZE);
    444  1.1     ahoka 		err = chfs_read_leb(chmp,
    445  1.1     ahoka 		    lnr, buf, ofs, CHFS_NODE_HDR_SIZE, &retlen);
    446  1.5        he 		if (err)
    447  1.5        he 			goto err_return;
    448  1.1     ahoka 
    449  1.1     ahoka 		if (retlen != CHFS_NODE_HDR_SIZE) {
    450  1.1     ahoka 			chfs_err("Error reading node header: "
    451  1.1     ahoka 			    "read: %zu instead of: %zu\n",
    452  1.1     ahoka 			    CHFS_NODE_HDR_SIZE, retlen);
    453  1.5        he 			err = EIO;
    454  1.5        he 			goto err_return;
    455  1.1     ahoka 		}
    456  1.1     ahoka 
    457  1.1     ahoka 		/* first we check if the buffer we read is full with 0xff, if yes maybe
    458  1.1     ahoka 		 * the blocks remaining area is free. We increase read_free and if it
    459  1.4     ttoth 		 * reaches MAX_READ_FREE we stop reading the block */
    460  1.1     ahoka 		if (check_pattern(buf, 0xff, 0, CHFS_NODE_HDR_SIZE)) {
    461  1.1     ahoka 			read_free += CHFS_NODE_HDR_SIZE;
    462  1.1     ahoka 			if (read_free >= MAX_READ_FREE(chmp)) {
    463  1.1     ahoka 				dbg("rest of the block is free. Size: %d\n", cheb->free_size);
    464  1.6  christos 				kmem_free(buf, CHFS_MAX_NODE_SIZE);
    465  1.1     ahoka 				return chfs_scan_classify_cheb(chmp, cheb);
    466  1.1     ahoka 			}
    467  1.1     ahoka 			ofs += CHFS_NODE_HDR_SIZE;
    468  1.1     ahoka 			continue;
    469  1.1     ahoka 		} else {
    470  1.1     ahoka 			chfs_update_eb_dirty(chmp, cheb, read_free);
    471  1.1     ahoka 			read_free = 0;
    472  1.1     ahoka 		}
    473  1.1     ahoka 
    474  1.1     ahoka 		nhdr = (struct chfs_flash_node_hdr *)buf;
    475  1.1     ahoka 
    476  1.1     ahoka 		err = chfs_scan_check_node_hdr(nhdr);
    477  1.1     ahoka 		if (err) {
    478  1.1     ahoka 			dbg("node hdr error\n");
    479  1.1     ahoka 			err = chfs_update_eb_dirty(chmp, cheb, 4);
    480  1.5        he 			if (err)
    481  1.5        he 				goto err_return;
    482  1.1     ahoka 
    483  1.1     ahoka 			ofs += 4;
    484  1.1     ahoka 			continue;
    485  1.1     ahoka 		}
    486  1.1     ahoka 		ofs += CHFS_NODE_HDR_SIZE;
    487  1.1     ahoka 		if (ofs > chmp->chm_ebh->eb_size) {
    488  1.1     ahoka 			chfs_err("Second part of node is on the next eraseblock.\n");
    489  1.5        he 			err = EIO;
    490  1.5        he 			goto err_return;
    491  1.1     ahoka 		}
    492  1.1     ahoka 		switch (le16toh(nhdr->type)) {
    493  1.1     ahoka 		case CHFS_NODETYPE_VNODE:
    494  1.4     ttoth 		/* vnode information */
    495  1.4     ttoth 			/* read up the node */
    496  1.1     ahoka 			len = le32toh(nhdr->length) - CHFS_NODE_HDR_SIZE;
    497  1.1     ahoka 			err = chfs_read_leb(chmp,
    498  1.1     ahoka 			    lnr, buf + CHFS_NODE_HDR_SIZE,
    499  1.1     ahoka 			    ofs, len,  &retlen);
    500  1.5        he 			if (err)
    501  1.5        he 				goto err_return;
    502  1.1     ahoka 
    503  1.1     ahoka 			if (retlen != len) {
    504  1.1     ahoka 				chfs_err("Error reading vnode: read: %zu instead of: %zu\n",
    505  1.1     ahoka 				    len, retlen);
    506  1.5        he 				err = EIO;
    507  1.5        he 				goto err_return;
    508  1.1     ahoka 			}
    509  1.1     ahoka 			KASSERT(lnr == cheb->lnr);
    510  1.1     ahoka 			err = chfs_scan_check_vnode(chmp,
    511  1.1     ahoka 			    cheb, buf, ofs - CHFS_NODE_HDR_SIZE);
    512  1.5        he 			if (err)
    513  1.5        he 				goto err_return;
    514  1.1     ahoka 
    515  1.1     ahoka 			break;
    516  1.1     ahoka 		case CHFS_NODETYPE_DIRENT:
    517  1.4     ttoth 		/* directory entry */
    518  1.4     ttoth 			/* read up the node */
    519  1.1     ahoka 			len = le32toh(nhdr->length) - CHFS_NODE_HDR_SIZE;
    520  1.1     ahoka 
    521  1.1     ahoka 			err = chfs_read_leb(chmp,
    522  1.1     ahoka 			    lnr, buf + CHFS_NODE_HDR_SIZE,
    523  1.1     ahoka 			    ofs, len, &retlen);
    524  1.5        he 			if (err)
    525  1.5        he 				goto err_return;
    526  1.1     ahoka 
    527  1.1     ahoka 			if (retlen != len) {
    528  1.1     ahoka 				chfs_err("Error reading dirent node: read: %zu "
    529  1.1     ahoka 				    "instead of: %zu\n", len, retlen);
    530  1.5        he 				err = EIO;
    531  1.5        he 				goto err_return;
    532  1.1     ahoka 			}
    533  1.1     ahoka 
    534  1.1     ahoka 			KASSERT(lnr == cheb->lnr);
    535  1.1     ahoka 
    536  1.1     ahoka 			err = chfs_scan_check_dirent_node(chmp,
    537  1.1     ahoka 			    cheb, buf, ofs - CHFS_NODE_HDR_SIZE);
    538  1.5        he 			if (err)
    539  1.5        he 				goto err_return;
    540  1.1     ahoka 
    541  1.1     ahoka 			break;
    542  1.1     ahoka 		case CHFS_NODETYPE_DATA:
    543  1.4     ttoth 		/* data node */
    544  1.1     ahoka 			len = sizeof(struct chfs_flash_data_node) -
    545  1.1     ahoka 			    CHFS_NODE_HDR_SIZE;
    546  1.1     ahoka 			err = chfs_read_leb(chmp,
    547  1.1     ahoka 			    lnr, buf + CHFS_NODE_HDR_SIZE,
    548  1.1     ahoka 			    ofs, len, &retlen);
    549  1.5        he 			if (err)
    550  1.5        he 				goto err_return;
    551  1.1     ahoka 
    552  1.1     ahoka 			if (retlen != len) {
    553  1.1     ahoka 				chfs_err("Error reading data node: read: %zu "
    554  1.1     ahoka 				    "instead of: %zu\n", len, retlen);
    555  1.5        he 				err = EIO;
    556  1.5        he 				goto err_return;
    557  1.1     ahoka 			}
    558  1.1     ahoka 			KASSERT(lnr == cheb->lnr);
    559  1.1     ahoka 			err = chfs_scan_check_data_node(chmp,
    560  1.1     ahoka 			    cheb, buf, ofs - CHFS_NODE_HDR_SIZE);
    561  1.1     ahoka 			if (err)
    562  1.5        he 				goto err_return;
    563  1.1     ahoka 
    564  1.1     ahoka 			break;
    565  1.1     ahoka 		case CHFS_NODETYPE_PADDING:
    566  1.4     ttoth 		/* padding node, set size and update dirty */
    567  1.1     ahoka 			nref = chfs_alloc_node_ref(cheb);
    568  1.1     ahoka 			nref->nref_offset = ofs - CHFS_NODE_HDR_SIZE;
    569  1.1     ahoka 			nref->nref_offset = CHFS_GET_OFS(nref->nref_offset) |
    570  1.1     ahoka 			    CHFS_OBSOLETE_NODE_MASK;
    571  1.1     ahoka 
    572  1.1     ahoka 			err = chfs_update_eb_dirty(chmp, cheb,
    573  1.1     ahoka 			    le32toh(nhdr->length));
    574  1.1     ahoka 			if (err)
    575  1.5        he 				goto err_return;
    576  1.1     ahoka 
    577  1.1     ahoka 			break;
    578  1.1     ahoka 		default:
    579  1.4     ttoth 		/* unknown node type, update dirty and skip */
    580  1.1     ahoka 			err = chfs_update_eb_dirty(chmp, cheb,
    581  1.1     ahoka 			    le32toh(nhdr->length));
    582  1.1     ahoka 			if (err)
    583  1.5        he 				goto err_return;
    584  1.1     ahoka 
    585  1.1     ahoka 			break;
    586  1.1     ahoka 		}
    587  1.1     ahoka 		ofs += le32toh(nhdr->length) - CHFS_NODE_HDR_SIZE;
    588  1.1     ahoka 	}
    589  1.1     ahoka 
    590  1.1     ahoka 	KASSERT(cheb->used_size + cheb->free_size + cheb->dirty_size +
    591  1.1     ahoka 	    cheb->unchecked_size + cheb->wasted_size == chmp->chm_ebh->eb_size);
    592  1.1     ahoka 
    593  1.5        he 	err = chfs_scan_classify_cheb(chmp, cheb);
    594  1.5        he 	/* FALLTHROUGH */
    595  1.5        he     err_return:
    596  1.5        he 	kmem_free(buf, CHFS_MAX_NODE_SIZE);
    597  1.5        he 	return err;
    598  1.1     ahoka }
    599