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