Home | History | Annotate | Line # | Download | only in chfs
chfs_write.c revision 1.5
      1  1.5  ttoth /*	$NetBSD: chfs_write.c,v 1.5 2012/10/19 12:44:39 ttoth Exp $	*/
      2  1.1  ahoka 
      3  1.1  ahoka /*-
      4  1.1  ahoka  * Copyright (c) 2010 Department of Software Engineering,
      5  1.1  ahoka  *		      University of Szeged, Hungary
      6  1.1  ahoka  * Copyright (C) 2010 David Tengeri <dtengeri (at) inf.u-szeged.hu>
      7  1.1  ahoka  * Copyright (C) 2010 Tamas Toth <ttoth (at) inf.u-szeged.hu>
      8  1.1  ahoka  * Copyright (C) 2010 Adam Hoka <ahoka (at) NetBSD.org>
      9  1.1  ahoka  * All rights reserved.
     10  1.1  ahoka  *
     11  1.1  ahoka  * This code is derived from software contributed to The NetBSD Foundation
     12  1.1  ahoka  * by the Department of Software Engineering, University of Szeged, Hungary
     13  1.1  ahoka  *
     14  1.1  ahoka  * Redistribution and use in source and binary forms, with or without
     15  1.1  ahoka  * modification, are permitted provided that the following conditions
     16  1.1  ahoka  * are met:
     17  1.1  ahoka  * 1. Redistributions of source code must retain the above copyright
     18  1.1  ahoka  *    notice, this list of conditions and the following disclaimer.
     19  1.1  ahoka  * 2. Redistributions in binary form must reproduce the above copyright
     20  1.1  ahoka  *    notice, this list of conditions and the following disclaimer in the
     21  1.1  ahoka  *    documentation and/or other materials provided with the distribution.
     22  1.1  ahoka  *
     23  1.1  ahoka  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     24  1.1  ahoka  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     25  1.1  ahoka  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     26  1.1  ahoka  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     27  1.1  ahoka  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
     28  1.1  ahoka  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     29  1.1  ahoka  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
     30  1.1  ahoka  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     31  1.1  ahoka  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     32  1.1  ahoka  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     33  1.1  ahoka  * SUCH DAMAGE.
     34  1.1  ahoka  */
     35  1.1  ahoka 
     36  1.1  ahoka 
     37  1.1  ahoka #include <sys/param.h>
     38  1.1  ahoka #include <sys/buf.h>
     39  1.1  ahoka 
     40  1.1  ahoka #include "chfs.h"
     41  1.1  ahoka 
     42  1.5  ttoth 
     43  1.5  ttoth /* chfs_write_flash_vnode - writes out a vnode information to flash */
     44  1.1  ahoka int
     45  1.1  ahoka chfs_write_flash_vnode(struct chfs_mount *chmp,
     46  1.1  ahoka     struct chfs_inode *ip, int prio)
     47  1.1  ahoka {
     48  1.1  ahoka 	KASSERT(mutex_owned(&chmp->chm_lock_mountfields));
     49  1.1  ahoka 
     50  1.1  ahoka 	struct chfs_flash_vnode *fvnode;
     51  1.1  ahoka 	struct chfs_vnode_cache* chvc;
     52  1.1  ahoka 	struct chfs_node_ref *nref;
     53  1.1  ahoka 	struct iovec vec;
     54  1.1  ahoka 	size_t size, retlen;
     55  1.1  ahoka 	int err = 0, retries = 0;
     56  1.1  ahoka 
     57  1.5  ttoth 	/* root vnode is in-memory only */
     58  1.1  ahoka 	if (ip->ino == CHFS_ROOTINO)
     59  1.1  ahoka 		return 0;
     60  1.1  ahoka 
     61  1.1  ahoka 	fvnode = chfs_alloc_flash_vnode();
     62  1.1  ahoka 	if (!fvnode)
     63  1.1  ahoka 		return ENOMEM;
     64  1.1  ahoka 
     65  1.1  ahoka 	chvc = ip->chvc;
     66  1.1  ahoka 
     67  1.5  ttoth 	/* setting up flash_vnode's fields */
     68  1.1  ahoka 	size = sizeof(*fvnode);
     69  1.1  ahoka 	fvnode->magic = htole16(CHFS_FS_MAGIC_BITMASK);
     70  1.1  ahoka 	fvnode->type = htole16(CHFS_NODETYPE_VNODE);
     71  1.1  ahoka 	fvnode->length = htole32(CHFS_PAD(size));
     72  1.1  ahoka 	fvnode->hdr_crc = htole32(crc32(0, (uint8_t *)fvnode,
     73  1.1  ahoka 		CHFS_NODE_HDR_SIZE - 4));
     74  1.1  ahoka 	fvnode->vno = htole64(ip->ino);
     75  1.1  ahoka 	fvnode->version = htole64(++ip->chvc->highest_version);
     76  1.1  ahoka 	fvnode->mode = htole32(ip->mode);
     77  1.1  ahoka 	fvnode->dn_size = htole32(ip->size);
     78  1.1  ahoka 	fvnode->atime = htole32(ip->atime);
     79  1.1  ahoka 	fvnode->ctime = htole32(ip->ctime);
     80  1.1  ahoka 	fvnode->mtime = htole32(ip->mtime);
     81  1.1  ahoka 	fvnode->gid = htole32(ip->gid);
     82  1.1  ahoka 	fvnode->uid = htole32(ip->uid);
     83  1.1  ahoka 	fvnode->node_crc = htole32(crc32(0, (uint8_t *)fvnode, size - 4));
     84  1.1  ahoka 
     85  1.1  ahoka retry:
     86  1.5  ttoth 	/* setting up the next eraseblock where we will write */
     87  1.1  ahoka 	if (prio == ALLOC_GC) {
     88  1.5  ttoth 		/* GC called this function */
     89  1.1  ahoka 		err = chfs_reserve_space_gc(chmp, CHFS_PAD(size));
     90  1.1  ahoka 		if (err)
     91  1.1  ahoka 			goto out;
     92  1.1  ahoka 	} else {
     93  1.1  ahoka 		chfs_gc_trigger(chmp);
     94  1.1  ahoka 		if (prio == ALLOC_NORMAL)
     95  1.1  ahoka 			err = chfs_reserve_space_normal(chmp,
     96  1.1  ahoka 			    CHFS_PAD(size), ALLOC_NORMAL);
     97  1.1  ahoka 		else
     98  1.1  ahoka 			err = chfs_reserve_space_normal(chmp,
     99  1.1  ahoka 			    CHFS_PAD(size), ALLOC_DELETION);
    100  1.1  ahoka 		if (err)
    101  1.1  ahoka 			goto out;
    102  1.1  ahoka 	}
    103  1.1  ahoka 
    104  1.5  ttoth 	/* allocating a new node reference */
    105  1.1  ahoka 	nref = chfs_alloc_node_ref(chmp->chm_nextblock);
    106  1.1  ahoka 	if (!nref) {
    107  1.1  ahoka 		err = ENOMEM;
    108  1.1  ahoka 		goto out;
    109  1.1  ahoka 	}
    110  1.1  ahoka 
    111  1.1  ahoka 	mutex_enter(&chmp->chm_lock_sizes);
    112  1.1  ahoka 
    113  1.5  ttoth 	/* caculating offset and sizes  */
    114  1.1  ahoka 	nref->nref_offset = chmp->chm_ebh->eb_size - chmp->chm_nextblock->free_size;
    115  1.1  ahoka 	chfs_change_size_free(chmp, chmp->chm_nextblock, -CHFS_PAD(size));
    116  1.1  ahoka 	vec.iov_base = fvnode;
    117  1.1  ahoka 	vec.iov_len = CHFS_PAD(size);
    118  1.5  ttoth 
    119  1.5  ttoth 	/* write it into the writebuffer */
    120  1.1  ahoka 	err = chfs_write_wbuf(chmp, &vec, 1, nref->nref_offset, &retlen);
    121  1.1  ahoka 	if (err || retlen != CHFS_PAD(size)) {
    122  1.5  ttoth 		/* there was an error during write */
    123  1.1  ahoka 		chfs_err("error while writing out flash vnode to the media\n");
    124  1.1  ahoka 		chfs_err("err: %d | size: %zu | retlen : %zu\n",
    125  1.1  ahoka 		    err, CHFS_PAD(size), retlen);
    126  1.1  ahoka 		chfs_change_size_dirty(chmp,
    127  1.1  ahoka 		    chmp->chm_nextblock, CHFS_PAD(size));
    128  1.1  ahoka 		if (retries) {
    129  1.1  ahoka 			err = EIO;
    130  1.1  ahoka 			mutex_exit(&chmp->chm_lock_sizes);
    131  1.1  ahoka 			goto out;
    132  1.1  ahoka 		}
    133  1.1  ahoka 
    134  1.5  ttoth 		/* try again */
    135  1.1  ahoka 		retries++;
    136  1.1  ahoka 		mutex_exit(&chmp->chm_lock_sizes);
    137  1.1  ahoka 		goto retry;
    138  1.1  ahoka 	}
    139  1.5  ttoth 
    140  1.5  ttoth 	/* everything went well */
    141  1.1  ahoka 	chfs_change_size_used(chmp,
    142  1.1  ahoka 	    &chmp->chm_blocks[nref->nref_lnr], CHFS_PAD(size));
    143  1.1  ahoka 	mutex_exit(&chmp->chm_lock_sizes);
    144  1.1  ahoka 
    145  1.5  ttoth 	/* add the new nref to vnode cache */
    146  1.4  ttoth 	mutex_enter(&chmp->chm_lock_vnocache);
    147  1.1  ahoka 	chfs_add_vnode_ref_to_vc(chmp, chvc, nref);
    148  1.4  ttoth 	mutex_exit(&chmp->chm_lock_vnocache);
    149  1.1  ahoka 	KASSERT(chmp->chm_blocks[nref->nref_lnr].used_size <= chmp->chm_ebh->eb_size);
    150  1.1  ahoka out:
    151  1.1  ahoka 	chfs_free_flash_vnode(fvnode);
    152  1.1  ahoka 	return err;
    153  1.1  ahoka }
    154  1.1  ahoka 
    155  1.5  ttoth /* chfs_write_flash_dirent - writes out a directory entry to flash */
    156  1.1  ahoka int
    157  1.1  ahoka chfs_write_flash_dirent(struct chfs_mount *chmp, struct chfs_inode *pdir,
    158  1.1  ahoka     struct chfs_inode *ip, struct chfs_dirent *fd,
    159  1.1  ahoka     ino_t ino, int prio)
    160  1.1  ahoka {
    161  1.1  ahoka 	KASSERT(mutex_owned(&chmp->chm_lock_mountfields));
    162  1.1  ahoka 
    163  1.1  ahoka 	struct chfs_flash_dirent_node *fdirent;
    164  1.1  ahoka 	struct chfs_node_ref *nref;
    165  1.1  ahoka 	struct iovec vec[2];
    166  1.1  ahoka 	size_t size, retlen;
    167  1.1  ahoka 	int err = 0, retries = 0;
    168  1.1  ahoka 	uint8_t *name;
    169  1.1  ahoka 	size_t namelen;
    170  1.1  ahoka 
    171  1.1  ahoka 	KASSERT(fd->vno != CHFS_ROOTINO);
    172  1.1  ahoka 
    173  1.5  ttoth 	/* setting up flash_dirent's fields */
    174  1.1  ahoka 	fdirent = chfs_alloc_flash_dirent();
    175  1.1  ahoka 	if (!fdirent)
    176  1.1  ahoka 		return ENOMEM;
    177  1.1  ahoka 
    178  1.1  ahoka 	size = sizeof(*fdirent) + fd->nsize;
    179  1.1  ahoka 	namelen = CHFS_PAD(size) - sizeof(*fdirent);
    180  1.1  ahoka 
    181  1.1  ahoka 	name = kmem_zalloc(namelen, KM_SLEEP);
    182  1.1  ahoka 	memcpy(name, fd->name, fd->nsize);
    183  1.1  ahoka 
    184  1.1  ahoka 	fdirent->magic = htole16(CHFS_FS_MAGIC_BITMASK);
    185  1.1  ahoka 	fdirent->type = htole16(CHFS_NODETYPE_DIRENT);
    186  1.1  ahoka 	fdirent->length = htole32(CHFS_PAD(size));
    187  1.1  ahoka 	fdirent->hdr_crc = htole32(crc32(0, (uint8_t *)fdirent,
    188  1.1  ahoka 		CHFS_NODE_HDR_SIZE - 4));
    189  1.1  ahoka 	fdirent->vno = htole64(ino);
    190  1.1  ahoka 	fdirent->pvno = htole64(pdir->ino);
    191  1.1  ahoka 	fdirent->version = htole64(++pdir->chvc->highest_version);
    192  1.1  ahoka 	fdirent->mctime = ip?ip->ctime:0;
    193  1.1  ahoka 	fdirent->nsize = fd->nsize;
    194  1.1  ahoka 	fdirent->dtype = fd->type;
    195  1.1  ahoka 	fdirent->name_crc = crc32(0, (uint8_t *)&(fd->name), fd->nsize);
    196  1.1  ahoka 	fdirent->node_crc = crc32(0, (uint8_t *)fdirent, sizeof(*fdirent) - 4);
    197  1.1  ahoka 
    198  1.5  ttoth 	/* directory's name is written out right after the dirent */
    199  1.1  ahoka 	vec[0].iov_base = fdirent;
    200  1.1  ahoka 	vec[0].iov_len  = sizeof(*fdirent);
    201  1.1  ahoka 	vec[1].iov_base = name;
    202  1.1  ahoka 	vec[1].iov_len  = namelen;
    203  1.1  ahoka 
    204  1.1  ahoka retry:
    205  1.5  ttoth 	/* setting up the next eraseblock where we will write */
    206  1.1  ahoka 	if (prio == ALLOC_GC) {
    207  1.1  ahoka 		/* the GC calls this function */
    208  1.1  ahoka 		err = chfs_reserve_space_gc(chmp, CHFS_PAD(size));
    209  1.1  ahoka 		if (err)
    210  1.1  ahoka 			goto out;
    211  1.1  ahoka 	} else {
    212  1.1  ahoka 		chfs_gc_trigger(chmp);
    213  1.1  ahoka 		if (prio == ALLOC_NORMAL)
    214  1.1  ahoka 			err = chfs_reserve_space_normal(chmp,
    215  1.1  ahoka 			    CHFS_PAD(size), ALLOC_NORMAL);
    216  1.1  ahoka 		else
    217  1.1  ahoka 			err = chfs_reserve_space_normal(chmp,
    218  1.1  ahoka 			    CHFS_PAD(size), ALLOC_DELETION);
    219  1.1  ahoka 		if (err)
    220  1.1  ahoka 			goto out;
    221  1.1  ahoka 	}
    222  1.1  ahoka 
    223  1.5  ttoth 	/* allocating a new node reference */
    224  1.1  ahoka 	nref = chfs_alloc_node_ref(chmp->chm_nextblock);
    225  1.1  ahoka 	if (!nref) {
    226  1.1  ahoka 		err = ENOMEM;
    227  1.1  ahoka 		goto out;
    228  1.1  ahoka 	}
    229  1.1  ahoka 
    230  1.1  ahoka 	mutex_enter(&chmp->chm_lock_sizes);
    231  1.1  ahoka 
    232  1.1  ahoka 	nref->nref_offset = chmp->chm_ebh->eb_size - chmp->chm_nextblock->free_size;
    233  1.1  ahoka 	chfs_change_size_free(chmp, chmp->chm_nextblock, -CHFS_PAD(size));
    234  1.1  ahoka 
    235  1.5  ttoth 	/* write it into the writebuffer */
    236  1.1  ahoka 	err = chfs_write_wbuf(chmp, vec, 2, nref->nref_offset, &retlen);
    237  1.1  ahoka 	if (err || retlen != CHFS_PAD(size)) {
    238  1.5  ttoth 		/* there was an error during write */
    239  1.1  ahoka 		chfs_err("error while writing out flash dirent node to the media\n");
    240  1.1  ahoka 		chfs_err("err: %d | size: %zu | retlen : %zu\n",
    241  1.1  ahoka 		    err, CHFS_PAD(size), retlen);
    242  1.1  ahoka 		chfs_change_size_dirty(chmp,
    243  1.1  ahoka 		    chmp->chm_nextblock, CHFS_PAD(size));
    244  1.1  ahoka 		if (retries) {
    245  1.1  ahoka 			err = EIO;
    246  1.1  ahoka 			mutex_exit(&chmp->chm_lock_sizes);
    247  1.1  ahoka 			goto out;
    248  1.1  ahoka 		}
    249  1.1  ahoka 
    250  1.5  ttoth 		/* try again */
    251  1.1  ahoka 		retries++;
    252  1.1  ahoka 		mutex_exit(&chmp->chm_lock_sizes);
    253  1.1  ahoka 		goto retry;
    254  1.1  ahoka 	}
    255  1.1  ahoka 
    256  1.1  ahoka 
    257  1.5  ttoth 	/* everything went well */
    258  1.1  ahoka 	chfs_change_size_used(chmp,
    259  1.1  ahoka 	    &chmp->chm_blocks[nref->nref_lnr], CHFS_PAD(size));
    260  1.1  ahoka 	mutex_exit(&chmp->chm_lock_sizes);
    261  1.1  ahoka 	KASSERT(chmp->chm_blocks[nref->nref_lnr].used_size <= chmp->chm_ebh->eb_size);
    262  1.4  ttoth 
    263  1.5  ttoth 	/* add the new nref to the directory chain of vnode cache */
    264  1.1  ahoka 	fd->nref = nref;
    265  1.1  ahoka 	if (prio != ALLOC_DELETION) {
    266  1.4  ttoth 		mutex_enter(&chmp->chm_lock_vnocache);
    267  1.1  ahoka 		chfs_add_node_to_list(chmp,
    268  1.1  ahoka 			pdir->chvc, nref, &pdir->chvc->dirents);
    269  1.4  ttoth 		mutex_exit(&chmp->chm_lock_vnocache);
    270  1.1  ahoka 	}
    271  1.1  ahoka out:
    272  1.1  ahoka 	chfs_free_flash_dirent(fdirent);
    273  1.1  ahoka 	return err;
    274  1.1  ahoka }
    275  1.1  ahoka 
    276  1.5  ttoth /* chfs_write_flash_dnode - writes out a data node to flash */
    277  1.1  ahoka int
    278  1.1  ahoka chfs_write_flash_dnode(struct chfs_mount *chmp, struct vnode *vp,
    279  1.1  ahoka     struct buf *bp, struct chfs_full_dnode *fd)
    280  1.1  ahoka {
    281  1.1  ahoka 	KASSERT(mutex_owned(&chmp->chm_lock_mountfields));
    282  1.1  ahoka 
    283  1.1  ahoka 	int err = 0, retries = 0;
    284  1.1  ahoka 	size_t size, retlen;
    285  1.1  ahoka 	off_t ofs;
    286  1.1  ahoka 	struct chfs_flash_data_node *dnode;
    287  1.1  ahoka 	struct chfs_node_ref *nref;
    288  1.1  ahoka 	struct chfs_inode *ip = VTOI(vp);
    289  1.1  ahoka 	struct iovec vec[2];
    290  1.1  ahoka 	uint32_t len;
    291  1.1  ahoka 	void *tmpbuf = NULL;
    292  1.1  ahoka 
    293  1.1  ahoka 	KASSERT(ip->ino != CHFS_ROOTINO);
    294  1.1  ahoka 
    295  1.1  ahoka 	dnode = chfs_alloc_flash_dnode();
    296  1.1  ahoka 	if (!dnode)
    297  1.1  ahoka 		return ENOMEM;
    298  1.1  ahoka 
    299  1.1  ahoka 	/* initialize flash data node */
    300  1.1  ahoka 	ofs = bp->b_blkno * PAGE_SIZE;
    301  1.1  ahoka 	len = MIN((vp->v_size - ofs), bp->b_resid);
    302  1.1  ahoka 	size = sizeof(*dnode) + len;
    303  1.1  ahoka 
    304  1.1  ahoka 	dnode->magic = htole16(CHFS_FS_MAGIC_BITMASK);
    305  1.1  ahoka 	dnode->type = htole16(CHFS_NODETYPE_DATA);
    306  1.1  ahoka 	dnode->length = htole32(CHFS_PAD(size));
    307  1.1  ahoka 	dnode->hdr_crc = htole32(crc32(0, (uint8_t *)dnode,
    308  1.1  ahoka 		CHFS_NODE_HDR_SIZE - 4));
    309  1.1  ahoka 	dnode->vno = htole64(ip->ino);
    310  1.1  ahoka 	dnode->version = htole64(++ip->chvc->highest_version);
    311  1.1  ahoka 	dnode->offset = htole64(ofs);
    312  1.1  ahoka 	dnode->data_length = htole32(len);
    313  1.1  ahoka 	dnode->data_crc = htole32(crc32(0, (uint8_t *)bp->b_data, len));
    314  1.1  ahoka 	dnode->node_crc = htole32(crc32(0, (uint8_t *)dnode,
    315  1.1  ahoka 		sizeof(*dnode) - 4));
    316  1.1  ahoka 
    317  1.2    agc 	dbg("dnode @%llu %ub v%llu\n", (unsigned long long)dnode->offset,
    318  1.2    agc 		dnode->data_length, (unsigned long long)dnode->version);
    319  1.1  ahoka 
    320  1.5  ttoth 	/* pad data if needed */
    321  1.1  ahoka 	if (CHFS_PAD(size) - sizeof(*dnode)) {
    322  1.1  ahoka 		tmpbuf = kmem_zalloc(CHFS_PAD(size)
    323  1.1  ahoka 		    - sizeof(*dnode), KM_SLEEP);
    324  1.1  ahoka 		memcpy(tmpbuf, bp->b_data, len);
    325  1.1  ahoka 	}
    326  1.1  ahoka 
    327  1.5  ttoth 	/* creating iovecs for writebuffer
    328  1.5  ttoth 	 * data is written out right after the data node */
    329  1.1  ahoka 	vec[0].iov_base = dnode;
    330  1.1  ahoka 	vec[0].iov_len = sizeof(*dnode);
    331  1.1  ahoka 	vec[1].iov_base = tmpbuf;
    332  1.1  ahoka 	vec[1].iov_len = CHFS_PAD(size) - sizeof(*dnode);
    333  1.1  ahoka 
    334  1.1  ahoka 	fd->ofs = ofs;
    335  1.1  ahoka 	fd->size = len;
    336  1.1  ahoka 
    337  1.1  ahoka retry:
    338  1.1  ahoka 	/* Reserve space for data node. This will set up the next eraseblock
    339  1.1  ahoka 	 * where to we will write.
    340  1.1  ahoka 	 */
    341  1.1  ahoka 	chfs_gc_trigger(chmp);
    342  1.1  ahoka 	err = chfs_reserve_space_normal(chmp,
    343  1.1  ahoka 	    CHFS_PAD(size), ALLOC_NORMAL);
    344  1.1  ahoka 	if (err)
    345  1.1  ahoka 		goto out;
    346  1.1  ahoka 
    347  1.5  ttoth 	/* allocating a new node reference */
    348  1.1  ahoka 	nref = chfs_alloc_node_ref(chmp->chm_nextblock);
    349  1.1  ahoka 	if (!nref) {
    350  1.1  ahoka 		err = ENOMEM;
    351  1.1  ahoka 		goto out;
    352  1.1  ahoka 	}
    353  1.1  ahoka 
    354  1.1  ahoka 	nref->nref_offset =
    355  1.1  ahoka 	    chmp->chm_ebh->eb_size - chmp->chm_nextblock->free_size;
    356  1.1  ahoka 
    357  1.1  ahoka 	KASSERT(nref->nref_offset < chmp->chm_ebh->eb_size);
    358  1.1  ahoka 
    359  1.1  ahoka 	mutex_enter(&chmp->chm_lock_sizes);
    360  1.1  ahoka 
    361  1.1  ahoka 	chfs_change_size_free(chmp,
    362  1.1  ahoka 	    chmp->chm_nextblock, -CHFS_PAD(size));
    363  1.1  ahoka 
    364  1.5  ttoth 	/* write it into the writebuffer */
    365  1.1  ahoka 	err = chfs_write_wbuf(chmp, vec, 2, nref->nref_offset, &retlen);
    366  1.1  ahoka 	if (err || retlen != CHFS_PAD(size)) {
    367  1.5  ttoth 		/* there was an error during write */
    368  1.1  ahoka 		chfs_err("error while writing out flash data node to the media\n");
    369  1.1  ahoka 		chfs_err("err: %d | size: %zu | retlen : %zu\n",
    370  1.1  ahoka 		    err, size, retlen);
    371  1.1  ahoka 		chfs_change_size_dirty(chmp,
    372  1.1  ahoka 		    chmp->chm_nextblock, CHFS_PAD(size));
    373  1.1  ahoka 		if (retries) {
    374  1.1  ahoka 			err = EIO;
    375  1.1  ahoka 			mutex_exit(&chmp->chm_lock_sizes);
    376  1.1  ahoka 			goto out;
    377  1.1  ahoka 		}
    378  1.1  ahoka 
    379  1.5  ttoth 		/* try again */
    380  1.1  ahoka 		retries++;
    381  1.1  ahoka 		mutex_exit(&chmp->chm_lock_sizes);
    382  1.1  ahoka 		goto retry;
    383  1.1  ahoka 	}
    384  1.5  ttoth 	/* everything went well */
    385  1.1  ahoka 	ip->write_size += fd->size;
    386  1.1  ahoka 	chfs_change_size_used(chmp,
    387  1.1  ahoka 	    &chmp->chm_blocks[nref->nref_lnr], CHFS_PAD(size));
    388  1.1  ahoka 	mutex_exit(&chmp->chm_lock_sizes);
    389  1.1  ahoka 
    390  1.4  ttoth 	mutex_enter(&chmp->chm_lock_vnocache);
    391  1.4  ttoth 	if (fd->nref != NULL) {
    392  1.4  ttoth 		chfs_remove_frags_of_node(chmp, &ip->fragtree, fd->nref);
    393  1.4  ttoth 		chfs_remove_and_obsolete(chmp, ip->chvc, fd->nref, &ip->chvc->dnode);
    394  1.4  ttoth 	}
    395  1.4  ttoth 
    396  1.5  ttoth 	/* add the new nref to the data node chain of vnode cache */
    397  1.1  ahoka 	KASSERT(chmp->chm_blocks[nref->nref_lnr].used_size <= chmp->chm_ebh->eb_size);
    398  1.1  ahoka 	fd->nref = nref;
    399  1.1  ahoka 	chfs_add_node_to_list(chmp, ip->chvc, nref, &ip->chvc->dnode);
    400  1.4  ttoth 	mutex_exit(&chmp->chm_lock_vnocache);
    401  1.1  ahoka out:
    402  1.1  ahoka 	chfs_free_flash_dnode(dnode);
    403  1.1  ahoka 	if (CHFS_PAD(size) - sizeof(*dnode)) {
    404  1.1  ahoka 		kmem_free(tmpbuf, CHFS_PAD(size) - sizeof(*dnode));
    405  1.1  ahoka 	}
    406  1.1  ahoka 
    407  1.1  ahoka 	return err;
    408  1.1  ahoka }
    409  1.1  ahoka 
    410  1.5  ttoth /*
    411  1.1  ahoka  * chfs_do_link - makes a copy from a node
    412  1.1  ahoka  * This function writes the dirent of the new node to the media.
    413  1.1  ahoka  */
    414  1.1  ahoka int
    415  1.3  ttoth chfs_do_link(struct chfs_inode *ip, struct chfs_inode *parent, const char *name, int namelen, enum chtype type)
    416  1.1  ahoka {
    417  1.1  ahoka 	int error = 0;
    418  1.1  ahoka 	struct vnode *vp = ITOV(ip);
    419  1.1  ahoka 	struct ufsmount *ump = VFSTOUFS(vp->v_mount);
    420  1.1  ahoka 	struct chfs_mount *chmp = ump->um_chfs;
    421  1.1  ahoka 	struct chfs_dirent *newfd = NULL;
    422  1.1  ahoka 
    423  1.5  ttoth 	/* setting up the new directory entry */
    424  1.1  ahoka 	newfd = chfs_alloc_dirent(namelen + 1);
    425  1.1  ahoka 
    426  1.1  ahoka 	newfd->vno = ip->ino;
    427  1.1  ahoka 	newfd->type = type;
    428  1.1  ahoka 	newfd->nsize = namelen;
    429  1.1  ahoka 	memcpy(newfd->name, name, namelen);
    430  1.1  ahoka 	newfd->name[newfd->nsize] = 0;
    431  1.1  ahoka 
    432  1.1  ahoka 	ip->chvc->nlink++;
    433  1.1  ahoka 	parent->chvc->nlink++;
    434  1.1  ahoka 	ip->iflag |= IN_CHANGE;
    435  1.1  ahoka 	chfs_update(vp, NULL, NULL, UPDATE_WAIT);
    436  1.1  ahoka 
    437  1.1  ahoka 	mutex_enter(&chmp->chm_lock_mountfields);
    438  1.1  ahoka 
    439  1.5  ttoth 	/* update vnode information */
    440  1.1  ahoka 	error = chfs_write_flash_vnode(chmp, ip, ALLOC_NORMAL);
    441  1.1  ahoka 	if (error)
    442  1.1  ahoka 		return error;
    443  1.1  ahoka 
    444  1.5  ttoth 	/* write out the new dirent */
    445  1.1  ahoka 	error = chfs_write_flash_dirent(chmp,
    446  1.1  ahoka 	    parent, ip, newfd, ip->ino, ALLOC_NORMAL);
    447  1.1  ahoka 	/* TODO: what should we do if error isn't zero? */
    448  1.1  ahoka 
    449  1.1  ahoka 	mutex_exit(&chmp->chm_lock_mountfields);
    450  1.1  ahoka 
    451  1.1  ahoka 	/* add fd to the fd list */
    452  1.1  ahoka 	TAILQ_INSERT_TAIL(&parent->dents, newfd, fds);
    453  1.1  ahoka 
    454  1.1  ahoka 	return error;
    455  1.1  ahoka }
    456  1.1  ahoka 
    457  1.1  ahoka 
    458  1.5  ttoth /*
    459  1.1  ahoka  * chfs_do_unlink - delete a node
    460  1.5  ttoth  * This function set the nlink and vno of the node to zero and
    461  1.5  ttoth  * write its dirent to the media.
    462  1.1  ahoka  */
    463  1.1  ahoka int
    464  1.1  ahoka chfs_do_unlink(struct chfs_inode *ip,
    465  1.1  ahoka     struct chfs_inode *parent, const char *name, int namelen)
    466  1.1  ahoka {
    467  1.1  ahoka 	struct chfs_dirent *fd, *tmpfd;
    468  1.1  ahoka 	int error = 0;
    469  1.1  ahoka 	struct vnode *vp = ITOV(ip);
    470  1.1  ahoka 	struct ufsmount *ump = VFSTOUFS(vp->v_mount);
    471  1.1  ahoka 	struct chfs_mount *chmp = ump->um_chfs;
    472  1.1  ahoka 	struct chfs_node_ref *nref;
    473  1.1  ahoka 
    474  1.1  ahoka 	vflushbuf(vp, 0);
    475  1.1  ahoka 
    476  1.1  ahoka 	mutex_enter(&chmp->chm_lock_mountfields);
    477  1.1  ahoka 
    478  1.1  ahoka 	/* remove the full direntry from the parent dents list */
    479  1.1  ahoka 	TAILQ_FOREACH_SAFE(fd, &parent->dents, fds, tmpfd) {
    480  1.1  ahoka 		if (fd->vno == ip->ino &&
    481  1.1  ahoka 		    fd->nsize == namelen &&
    482  1.1  ahoka 		    !memcmp(fd->name, name, fd->nsize)) {
    483  1.4  ttoth 
    484  1.5  ttoth 			/* remove every fragment of the file */
    485  1.4  ttoth 			chfs_kill_fragtree(chmp, &ip->fragtree);
    486  1.4  ttoth 
    487  1.5  ttoth 			/* decrease number of links to the file */
    488  1.3  ttoth 			if (fd->type == CHT_DIR && ip->chvc->nlink == 2)
    489  1.1  ahoka 				ip->chvc->nlink = 0;
    490  1.1  ahoka 			else
    491  1.1  ahoka 				ip->chvc->nlink--;
    492  1.1  ahoka 
    493  1.3  ttoth 			fd->type = CHT_BLANK;
    494  1.1  ahoka 
    495  1.5  ttoth 			/* remove from parent's directory entries */
    496  1.1  ahoka 			TAILQ_REMOVE(&parent->dents, fd, fds);
    497  1.1  ahoka 
    498  1.4  ttoth 			mutex_enter(&chmp->chm_lock_vnocache);
    499  1.1  ahoka 
    500  1.4  ttoth 			dbg("FD->NREF vno: %llu, lnr: %u, ofs: %u\n",
    501  1.4  ttoth 			    fd->vno, fd->nref->nref_lnr, fd->nref->nref_offset);
    502  1.4  ttoth 			chfs_remove_and_obsolete(chmp, parent->chvc, fd->nref,
    503  1.4  ttoth 				&parent->chvc->dirents);
    504  1.1  ahoka 
    505  1.1  ahoka 			error = chfs_write_flash_dirent(chmp,
    506  1.1  ahoka 			    parent, ip, fd, 0, ALLOC_DELETION);
    507  1.1  ahoka 
    508  1.4  ttoth 			dbg("FD->NREF vno: %llu, lnr: %u, ofs: %u\n",
    509  1.4  ttoth 			    fd->vno, fd->nref->nref_lnr, fd->nref->nref_offset);
    510  1.5  ttoth 			/* set nref_next field */
    511  1.4  ttoth 			chfs_add_node_to_list(chmp, parent->chvc, fd->nref,
    512  1.4  ttoth 				&parent->chvc->dirents);
    513  1.5  ttoth 			/* remove from the list */
    514  1.4  ttoth 			chfs_remove_and_obsolete(chmp, parent->chvc, fd->nref,
    515  1.4  ttoth 				&parent->chvc->dirents);
    516  1.4  ttoth 
    517  1.5  ttoth 			/* clean dnode list */
    518  1.4  ttoth 			while (ip->chvc->dnode != (struct chfs_node_ref *)ip->chvc) {
    519  1.4  ttoth 				nref = ip->chvc->dnode;
    520  1.4  ttoth 				chfs_remove_frags_of_node(chmp, &ip->fragtree, nref);
    521  1.4  ttoth 				chfs_remove_and_obsolete(chmp, ip->chvc, nref, &ip->chvc->dnode);
    522  1.1  ahoka 			}
    523  1.1  ahoka 
    524  1.5  ttoth 			/* clean vnode information (list) */
    525  1.4  ttoth 			while (ip->chvc->v != (struct chfs_node_ref *)ip->chvc) {
    526  1.4  ttoth 				nref = ip->chvc->v;
    527  1.4  ttoth 				chfs_remove_and_obsolete(chmp, ip->chvc, nref, &ip->chvc->v);
    528  1.1  ahoka 			}
    529  1.1  ahoka 
    530  1.5  ttoth 			/* decrease number of links to parent */
    531  1.1  ahoka 			parent->chvc->nlink--;
    532  1.4  ttoth 
    533  1.4  ttoth 			mutex_exit(&chmp->chm_lock_vnocache);
    534  1.1  ahoka 			//TODO: if error
    535  1.1  ahoka 		}
    536  1.1  ahoka 	}
    537  1.1  ahoka 	mutex_exit(&chmp->chm_lock_mountfields);
    538  1.1  ahoka 
    539  1.1  ahoka 	return error;
    540  1.1  ahoka }
    541