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