xref: /minix3/sys/ufs/chfs/chfs_build.c (revision 84d9c625bfea59e274550651111ae9edfdc40fbd)
1*84d9c625SLionel Sambuc /*	$NetBSD: chfs_build.c,v 1.5 2012/10/19 12:44:39 ttoth Exp $	*/
2d65f6f70SBen Gras 
3d65f6f70SBen Gras /*-
4d65f6f70SBen Gras  * Copyright (c) 2010 Department of Software Engineering,
5d65f6f70SBen Gras  *		      University of Szeged, Hungary
6d65f6f70SBen Gras  * All rights reserved.
7d65f6f70SBen Gras  *
8d65f6f70SBen Gras  * This code is derived from software contributed to The NetBSD Foundation
9d65f6f70SBen Gras  * by the Department of Software Engineering, University of Szeged, Hungary
10d65f6f70SBen Gras  *
11d65f6f70SBen Gras  * Redistribution and use in source and binary forms, with or without
12d65f6f70SBen Gras  * modification, are permitted provided that the following conditions
13d65f6f70SBen Gras  * are met:
14d65f6f70SBen Gras  * 1. Redistributions of source code must retain the above copyright
15d65f6f70SBen Gras  *    notice, this list of conditions and the following disclaimer.
16d65f6f70SBen Gras  * 2. Redistributions in binary form must reproduce the above copyright
17d65f6f70SBen Gras  *    notice, this list of conditions and the following disclaimer in the
18d65f6f70SBen Gras  *    documentation and/or other materials provided with the distribution.
19d65f6f70SBen Gras  *
20d65f6f70SBen Gras  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21d65f6f70SBen Gras  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22d65f6f70SBen Gras  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23d65f6f70SBen Gras  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24d65f6f70SBen Gras  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25d65f6f70SBen Gras  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26d65f6f70SBen Gras  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27d65f6f70SBen Gras  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28d65f6f70SBen Gras  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29d65f6f70SBen Gras  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30d65f6f70SBen Gras  * SUCH DAMAGE.
31d65f6f70SBen Gras  */
32d65f6f70SBen Gras 
33d65f6f70SBen Gras #include "chfs.h"
34d65f6f70SBen Gras 
35d65f6f70SBen Gras 
36*84d9c625SLionel Sambuc /*
37*84d9c625SLionel Sambuc  * chfs_calc_trigger_levels - setup filesystem parameters
38*84d9c625SLionel Sambuc  * Setups filesystem parameters (reserved blocks and GC trigger level)
39*84d9c625SLionel Sambuc  * for a specific flash.
40*84d9c625SLionel Sambuc  */
41d65f6f70SBen Gras void
chfs_calc_trigger_levels(struct chfs_mount * chmp)42d65f6f70SBen Gras chfs_calc_trigger_levels(struct chfs_mount *chmp)
43d65f6f70SBen Gras {
44d65f6f70SBen Gras 	uint32_t size;
45d65f6f70SBen Gras 
46d65f6f70SBen Gras 	chmp->chm_resv_blocks_deletion = 2;
47d65f6f70SBen Gras 
48*84d9c625SLionel Sambuc 	size = chmp->chm_ebh->flash_size / 50;  /* 2% of flash size */
49d65f6f70SBen Gras 	size += chmp->chm_ebh->peb_nr * 100;
50d65f6f70SBen Gras 	size += chmp->chm_ebh->eb_size - 1;
51d65f6f70SBen Gras 
52d65f6f70SBen Gras 	chmp->chm_resv_blocks_write =
53d65f6f70SBen Gras 	    chmp->chm_resv_blocks_deletion + (size / chmp->chm_ebh->eb_size);
54d65f6f70SBen Gras 	chmp->chm_resv_blocks_gctrigger = chmp->chm_resv_blocks_write + 1;
55d65f6f70SBen Gras 	chmp->chm_resv_blocks_gcmerge = chmp->chm_resv_blocks_deletion + 1;
56d65f6f70SBen Gras 	chmp->chm_vdirty_blocks_gctrigger = chmp->chm_resv_blocks_gctrigger * 10;
57d65f6f70SBen Gras 
58d65f6f70SBen Gras 	chmp->chm_nospc_dirty =
59d65f6f70SBen Gras 	    chmp->chm_ebh->eb_size + (chmp->chm_ebh->flash_size / 100);
60d65f6f70SBen Gras }
61d65f6f70SBen Gras 
62d65f6f70SBen Gras 
63*84d9c625SLionel Sambuc /*
64d65f6f70SBen Gras  * chfs_build_set_vnodecache_nlink - set pvno and nlink in vnodecaches
65*84d9c625SLionel Sambuc  * Travels vc's directory entries and sets the pvno and nlink
66d65f6f70SBen Gras  * attribute of the vnode where the dirent's vno points.
67d65f6f70SBen Gras  */
68d65f6f70SBen Gras void
chfs_build_set_vnodecache_nlink(struct chfs_mount * chmp,struct chfs_vnode_cache * vc)69d65f6f70SBen Gras chfs_build_set_vnodecache_nlink(struct chfs_mount *chmp,
70d65f6f70SBen Gras     struct chfs_vnode_cache *vc)
71d65f6f70SBen Gras {
72*84d9c625SLionel Sambuc 	struct chfs_dirent *fd, *tmpfd;
73d65f6f70SBen Gras 
74*84d9c625SLionel Sambuc 	TAILQ_FOREACH_SAFE(fd, &vc->scan_dirents, fds, tmpfd) {
75d65f6f70SBen Gras 		struct chfs_vnode_cache *child_vc;
76d65f6f70SBen Gras 
77d65f6f70SBen Gras 		if (!fd->vno)
78d65f6f70SBen Gras 			continue;
79d65f6f70SBen Gras 
80d65f6f70SBen Gras 		mutex_enter(&chmp->chm_lock_vnocache);
81d65f6f70SBen Gras 		child_vc = chfs_vnode_cache_get(chmp, fd->vno);
82d65f6f70SBen Gras 		mutex_exit(&chmp->chm_lock_vnocache);
83d65f6f70SBen Gras 		if (!child_vc) {
84d65f6f70SBen Gras 			chfs_mark_node_obsolete(chmp, fd->nref);
85*84d9c625SLionel Sambuc 			TAILQ_REMOVE(&vc->scan_dirents, fd, fds);
86d65f6f70SBen Gras 			continue;
87d65f6f70SBen Gras 		}
88*84d9c625SLionel Sambuc 		if (fd->type == CHT_DIR) {
89d65f6f70SBen Gras 			if (child_vc->nlink < 1)
90d65f6f70SBen Gras 				child_vc->nlink = 1;
91d65f6f70SBen Gras 
92d65f6f70SBen Gras 			if (child_vc->pvno) {
93d65f6f70SBen Gras 				chfs_err("found a hard link: child dir: %s"
94d65f6f70SBen Gras 				    ", (vno: %llu) of dir vno: %llu\n",
95d65f6f70SBen Gras 				    fd->name, (unsigned long long)fd->vno,
96d65f6f70SBen Gras 				    (unsigned long long)vc->vno);
97d65f6f70SBen Gras 			} else {
98d65f6f70SBen Gras 				child_vc->pvno = vc->vno;
99d65f6f70SBen Gras 			}
100d65f6f70SBen Gras 		}
101d65f6f70SBen Gras 		child_vc->nlink++;
102d65f6f70SBen Gras 		vc->nlink++;
103d65f6f70SBen Gras 	}
104d65f6f70SBen Gras }
105d65f6f70SBen Gras 
106*84d9c625SLionel Sambuc /*
107d65f6f70SBen Gras  * chfs_build_remove_unlinked vnode
108d65f6f70SBen Gras  */
109d65f6f70SBen Gras void
chfs_build_remove_unlinked_vnode(struct chfs_mount * chmp,struct chfs_vnode_cache * vc,struct chfs_dirent_list * unlinked)110d65f6f70SBen Gras chfs_build_remove_unlinked_vnode(struct chfs_mount *chmp,
111d65f6f70SBen Gras     struct chfs_vnode_cache *vc,
112d65f6f70SBen Gras     struct chfs_dirent_list *unlinked)
113d65f6f70SBen Gras {
114d65f6f70SBen Gras 	struct chfs_node_ref *nref;
115d65f6f70SBen Gras 	struct chfs_dirent *fd, *tmpfd;
116d65f6f70SBen Gras 
117d65f6f70SBen Gras 	dbg("START\n");
118d65f6f70SBen Gras 	dbg("vno: %llu\n", (unsigned long long)vc->vno);
119d65f6f70SBen Gras 
120d65f6f70SBen Gras 	KASSERT(mutex_owned(&chmp->chm_lock_mountfields));
121*84d9c625SLionel Sambuc 	nref = vc->dnode;
122*84d9c625SLionel Sambuc 	/* The vnode cache is at the end of the data node's chain */
123d65f6f70SBen Gras 	while (nref != (struct chfs_node_ref *)vc) {
124d65f6f70SBen Gras 		struct chfs_node_ref *next = nref->nref_next;
125d65f6f70SBen Gras 		dbg("mark dnode\n");
126d65f6f70SBen Gras 		chfs_mark_node_obsolete(chmp, nref);
127d65f6f70SBen Gras 		nref = next;
128d65f6f70SBen Gras 	}
129*84d9c625SLionel Sambuc 	vc->dnode = (struct chfs_node_ref *)vc;
130d65f6f70SBen Gras 	nref = vc->dirents;
131*84d9c625SLionel Sambuc 	/* The vnode cache is at the end of the dirent node's chain */
132d65f6f70SBen Gras 	while (nref != (struct chfs_node_ref *)vc) {
133d65f6f70SBen Gras 		struct chfs_node_ref *next = nref->nref_next;
134d65f6f70SBen Gras 		dbg("mark dirent\n");
135d65f6f70SBen Gras 		chfs_mark_node_obsolete(chmp, nref);
136d65f6f70SBen Gras 		nref = next;
137d65f6f70SBen Gras 	}
138*84d9c625SLionel Sambuc 	vc->dirents = (struct chfs_node_ref *)vc;
139d65f6f70SBen Gras 	if (!TAILQ_EMPTY(&vc->scan_dirents)) {
140d65f6f70SBen Gras 		TAILQ_FOREACH_SAFE(fd, &vc->scan_dirents, fds, tmpfd) {
141d65f6f70SBen Gras 			struct chfs_vnode_cache *child_vc;
142d65f6f70SBen Gras 			dbg("dirent dump:\n");
143d65f6f70SBen Gras 			dbg(" ->vno:     %llu\n", (unsigned long long)fd->vno);
144d65f6f70SBen Gras 			dbg(" ->version: %llu\n", (unsigned long long)fd->version);
145d65f6f70SBen Gras 			dbg(" ->nhash:   0x%x\n", fd->nhash);
146d65f6f70SBen Gras 			dbg(" ->nsize:   %d\n", fd->nsize);
147d65f6f70SBen Gras 			dbg(" ->name:    %s\n", fd->name);
148d65f6f70SBen Gras 			dbg(" ->type:    %d\n", fd->type);
149d65f6f70SBen Gras 			TAILQ_REMOVE(&vc->scan_dirents, fd, fds);
150d65f6f70SBen Gras 
151d65f6f70SBen Gras 			if (!fd->vno) {
152d65f6f70SBen Gras 				chfs_free_dirent(fd);
153d65f6f70SBen Gras 				continue;
154d65f6f70SBen Gras 			}
155d65f6f70SBen Gras 			mutex_enter(&chmp->chm_lock_vnocache);
156d65f6f70SBen Gras 			child_vc = chfs_vnode_cache_get(chmp, fd->vno);
157d65f6f70SBen Gras 			mutex_exit(&chmp->chm_lock_vnocache);
158d65f6f70SBen Gras 			if (!child_vc) {
159d65f6f70SBen Gras 				chfs_free_dirent(fd);
160d65f6f70SBen Gras 				continue;
161d65f6f70SBen Gras 			}
162*84d9c625SLionel Sambuc 			/*
163d65f6f70SBen Gras 			 * Decrease nlink in child. If it is 0, add to unlinked
164d65f6f70SBen Gras 			 * dirents or just free it otherwise.
165d65f6f70SBen Gras 			 */
166d65f6f70SBen Gras 			child_vc->nlink--;
167d65f6f70SBen Gras 
168d65f6f70SBen Gras 			if (!child_vc->nlink) {
169d65f6f70SBen Gras 				// XXX HEAD or TAIL?
170d65f6f70SBen Gras 				// original code did HEAD, but we could add
171d65f6f70SBen Gras 				// it to the TAIL easily with TAILQ.
172d65f6f70SBen Gras 				TAILQ_INSERT_TAIL(unlinked, fd, fds);
173d65f6f70SBen Gras 			} else {
174d65f6f70SBen Gras 				chfs_free_dirent(fd);
175d65f6f70SBen Gras 			}
176d65f6f70SBen Gras 		}
177d65f6f70SBen Gras 	} else {
178d65f6f70SBen Gras 		dbg("there are no scan dirents\n");
179d65f6f70SBen Gras 	}
180d65f6f70SBen Gras 
181d65f6f70SBen Gras 	nref = vc->v;
182d65f6f70SBen Gras 	while ((struct chfs_vnode_cache *)nref != vc) {
183d65f6f70SBen Gras 		chfs_mark_node_obsolete(chmp, nref);
184d65f6f70SBen Gras 		nref = nref->nref_next;
185d65f6f70SBen Gras 	}
186*84d9c625SLionel Sambuc 	vc->v = (struct chfs_node_ref *)vc;
187d65f6f70SBen Gras 
188d65f6f70SBen Gras 	mutex_enter(&chmp->chm_lock_vnocache);
189d65f6f70SBen Gras 	if (vc->vno != CHFS_ROOTINO)
190*84d9c625SLionel Sambuc 		vc->state = VNO_STATE_UNCHECKED;
191d65f6f70SBen Gras 	mutex_exit(&chmp->chm_lock_vnocache);
192d65f6f70SBen Gras 	dbg("END\n");
193d65f6f70SBen Gras }
194d65f6f70SBen Gras 
195*84d9c625SLionel Sambuc /*
196d65f6f70SBen Gras  * chfs_build_filesystem - build in-memory representation of filesystem
197d65f6f70SBen Gras  *
198d65f6f70SBen Gras  * Step 1:
199*84d9c625SLionel Sambuc  * Scans through the eraseblocks mapped in EBH.
200d65f6f70SBen Gras  * During scan builds up the map of vnodes and directory entries and puts them
201d65f6f70SBen Gras  * into the vnode_cache.
202d65f6f70SBen Gras  * Step 2:
203d65f6f70SBen Gras  * Scans the directory tree and set the nlink in the vnode caches.
204d65f6f70SBen Gras  * Step 3:
205d65f6f70SBen Gras  * Scans vnode caches with nlink = 0
206d65f6f70SBen Gras  */
207d65f6f70SBen Gras int
chfs_build_filesystem(struct chfs_mount * chmp)208d65f6f70SBen Gras chfs_build_filesystem(struct chfs_mount *chmp)
209d65f6f70SBen Gras {
210d65f6f70SBen Gras 	int i,err = 0;
211d65f6f70SBen Gras 	struct chfs_vnode_cache *vc;
212d65f6f70SBen Gras 	struct chfs_dirent *fd, *tmpfd;
213d65f6f70SBen Gras 	struct chfs_node_ref **nref;
214d65f6f70SBen Gras 	struct chfs_dirent_list unlinked;
215d65f6f70SBen Gras 	struct chfs_vnode_cache *notregvc;
216d65f6f70SBen Gras 
217d65f6f70SBen Gras 	TAILQ_INIT(&unlinked);
218d65f6f70SBen Gras 
219d65f6f70SBen Gras 	mutex_enter(&chmp->chm_lock_mountfields);
220d65f6f70SBen Gras 
221*84d9c625SLionel Sambuc 	/* Step 1 */
222d65f6f70SBen Gras 	chmp->chm_flags |= CHFS_MP_FLAG_SCANNING;
223d65f6f70SBen Gras 	for (i = 0; i < chmp->chm_ebh->peb_nr; i++) {
224d65f6f70SBen Gras 		chmp->chm_blocks[i].lnr = i;
225d65f6f70SBen Gras 		chmp->chm_blocks[i].free_size = chmp->chm_ebh->eb_size;
226*84d9c625SLionel Sambuc 		/* If the LEB is add to free list skip it. */
227d65f6f70SBen Gras 		if (chmp->chm_ebh->lmap[i] < 0) {
228d65f6f70SBen Gras 			TAILQ_INSERT_TAIL(&chmp->chm_free_queue,
229d65f6f70SBen Gras 			    &chmp->chm_blocks[i], queue);
230d65f6f70SBen Gras 			chmp->chm_nr_free_blocks++;
231d65f6f70SBen Gras 			continue;
232d65f6f70SBen Gras 		}
233d65f6f70SBen Gras 
234d65f6f70SBen Gras 		err = chfs_scan_eraseblock(chmp, &chmp->chm_blocks[i]);
235d65f6f70SBen Gras 		switch (err) {
236d65f6f70SBen Gras 		case CHFS_BLK_STATE_FREE:
237d65f6f70SBen Gras 			chmp->chm_nr_free_blocks++;
238d65f6f70SBen Gras 			TAILQ_INSERT_TAIL(&chmp->chm_free_queue,
239d65f6f70SBen Gras 			    &chmp->chm_blocks[i], queue);
240d65f6f70SBen Gras 			break;
241d65f6f70SBen Gras 		case CHFS_BLK_STATE_CLEAN:
242d65f6f70SBen Gras 			TAILQ_INSERT_TAIL(&chmp->chm_clean_queue,
243d65f6f70SBen Gras 			    &chmp->chm_blocks[i], queue);
244d65f6f70SBen Gras 			break;
245d65f6f70SBen Gras 		case CHFS_BLK_STATE_PARTDIRTY:
246d65f6f70SBen Gras 			if (chmp->chm_blocks[i].free_size > chmp->chm_wbuf_pagesize &&
247d65f6f70SBen Gras 			    (!chmp->chm_nextblock ||
248d65f6f70SBen Gras 				chmp->chm_blocks[i].free_size >
249d65f6f70SBen Gras 				chmp->chm_nextblock->free_size)) {
250d65f6f70SBen Gras 				/* convert the old nextblock's free size to
251d65f6f70SBen Gras 				 * dirty and put it on a list */
252d65f6f70SBen Gras 				if (chmp->chm_nextblock) {
253d65f6f70SBen Gras 					err = chfs_close_eraseblock(chmp,
254d65f6f70SBen Gras 					    chmp->chm_nextblock);
255d65f6f70SBen Gras 					if (err)
256d65f6f70SBen Gras 						return err;
257d65f6f70SBen Gras 				}
258d65f6f70SBen Gras 				chmp->chm_nextblock = &chmp->chm_blocks[i];
259d65f6f70SBen Gras 			} else {
260d65f6f70SBen Gras 				/* convert the scanned block's free size to
261d65f6f70SBen Gras 				 * dirty and put it on a list */
262d65f6f70SBen Gras 				err = chfs_close_eraseblock(chmp,
263d65f6f70SBen Gras 				    &chmp->chm_blocks[i]);
264d65f6f70SBen Gras 				if (err)
265d65f6f70SBen Gras 					return err;
266d65f6f70SBen Gras 			}
267d65f6f70SBen Gras 			break;
268d65f6f70SBen Gras 		case CHFS_BLK_STATE_ALLDIRTY:
269d65f6f70SBen Gras 			/*
270d65f6f70SBen Gras 			 * The block has a valid EBH header, but it doesn't
271d65f6f70SBen Gras 			 * contain any valid data.
272d65f6f70SBen Gras 			 */
273d65f6f70SBen Gras 			TAILQ_INSERT_TAIL(&chmp->chm_erase_pending_queue,
274d65f6f70SBen Gras 			    &chmp->chm_blocks[i], queue);
275d65f6f70SBen Gras 			chmp->chm_nr_erasable_blocks++;
276d65f6f70SBen Gras 			break;
277d65f6f70SBen Gras 		default:
278d65f6f70SBen Gras 			/* It was an error, unknown  state */
279d65f6f70SBen Gras 			break;
280d65f6f70SBen Gras 		}
281d65f6f70SBen Gras 
282d65f6f70SBen Gras 	}
283d65f6f70SBen Gras 	chmp->chm_flags &= ~CHFS_MP_FLAG_SCANNING;
284d65f6f70SBen Gras 
285d65f6f70SBen Gras 
286d65f6f70SBen Gras 	//TODO need bad block check (and bad block handling in EBH too!!)
287d65f6f70SBen Gras 	/* Now EBH only checks block is bad  during its scan operation.
288d65f6f70SBen Gras 	 * Need check at erase + write + read...
289d65f6f70SBen Gras 	 */
290d65f6f70SBen Gras 
291*84d9c625SLionel Sambuc 	/* Step 2 */
292d65f6f70SBen Gras 	chmp->chm_flags |= CHFS_MP_FLAG_BUILDING;
293d65f6f70SBen Gras 	for (i = 0; i < VNODECACHE_SIZE; i++) {
294d65f6f70SBen Gras 		vc = chmp->chm_vnocache_hash[i];
295d65f6f70SBen Gras 		while (vc) {
296d65f6f70SBen Gras 			dbg("vc->vno: %llu\n", (unsigned long long)vc->vno);
297d65f6f70SBen Gras 			if (!TAILQ_EMPTY(&vc->scan_dirents))
298d65f6f70SBen Gras 				chfs_build_set_vnodecache_nlink(chmp, vc);
299d65f6f70SBen Gras 			vc = vc->next;
300d65f6f70SBen Gras 		}
301d65f6f70SBen Gras 	}
302d65f6f70SBen Gras 
303*84d9c625SLionel Sambuc 	/* Step 3 */
304d65f6f70SBen Gras 	for (i =  0; i < VNODECACHE_SIZE; i++) {
305d65f6f70SBen Gras 		vc = chmp->chm_vnocache_hash[i];
306d65f6f70SBen Gras 		while (vc) {
307d65f6f70SBen Gras 			if (vc->nlink) {
308d65f6f70SBen Gras 				vc = vc->next;
309d65f6f70SBen Gras 				continue;
310d65f6f70SBen Gras 			}
311d65f6f70SBen Gras 
312d65f6f70SBen Gras 			chfs_build_remove_unlinked_vnode(chmp,
313d65f6f70SBen Gras 			    vc, &unlinked);
314d65f6f70SBen Gras 			vc = vc->next;
315d65f6f70SBen Gras 		}
316d65f6f70SBen Gras 	}
317d65f6f70SBen Gras 	/* Remove the newly unlinked vnodes. They are on the unlinked list */
318d65f6f70SBen Gras 	TAILQ_FOREACH_SAFE(fd, &unlinked, fds, tmpfd) {
319d65f6f70SBen Gras 		TAILQ_REMOVE(&unlinked, fd, fds);
320d65f6f70SBen Gras 		mutex_enter(&chmp->chm_lock_vnocache);
321d65f6f70SBen Gras 		vc = chfs_vnode_cache_get(chmp, fd->vno);
322d65f6f70SBen Gras 		mutex_exit(&chmp->chm_lock_vnocache);
323d65f6f70SBen Gras 		if (vc) {
324d65f6f70SBen Gras 			chfs_build_remove_unlinked_vnode(chmp,
325d65f6f70SBen Gras 			    vc, &unlinked);
326d65f6f70SBen Gras 		}
327d65f6f70SBen Gras 		chfs_free_dirent(fd);
328d65f6f70SBen Gras 	}
329d65f6f70SBen Gras 
330d65f6f70SBen Gras 	chmp->chm_flags &= ~CHFS_MP_FLAG_BUILDING;
331d65f6f70SBen Gras 
332d65f6f70SBen Gras 	/* Free all dirents */
333d65f6f70SBen Gras 	for (i =  0; i < VNODECACHE_SIZE; i++) {
334d65f6f70SBen Gras 		vc = chmp->chm_vnocache_hash[i];
335d65f6f70SBen Gras 		while (vc) {
336d65f6f70SBen Gras 			TAILQ_FOREACH_SAFE(fd, &vc->scan_dirents, fds, tmpfd) {
337d65f6f70SBen Gras 				TAILQ_REMOVE(&vc->scan_dirents, fd, fds);
338d65f6f70SBen Gras 				if (fd->vno == 0) {
339d65f6f70SBen Gras 					nref = &fd->nref;
340d65f6f70SBen Gras 					*nref = fd->nref->nref_next;
341*84d9c625SLionel Sambuc 				} else if (fd->type == CHT_DIR) {
342*84d9c625SLionel Sambuc 					/* set state every non-VREG file's vc */
343d65f6f70SBen Gras 					mutex_enter(&chmp->chm_lock_vnocache);
344*84d9c625SLionel Sambuc 					notregvc = chfs_vnode_cache_get(chmp, fd->vno);
345*84d9c625SLionel Sambuc 					notregvc->state = VNO_STATE_PRESENT;
346d65f6f70SBen Gras 					mutex_exit(&chmp->chm_lock_vnocache);
347d65f6f70SBen Gras 				}
348d65f6f70SBen Gras 				chfs_free_dirent(fd);
349d65f6f70SBen Gras 			}
350d65f6f70SBen Gras 			KASSERT(TAILQ_EMPTY(&vc->scan_dirents));
351d65f6f70SBen Gras 			vc = vc->next;
352d65f6f70SBen Gras 		}
353d65f6f70SBen Gras 	}
354d65f6f70SBen Gras 
355*84d9c625SLionel Sambuc 	/* Set up chmp->chm_wbuf_ofs for the first write */
356d65f6f70SBen Gras 	if (chmp->chm_nextblock) {
357d65f6f70SBen Gras 		dbg("free_size: %d\n", chmp->chm_nextblock->free_size);
358d65f6f70SBen Gras 		chmp->chm_wbuf_ofs = chmp->chm_ebh->eb_size -
359d65f6f70SBen Gras 		    chmp->chm_nextblock->free_size;
360d65f6f70SBen Gras 	} else {
361d65f6f70SBen Gras 		chmp->chm_wbuf_ofs = 0xffffffff;
362d65f6f70SBen Gras 	}
363d65f6f70SBen Gras 	mutex_exit(&chmp->chm_lock_mountfields);
364d65f6f70SBen Gras 
365d65f6f70SBen Gras 	return 0;
366d65f6f70SBen Gras }
367d65f6f70SBen Gras 
368