Home | History | Annotate | Line # | Download | only in chfs
      1  1.10    andvar /*	$NetBSD: chfs_scan.c,v 1.10 2021/07/16 21:18:41 andvar 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.9    andvar 			mutex_exit(&chmp->chm_lock_vnocache);
    155   1.1     ahoka 			return CHFS_NODE_OK;
    156   1.1     ahoka 		}
    157   1.1     ahoka 	} else {
    158   1.1     ahoka 		vc->vno_version = kmem_alloc(sizeof(uint64_t), KM_SLEEP);
    159   1.1     ahoka 		*vc->vno_version = le64toh(vnode->version);
    160   1.1     ahoka 		chfs_add_vnode_ref_to_vc(chmp, vc, nref);
    161   1.1     ahoka 	}
    162   1.3     ttoth 	mutex_exit(&chmp->chm_lock_vnocache);
    163   1.1     ahoka 
    164   1.4     ttoth 	/* update sizes */
    165   1.1     ahoka 	mutex_enter(&chmp->chm_lock_sizes);
    166   1.1     ahoka 	chfs_change_size_free(chmp, cheb, -le32toh(vnode->length));
    167   1.1     ahoka 	chfs_change_size_used(chmp, cheb, le32toh(vnode->length));
    168   1.1     ahoka 	mutex_exit(&chmp->chm_lock_sizes);
    169   1.1     ahoka 
    170   1.1     ahoka 	KASSERT(cheb->used_size <= chmp->chm_ebh->eb_size);
    171   1.1     ahoka 
    172   1.1     ahoka 	KASSERT(cheb->used_size + cheb->free_size + cheb->dirty_size + cheb->unchecked_size + cheb->wasted_size == chmp->chm_ebh->eb_size);
    173   1.1     ahoka 
    174   1.1     ahoka 	return CHFS_NODE_OK;
    175   1.1     ahoka }
    176   1.1     ahoka 
    177   1.4     ttoth /* chfs_scan_mark_dirent_obsolete - marks a directory entry "obsolete" */
    178   1.1     ahoka int
    179   1.1     ahoka chfs_scan_mark_dirent_obsolete(struct chfs_mount *chmp,
    180   1.1     ahoka     struct chfs_vnode_cache *vc, struct chfs_dirent *fd)
    181   1.1     ahoka {
    182   1.8     ryoon 	struct chfs_eraseblock *cheb __diagused;
    183   1.1     ahoka 	struct chfs_node_ref *prev, *nref;
    184   1.1     ahoka 
    185   1.1     ahoka 	nref = fd->nref;
    186   1.1     ahoka 	cheb = &chmp->chm_blocks[fd->nref->nref_lnr];
    187   1.1     ahoka 
    188   1.4     ttoth 	/* remove dirent's node ref from vnode cache */
    189   1.1     ahoka 	prev = vc->dirents;
    190   1.1     ahoka 	if (prev && prev == nref) {
    191   1.1     ahoka 		vc->dirents = prev->nref_next;
    192   1.1     ahoka 	} else if (prev && prev != (void *)vc) {
    193   1.3     ttoth 		while (prev->nref_next && prev->nref_next != (void *)vc) {
    194   1.3     ttoth 			if (prev->nref_next == nref) {
    195   1.3     ttoth 				prev->nref_next = nref->nref_next;
    196   1.3     ttoth 				break;
    197   1.3     ttoth 			}
    198   1.1     ahoka 			prev = prev->nref_next;
    199   1.1     ahoka 		}
    200   1.3     ttoth 	}
    201   1.1     ahoka 
    202   1.1     ahoka 	KASSERT(cheb->used_size + cheb->free_size + cheb->dirty_size +
    203   1.1     ahoka 	    cheb->unchecked_size + cheb->wasted_size == chmp->chm_ebh->eb_size);
    204   1.1     ahoka 
    205   1.1     ahoka 	return 0;
    206   1.1     ahoka }
    207   1.1     ahoka 
    208   1.4     ttoth /* chfs_add_fd_to_list - adds a directory entry to its parent's vnode cache */
    209   1.1     ahoka void
    210   1.1     ahoka chfs_add_fd_to_list(struct chfs_mount *chmp,
    211   1.1     ahoka     struct chfs_dirent *new, struct chfs_vnode_cache *pvc)
    212   1.1     ahoka {
    213   1.1     ahoka 	KASSERT(mutex_owned(&chmp->chm_lock_mountfields));
    214   1.1     ahoka 	int size;
    215   1.1     ahoka 	struct chfs_eraseblock *cheb, *oldcheb;
    216   1.1     ahoka 	struct chfs_dirent *fd, *tmpfd;
    217   1.1     ahoka 
    218   1.1     ahoka 	dbg("adding fd to list: %s\n", new->name);
    219   1.1     ahoka 
    220   1.4     ttoth 	/* update highest version if needed */
    221   1.1     ahoka 	if ((new->version > pvc->highest_version))
    222   1.1     ahoka 		pvc->highest_version = new->version;
    223   1.1     ahoka 
    224   1.1     ahoka 	size = CHFS_PAD(sizeof(struct chfs_flash_dirent_node) +
    225   1.1     ahoka 	    new->nsize);
    226   1.1     ahoka 	cheb = &chmp->chm_blocks[new->nref->nref_lnr];
    227   1.1     ahoka 
    228  1.10    andvar 	mutex_enter(&chmp->chm_lock_sizes);
    229   1.1     ahoka 	TAILQ_FOREACH_SAFE(fd, &pvc->scan_dirents, fds, tmpfd) {
    230   1.1     ahoka 		if (fd->nhash > new->nhash) {
    231   1.1     ahoka 			/* insert new before fd */
    232   1.1     ahoka 			TAILQ_INSERT_BEFORE(fd, new, fds);
    233   1.1     ahoka 			goto out;
    234   1.1     ahoka 		} else if (fd->nhash == new->nhash &&
    235   1.1     ahoka 		    !strcmp(fd->name, new->name)) {
    236   1.1     ahoka 			if (new->version > fd->version) {
    237   1.1     ahoka 				/* replace fd with new */
    238   1.1     ahoka 				TAILQ_INSERT_BEFORE(fd, new, fds);
    239   1.1     ahoka 				chfs_change_size_free(chmp, cheb, -size);
    240   1.1     ahoka 				chfs_change_size_used(chmp, cheb, size);
    241   1.1     ahoka 
    242   1.1     ahoka 				TAILQ_REMOVE(&pvc->scan_dirents, fd, fds);
    243   1.1     ahoka 				if (fd->nref) {
    244   1.1     ahoka 					size = CHFS_PAD(sizeof(struct chfs_flash_dirent_node) + fd->nsize);
    245   1.1     ahoka 					chfs_scan_mark_dirent_obsolete(chmp, pvc, fd);
    246   1.1     ahoka 					oldcheb = &chmp->chm_blocks[fd->nref->nref_lnr];
    247   1.1     ahoka 					chfs_change_size_used(chmp, oldcheb, -size);
    248   1.1     ahoka 					chfs_change_size_dirty(chmp, oldcheb, size);
    249   1.1     ahoka 				}
    250   1.1     ahoka 				chfs_free_dirent(fd);
    251   1.1     ahoka 			} else {
    252   1.4     ttoth 				/* new dirent is older */
    253   1.1     ahoka 				chfs_scan_mark_dirent_obsolete(chmp, pvc, new);
    254   1.1     ahoka 				chfs_change_size_free(chmp, cheb, -size);
    255   1.1     ahoka 				chfs_change_size_dirty(chmp, cheb, size);
    256   1.1     ahoka 				chfs_free_dirent(new);
    257   1.1     ahoka 			}
    258   1.1     ahoka 			mutex_exit(&chmp->chm_lock_sizes);
    259   1.1     ahoka 			return;
    260   1.1     ahoka 		}
    261   1.1     ahoka 	}
    262   1.1     ahoka 	/* if we couldnt fit it elsewhere, lets add to the end */
    263   1.1     ahoka 	TAILQ_INSERT_TAIL(&pvc->scan_dirents, new, fds);
    264   1.1     ahoka 
    265   1.1     ahoka out:
    266   1.4     ttoth 	/* update sizes */
    267   1.1     ahoka 	chfs_change_size_free(chmp, cheb, -size);
    268   1.1     ahoka 	chfs_change_size_used(chmp, cheb, size);
    269   1.1     ahoka 	mutex_exit(&chmp->chm_lock_sizes);
    270   1.1     ahoka 
    271   1.1     ahoka 	KASSERT(cheb->used_size <= chmp->chm_ebh->eb_size);
    272   1.1     ahoka 
    273   1.1     ahoka 	KASSERT(cheb->used_size + cheb->free_size + cheb->dirty_size + cheb->unchecked_size + cheb->wasted_size == chmp->chm_ebh->eb_size);
    274   1.4     ttoth }
    275   1.1     ahoka 
    276   1.4     ttoth /* chfs_scan_check_dirent_node - check vnode crc and add to vnode cache */
    277   1.1     ahoka int
    278   1.1     ahoka chfs_scan_check_dirent_node(struct chfs_mount *chmp,
    279   1.1     ahoka     struct chfs_eraseblock *cheb, void *buf, off_t ofs)
    280   1.1     ahoka {
    281   1.1     ahoka 	int err, namelen;
    282   1.1     ahoka 	uint32_t crc;
    283   1.1     ahoka 	struct chfs_dirent *fd;
    284   1.3     ttoth 	struct chfs_vnode_cache *parentvc;
    285   1.1     ahoka 	struct chfs_flash_dirent_node *dirent = buf;
    286   1.1     ahoka 
    287   1.4     ttoth 	/* check crc */
    288   1.1     ahoka 	crc = crc32(0, (uint8_t *)dirent, sizeof(*dirent) - 4);
    289   1.1     ahoka 	if (crc != le32toh(dirent->node_crc)) {
    290   1.1     ahoka 		err = chfs_update_eb_dirty(chmp, cheb, le32toh(dirent->length));
    291   1.1     ahoka 		if (err)
    292   1.1     ahoka 			return err;
    293   1.1     ahoka 		return CHFS_NODE_BADCRC;
    294   1.1     ahoka 	}
    295   1.4     ttoth 
    296   1.4     ttoth 	/* allocate space for name */
    297   1.1     ahoka 	namelen = dirent->nsize;
    298   1.1     ahoka 
    299   1.1     ahoka 	fd = chfs_alloc_dirent(namelen + 1);
    300   1.1     ahoka 	if (!fd)
    301   1.1     ahoka 		return ENOMEM;
    302   1.1     ahoka 
    303   1.4     ttoth 	/* allocate an nref */
    304   1.1     ahoka 	fd->nref = chfs_alloc_node_ref(cheb);
    305   1.1     ahoka 	if (!fd->nref)
    306   1.1     ahoka 		return ENOMEM;
    307   1.1     ahoka 
    308   1.1     ahoka 	KASSERT(fd->nref->nref_lnr == cheb->lnr);
    309   1.1     ahoka 
    310   1.1     ahoka 	memcpy(&fd->name, dirent->name, namelen);
    311   1.1     ahoka 	fd->nsize = namelen;
    312   1.1     ahoka 	fd->name[namelen] = 0;
    313   1.1     ahoka 	crc = crc32(0, fd->name, dirent->nsize);
    314   1.1     ahoka 	if (crc != le32toh(dirent->name_crc)) {
    315   1.1     ahoka 		chfs_err("Directory entry's name has bad crc: read: 0x%x, "
    316   1.1     ahoka 		    "calculated: 0x%x\n", le32toh(dirent->name_crc), crc);
    317   1.1     ahoka 		chfs_free_dirent(fd);
    318   1.1     ahoka 		err = chfs_update_eb_dirty(chmp, cheb, le32toh(dirent->length));
    319   1.1     ahoka 		if (err)
    320   1.1     ahoka 			return err;
    321   1.1     ahoka 		return CHFS_NODE_BADNAMECRC;
    322   1.1     ahoka 	}
    323   1.1     ahoka 
    324   1.4     ttoth 	/* check vnode_cache of parent node */
    325   1.1     ahoka 	mutex_enter(&chmp->chm_lock_vnocache);
    326   1.3     ttoth 	parentvc = chfs_scan_make_vnode_cache(chmp, le64toh(dirent->pvno));
    327   1.3     ttoth 	if (!parentvc) {
    328   1.1     ahoka 		chfs_free_dirent(fd);
    329   1.9    andvar 		mutex_exit(&chmp->chm_lock_vnocache);
    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.9    andvar 		if (!vc) {
    387   1.9    andvar 			mutex_exit(&chmp->chm_lock_vnocache);
    388   1.1     ahoka 			return ENOMEM;
    389   1.9    andvar 		}
    390   1.1     ahoka 	}
    391   1.3     ttoth 	chfs_add_node_to_list(chmp, vc, nref, &vc->dnode);
    392   1.1     ahoka 	mutex_exit(&chmp->chm_lock_vnocache);
    393   1.1     ahoka 
    394   1.1     ahoka 	dbg("chmpfree: %u, chebfree: %u, dnode: %u\n", chmp->chm_free_size, cheb->free_size, dnode->length);
    395   1.1     ahoka 
    396   1.4     ttoth 	/* update sizes */
    397   1.1     ahoka 	mutex_enter(&chmp->chm_lock_sizes);
    398   1.1     ahoka 	chfs_change_size_free(chmp, cheb, -dnode->length);
    399   1.1     ahoka 	chfs_change_size_unchecked(chmp, cheb, dnode->length);
    400   1.1     ahoka 	mutex_exit(&chmp->chm_lock_sizes);
    401   1.1     ahoka 	return CHFS_NODE_OK;
    402   1.1     ahoka }
    403   1.1     ahoka 
    404   1.4     ttoth /* chfs_scan_classify_cheb - determine eraseblock's state */
    405   1.1     ahoka int
    406   1.1     ahoka chfs_scan_classify_cheb(struct chfs_mount *chmp,
    407   1.1     ahoka     struct chfs_eraseblock *cheb)
    408   1.1     ahoka {
    409   1.1     ahoka 	if (cheb->free_size == chmp->chm_ebh->eb_size)
    410   1.1     ahoka 		return CHFS_BLK_STATE_FREE;
    411   1.1     ahoka 	else if (cheb->dirty_size < MAX_DIRTY_TO_CLEAN)
    412   1.1     ahoka 		return CHFS_BLK_STATE_CLEAN;
    413   1.1     ahoka 	else if (cheb->used_size || cheb->unchecked_size)
    414   1.1     ahoka 		return CHFS_BLK_STATE_PARTDIRTY;
    415   1.1     ahoka 	else
    416   1.1     ahoka 		return CHFS_BLK_STATE_ALLDIRTY;
    417   1.1     ahoka }
    418   1.1     ahoka 
    419   1.1     ahoka 
    420   1.4     ttoth /*
    421   1.1     ahoka  * chfs_scan_eraseblock - scans an eraseblock and looking for nodes
    422   1.1     ahoka  *
    423   1.1     ahoka  * This function scans a whole eraseblock, checks the nodes on it and add them
    424   1.1     ahoka  * to the vnode cache.
    425   1.1     ahoka  * Returns eraseblock state on success, error code if fails.
    426   1.1     ahoka  */
    427   1.1     ahoka int
    428   1.1     ahoka chfs_scan_eraseblock(struct chfs_mount *chmp,
    429   1.4     ttoth     struct chfs_eraseblock *cheb)
    430   1.4     ttoth {
    431   1.1     ahoka 	int err;
    432   1.1     ahoka 	size_t len, retlen;
    433   1.1     ahoka 	off_t ofs = 0;
    434   1.1     ahoka 	int lnr = cheb->lnr;
    435   1.1     ahoka 	u_char *buf;
    436   1.1     ahoka 	struct chfs_flash_node_hdr *nhdr;
    437   1.1     ahoka 	int read_free = 0;
    438   1.1     ahoka 	struct chfs_node_ref *nref;
    439   1.1     ahoka 
    440   1.1     ahoka 	dbg("scanning eraseblock content: %d free_size: %d\n", cheb->lnr, cheb->free_size);
    441   1.1     ahoka 	dbg("scanned physical block: %d\n", chmp->chm_ebh->lmap[lnr]);
    442   1.1     ahoka 	buf = kmem_alloc(CHFS_MAX_NODE_SIZE, KM_SLEEP);
    443   1.1     ahoka 
    444   1.1     ahoka 	while((ofs + CHFS_NODE_HDR_SIZE) < chmp->chm_ebh->eb_size) {
    445   1.1     ahoka 		memset(buf, 0 , CHFS_MAX_NODE_SIZE);
    446   1.1     ahoka 		err = chfs_read_leb(chmp,
    447   1.1     ahoka 		    lnr, buf, ofs, CHFS_NODE_HDR_SIZE, &retlen);
    448   1.5        he 		if (err)
    449   1.5        he 			goto err_return;
    450   1.1     ahoka 
    451   1.1     ahoka 		if (retlen != CHFS_NODE_HDR_SIZE) {
    452   1.1     ahoka 			chfs_err("Error reading node header: "
    453   1.1     ahoka 			    "read: %zu instead of: %zu\n",
    454   1.1     ahoka 			    CHFS_NODE_HDR_SIZE, retlen);
    455   1.5        he 			err = EIO;
    456   1.5        he 			goto err_return;
    457   1.1     ahoka 		}
    458   1.1     ahoka 
    459   1.1     ahoka 		/* first we check if the buffer we read is full with 0xff, if yes maybe
    460   1.1     ahoka 		 * the blocks remaining area is free. We increase read_free and if it
    461   1.4     ttoth 		 * reaches MAX_READ_FREE we stop reading the block */
    462   1.1     ahoka 		if (check_pattern(buf, 0xff, 0, CHFS_NODE_HDR_SIZE)) {
    463   1.1     ahoka 			read_free += CHFS_NODE_HDR_SIZE;
    464   1.1     ahoka 			if (read_free >= MAX_READ_FREE(chmp)) {
    465   1.1     ahoka 				dbg("rest of the block is free. Size: %d\n", cheb->free_size);
    466   1.6  christos 				kmem_free(buf, CHFS_MAX_NODE_SIZE);
    467   1.1     ahoka 				return chfs_scan_classify_cheb(chmp, cheb);
    468   1.1     ahoka 			}
    469   1.1     ahoka 			ofs += CHFS_NODE_HDR_SIZE;
    470   1.1     ahoka 			continue;
    471   1.1     ahoka 		} else {
    472   1.1     ahoka 			chfs_update_eb_dirty(chmp, cheb, read_free);
    473   1.1     ahoka 			read_free = 0;
    474   1.1     ahoka 		}
    475   1.1     ahoka 
    476   1.1     ahoka 		nhdr = (struct chfs_flash_node_hdr *)buf;
    477   1.1     ahoka 
    478   1.1     ahoka 		err = chfs_scan_check_node_hdr(nhdr);
    479   1.1     ahoka 		if (err) {
    480   1.1     ahoka 			dbg("node hdr error\n");
    481   1.1     ahoka 			err = chfs_update_eb_dirty(chmp, cheb, 4);
    482   1.5        he 			if (err)
    483   1.5        he 				goto err_return;
    484   1.1     ahoka 
    485   1.1     ahoka 			ofs += 4;
    486   1.1     ahoka 			continue;
    487   1.1     ahoka 		}
    488   1.1     ahoka 		ofs += CHFS_NODE_HDR_SIZE;
    489   1.1     ahoka 		if (ofs > chmp->chm_ebh->eb_size) {
    490   1.1     ahoka 			chfs_err("Second part of node is on the next eraseblock.\n");
    491   1.5        he 			err = EIO;
    492   1.5        he 			goto err_return;
    493   1.1     ahoka 		}
    494   1.1     ahoka 		switch (le16toh(nhdr->type)) {
    495   1.1     ahoka 		case CHFS_NODETYPE_VNODE:
    496   1.4     ttoth 		/* vnode information */
    497   1.4     ttoth 			/* read up the node */
    498   1.1     ahoka 			len = le32toh(nhdr->length) - CHFS_NODE_HDR_SIZE;
    499   1.1     ahoka 			err = chfs_read_leb(chmp,
    500   1.1     ahoka 			    lnr, buf + CHFS_NODE_HDR_SIZE,
    501   1.1     ahoka 			    ofs, len,  &retlen);
    502   1.5        he 			if (err)
    503   1.5        he 				goto err_return;
    504   1.1     ahoka 
    505   1.1     ahoka 			if (retlen != len) {
    506   1.1     ahoka 				chfs_err("Error reading vnode: read: %zu instead of: %zu\n",
    507   1.1     ahoka 				    len, retlen);
    508   1.5        he 				err = EIO;
    509   1.5        he 				goto err_return;
    510   1.1     ahoka 			}
    511   1.1     ahoka 			KASSERT(lnr == cheb->lnr);
    512   1.1     ahoka 			err = chfs_scan_check_vnode(chmp,
    513   1.1     ahoka 			    cheb, buf, ofs - CHFS_NODE_HDR_SIZE);
    514   1.5        he 			if (err)
    515   1.5        he 				goto err_return;
    516   1.1     ahoka 
    517   1.1     ahoka 			break;
    518   1.1     ahoka 		case CHFS_NODETYPE_DIRENT:
    519   1.4     ttoth 		/* directory entry */
    520   1.4     ttoth 			/* read up the node */
    521   1.1     ahoka 			len = le32toh(nhdr->length) - CHFS_NODE_HDR_SIZE;
    522   1.1     ahoka 
    523   1.1     ahoka 			err = chfs_read_leb(chmp,
    524   1.1     ahoka 			    lnr, buf + CHFS_NODE_HDR_SIZE,
    525   1.1     ahoka 			    ofs, len, &retlen);
    526   1.5        he 			if (err)
    527   1.5        he 				goto err_return;
    528   1.1     ahoka 
    529   1.1     ahoka 			if (retlen != len) {
    530   1.1     ahoka 				chfs_err("Error reading dirent node: read: %zu "
    531   1.1     ahoka 				    "instead of: %zu\n", len, retlen);
    532   1.5        he 				err = EIO;
    533   1.5        he 				goto err_return;
    534   1.1     ahoka 			}
    535   1.1     ahoka 
    536   1.1     ahoka 			KASSERT(lnr == cheb->lnr);
    537   1.1     ahoka 
    538   1.1     ahoka 			err = chfs_scan_check_dirent_node(chmp,
    539   1.1     ahoka 			    cheb, buf, ofs - CHFS_NODE_HDR_SIZE);
    540   1.5        he 			if (err)
    541   1.5        he 				goto err_return;
    542   1.1     ahoka 
    543   1.1     ahoka 			break;
    544   1.1     ahoka 		case CHFS_NODETYPE_DATA:
    545   1.4     ttoth 		/* data node */
    546   1.1     ahoka 			len = sizeof(struct chfs_flash_data_node) -
    547   1.1     ahoka 			    CHFS_NODE_HDR_SIZE;
    548   1.1     ahoka 			err = chfs_read_leb(chmp,
    549   1.1     ahoka 			    lnr, buf + CHFS_NODE_HDR_SIZE,
    550   1.1     ahoka 			    ofs, len, &retlen);
    551   1.5        he 			if (err)
    552   1.5        he 				goto err_return;
    553   1.1     ahoka 
    554   1.1     ahoka 			if (retlen != len) {
    555   1.1     ahoka 				chfs_err("Error reading data node: read: %zu "
    556   1.1     ahoka 				    "instead of: %zu\n", len, retlen);
    557   1.5        he 				err = EIO;
    558   1.5        he 				goto err_return;
    559   1.1     ahoka 			}
    560   1.1     ahoka 			KASSERT(lnr == cheb->lnr);
    561   1.1     ahoka 			err = chfs_scan_check_data_node(chmp,
    562   1.1     ahoka 			    cheb, buf, ofs - CHFS_NODE_HDR_SIZE);
    563   1.1     ahoka 			if (err)
    564   1.5        he 				goto err_return;
    565   1.1     ahoka 
    566   1.1     ahoka 			break;
    567   1.1     ahoka 		case CHFS_NODETYPE_PADDING:
    568   1.4     ttoth 		/* padding node, set size and update dirty */
    569   1.1     ahoka 			nref = chfs_alloc_node_ref(cheb);
    570   1.1     ahoka 			nref->nref_offset = ofs - CHFS_NODE_HDR_SIZE;
    571   1.1     ahoka 			nref->nref_offset = CHFS_GET_OFS(nref->nref_offset) |
    572   1.1     ahoka 			    CHFS_OBSOLETE_NODE_MASK;
    573   1.1     ahoka 
    574   1.1     ahoka 			err = chfs_update_eb_dirty(chmp, cheb,
    575   1.1     ahoka 			    le32toh(nhdr->length));
    576   1.1     ahoka 			if (err)
    577   1.5        he 				goto err_return;
    578   1.1     ahoka 
    579   1.1     ahoka 			break;
    580   1.1     ahoka 		default:
    581   1.4     ttoth 		/* unknown node type, update dirty and skip */
    582   1.1     ahoka 			err = chfs_update_eb_dirty(chmp, cheb,
    583   1.1     ahoka 			    le32toh(nhdr->length));
    584   1.1     ahoka 			if (err)
    585   1.5        he 				goto err_return;
    586   1.1     ahoka 
    587   1.1     ahoka 			break;
    588   1.1     ahoka 		}
    589   1.1     ahoka 		ofs += le32toh(nhdr->length) - CHFS_NODE_HDR_SIZE;
    590   1.1     ahoka 	}
    591   1.1     ahoka 
    592   1.1     ahoka 	KASSERT(cheb->used_size + cheb->free_size + cheb->dirty_size +
    593   1.1     ahoka 	    cheb->unchecked_size + cheb->wasted_size == chmp->chm_ebh->eb_size);
    594   1.1     ahoka 
    595   1.5        he 	err = chfs_scan_classify_cheb(chmp, cheb);
    596   1.5        he 	/* FALLTHROUGH */
    597   1.5        he     err_return:
    598   1.5        he 	kmem_free(buf, CHFS_MAX_NODE_SIZE);
    599   1.5        he 	return err;
    600   1.1     ahoka }
    601