xref: /netbsd-src/sys/ufs/chfs/chfs_write.c (revision f273a7a174ebed441f3363e0c944bd42390ca256)
1*f273a7a1Sandvar /*	$NetBSD: chfs_write.c,v 1.7 2021/12/07 21:37:37 andvar Exp $	*/
2288addd0Sahoka 
3288addd0Sahoka /*-
4288addd0Sahoka  * Copyright (c) 2010 Department of Software Engineering,
5288addd0Sahoka  *		      University of Szeged, Hungary
6288addd0Sahoka  * Copyright (C) 2010 David Tengeri <dtengeri@inf.u-szeged.hu>
7288addd0Sahoka  * Copyright (C) 2010 Tamas Toth <ttoth@inf.u-szeged.hu>
8288addd0Sahoka  * Copyright (C) 2010 Adam Hoka <ahoka@NetBSD.org>
9288addd0Sahoka  * All rights reserved.
10288addd0Sahoka  *
11288addd0Sahoka  * This code is derived from software contributed to The NetBSD Foundation
12288addd0Sahoka  * by the Department of Software Engineering, University of Szeged, Hungary
13288addd0Sahoka  *
14288addd0Sahoka  * Redistribution and use in source and binary forms, with or without
15288addd0Sahoka  * modification, are permitted provided that the following conditions
16288addd0Sahoka  * are met:
17288addd0Sahoka  * 1. Redistributions of source code must retain the above copyright
18288addd0Sahoka  *    notice, this list of conditions and the following disclaimer.
19288addd0Sahoka  * 2. Redistributions in binary form must reproduce the above copyright
20288addd0Sahoka  *    notice, this list of conditions and the following disclaimer in the
21288addd0Sahoka  *    documentation and/or other materials provided with the distribution.
22288addd0Sahoka  *
23288addd0Sahoka  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24288addd0Sahoka  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25288addd0Sahoka  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26288addd0Sahoka  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27288addd0Sahoka  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28288addd0Sahoka  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29288addd0Sahoka  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
30288addd0Sahoka  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31288addd0Sahoka  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32288addd0Sahoka  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33288addd0Sahoka  * SUCH DAMAGE.
34288addd0Sahoka  */
35288addd0Sahoka 
36288addd0Sahoka 
37288addd0Sahoka #include <sys/param.h>
38288addd0Sahoka #include <sys/buf.h>
39288addd0Sahoka 
40288addd0Sahoka #include "chfs.h"
41288addd0Sahoka 
42bca84b9eSttoth 
43bca84b9eSttoth /* chfs_write_flash_vnode - writes out a vnode information to flash */
44288addd0Sahoka int
chfs_write_flash_vnode(struct chfs_mount * chmp,struct chfs_inode * ip,int prio)45288addd0Sahoka chfs_write_flash_vnode(struct chfs_mount *chmp,
46288addd0Sahoka     struct chfs_inode *ip, int prio)
47288addd0Sahoka {
48288addd0Sahoka 	KASSERT(mutex_owned(&chmp->chm_lock_mountfields));
49288addd0Sahoka 
50288addd0Sahoka 	struct chfs_flash_vnode *fvnode;
51288addd0Sahoka 	struct chfs_vnode_cache* chvc;
52288addd0Sahoka 	struct chfs_node_ref *nref;
53288addd0Sahoka 	struct iovec vec;
54288addd0Sahoka 	size_t size, retlen;
55288addd0Sahoka 	int err = 0, retries = 0;
56288addd0Sahoka 
57bca84b9eSttoth 	/* root vnode is in-memory only */
58288addd0Sahoka 	if (ip->ino == CHFS_ROOTINO)
59288addd0Sahoka 		return 0;
60288addd0Sahoka 
61288addd0Sahoka 	fvnode = chfs_alloc_flash_vnode();
62288addd0Sahoka 	if (!fvnode)
63288addd0Sahoka 		return ENOMEM;
64288addd0Sahoka 
65288addd0Sahoka 	chvc = ip->chvc;
66288addd0Sahoka 
67bca84b9eSttoth 	/* setting up flash_vnode's fields */
68288addd0Sahoka 	size = sizeof(*fvnode);
69288addd0Sahoka 	fvnode->magic = htole16(CHFS_FS_MAGIC_BITMASK);
70288addd0Sahoka 	fvnode->type = htole16(CHFS_NODETYPE_VNODE);
71288addd0Sahoka 	fvnode->length = htole32(CHFS_PAD(size));
72288addd0Sahoka 	fvnode->hdr_crc = htole32(crc32(0, (uint8_t *)fvnode,
73288addd0Sahoka 		CHFS_NODE_HDR_SIZE - 4));
74288addd0Sahoka 	fvnode->vno = htole64(ip->ino);
75288addd0Sahoka 	fvnode->version = htole64(++ip->chvc->highest_version);
76288addd0Sahoka 	fvnode->mode = htole32(ip->mode);
77288addd0Sahoka 	fvnode->dn_size = htole32(ip->size);
78288addd0Sahoka 	fvnode->atime = htole32(ip->atime);
79288addd0Sahoka 	fvnode->ctime = htole32(ip->ctime);
80288addd0Sahoka 	fvnode->mtime = htole32(ip->mtime);
81288addd0Sahoka 	fvnode->gid = htole32(ip->gid);
82288addd0Sahoka 	fvnode->uid = htole32(ip->uid);
83288addd0Sahoka 	fvnode->node_crc = htole32(crc32(0, (uint8_t *)fvnode, size - 4));
84288addd0Sahoka 
85288addd0Sahoka retry:
86bca84b9eSttoth 	/* setting up the next eraseblock where we will write */
87288addd0Sahoka 	if (prio == ALLOC_GC) {
88bca84b9eSttoth 		/* GC called this function */
89288addd0Sahoka 		err = chfs_reserve_space_gc(chmp, CHFS_PAD(size));
90288addd0Sahoka 		if (err)
91288addd0Sahoka 			goto out;
92288addd0Sahoka 	} else {
93288addd0Sahoka 		chfs_gc_trigger(chmp);
94288addd0Sahoka 		if (prio == ALLOC_NORMAL)
95288addd0Sahoka 			err = chfs_reserve_space_normal(chmp,
96288addd0Sahoka 			    CHFS_PAD(size), ALLOC_NORMAL);
97288addd0Sahoka 		else
98288addd0Sahoka 			err = chfs_reserve_space_normal(chmp,
99288addd0Sahoka 			    CHFS_PAD(size), ALLOC_DELETION);
100288addd0Sahoka 		if (err)
101288addd0Sahoka 			goto out;
102288addd0Sahoka 	}
103288addd0Sahoka 
104bca84b9eSttoth 	/* allocating a new node reference */
105288addd0Sahoka 	nref = chfs_alloc_node_ref(chmp->chm_nextblock);
106288addd0Sahoka 	if (!nref) {
107288addd0Sahoka 		err = ENOMEM;
108288addd0Sahoka 		goto out;
109288addd0Sahoka 	}
110288addd0Sahoka 
111288addd0Sahoka 	mutex_enter(&chmp->chm_lock_sizes);
112288addd0Sahoka 
113*f273a7a1Sandvar 	/* calculating offset and sizes  */
114288addd0Sahoka 	nref->nref_offset = chmp->chm_ebh->eb_size - chmp->chm_nextblock->free_size;
115288addd0Sahoka 	chfs_change_size_free(chmp, chmp->chm_nextblock, -CHFS_PAD(size));
116288addd0Sahoka 	vec.iov_base = fvnode;
117288addd0Sahoka 	vec.iov_len = CHFS_PAD(size);
118bca84b9eSttoth 
119bca84b9eSttoth 	/* write it into the writebuffer */
120288addd0Sahoka 	err = chfs_write_wbuf(chmp, &vec, 1, nref->nref_offset, &retlen);
121288addd0Sahoka 	if (err || retlen != CHFS_PAD(size)) {
122bca84b9eSttoth 		/* there was an error during write */
123288addd0Sahoka 		chfs_err("error while writing out flash vnode to the media\n");
124288addd0Sahoka 		chfs_err("err: %d | size: %zu | retlen : %zu\n",
125288addd0Sahoka 		    err, CHFS_PAD(size), retlen);
126288addd0Sahoka 		chfs_change_size_dirty(chmp,
127288addd0Sahoka 		    chmp->chm_nextblock, CHFS_PAD(size));
128288addd0Sahoka 		if (retries) {
129288addd0Sahoka 			err = EIO;
130288addd0Sahoka 			mutex_exit(&chmp->chm_lock_sizes);
131288addd0Sahoka 			goto out;
132288addd0Sahoka 		}
133288addd0Sahoka 
134bca84b9eSttoth 		/* try again */
135288addd0Sahoka 		retries++;
136288addd0Sahoka 		mutex_exit(&chmp->chm_lock_sizes);
137288addd0Sahoka 		goto retry;
138288addd0Sahoka 	}
139bca84b9eSttoth 
140bca84b9eSttoth 	/* everything went well */
141288addd0Sahoka 	chfs_change_size_used(chmp,
142288addd0Sahoka 	    &chmp->chm_blocks[nref->nref_lnr], CHFS_PAD(size));
143288addd0Sahoka 	mutex_exit(&chmp->chm_lock_sizes);
144288addd0Sahoka 
145bca84b9eSttoth 	/* add the new nref to vnode cache */
1463fae61eeSttoth 	mutex_enter(&chmp->chm_lock_vnocache);
147288addd0Sahoka 	chfs_add_vnode_ref_to_vc(chmp, chvc, nref);
1483fae61eeSttoth 	mutex_exit(&chmp->chm_lock_vnocache);
149288addd0Sahoka 	KASSERT(chmp->chm_blocks[nref->nref_lnr].used_size <= chmp->chm_ebh->eb_size);
150288addd0Sahoka out:
151288addd0Sahoka 	chfs_free_flash_vnode(fvnode);
152288addd0Sahoka 	return err;
153288addd0Sahoka }
154288addd0Sahoka 
155bca84b9eSttoth /* chfs_write_flash_dirent - writes out a directory entry to flash */
156288addd0Sahoka 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)157288addd0Sahoka chfs_write_flash_dirent(struct chfs_mount *chmp, struct chfs_inode *pdir,
158288addd0Sahoka     struct chfs_inode *ip, struct chfs_dirent *fd,
159288addd0Sahoka     ino_t ino, int prio)
160288addd0Sahoka {
161288addd0Sahoka 	KASSERT(mutex_owned(&chmp->chm_lock_mountfields));
162288addd0Sahoka 
163288addd0Sahoka 	struct chfs_flash_dirent_node *fdirent;
164288addd0Sahoka 	struct chfs_node_ref *nref;
165288addd0Sahoka 	struct iovec vec[2];
166288addd0Sahoka 	size_t size, retlen;
167288addd0Sahoka 	int err = 0, retries = 0;
168288addd0Sahoka 	uint8_t *name;
169288addd0Sahoka 	size_t namelen;
170288addd0Sahoka 
171288addd0Sahoka 	KASSERT(fd->vno != CHFS_ROOTINO);
172288addd0Sahoka 
173bca84b9eSttoth 	/* setting up flash_dirent's fields */
174288addd0Sahoka 	fdirent = chfs_alloc_flash_dirent();
175288addd0Sahoka 	if (!fdirent)
176288addd0Sahoka 		return ENOMEM;
177288addd0Sahoka 
178288addd0Sahoka 	size = sizeof(*fdirent) + fd->nsize;
179288addd0Sahoka 	namelen = CHFS_PAD(size) - sizeof(*fdirent);
180288addd0Sahoka 
181288addd0Sahoka 	name = kmem_zalloc(namelen, KM_SLEEP);
182288addd0Sahoka 	memcpy(name, fd->name, fd->nsize);
183288addd0Sahoka 
184288addd0Sahoka 	fdirent->magic = htole16(CHFS_FS_MAGIC_BITMASK);
185288addd0Sahoka 	fdirent->type = htole16(CHFS_NODETYPE_DIRENT);
186288addd0Sahoka 	fdirent->length = htole32(CHFS_PAD(size));
187288addd0Sahoka 	fdirent->hdr_crc = htole32(crc32(0, (uint8_t *)fdirent,
188288addd0Sahoka 		CHFS_NODE_HDR_SIZE - 4));
189288addd0Sahoka 	fdirent->vno = htole64(ino);
190288addd0Sahoka 	fdirent->pvno = htole64(pdir->ino);
191288addd0Sahoka 	fdirent->version = htole64(++pdir->chvc->highest_version);
192288addd0Sahoka 	fdirent->mctime = ip?ip->ctime:0;
193288addd0Sahoka 	fdirent->nsize = fd->nsize;
194288addd0Sahoka 	fdirent->dtype = fd->type;
195288addd0Sahoka 	fdirent->name_crc = crc32(0, (uint8_t *)&(fd->name), fd->nsize);
196288addd0Sahoka 	fdirent->node_crc = crc32(0, (uint8_t *)fdirent, sizeof(*fdirent) - 4);
197288addd0Sahoka 
198bca84b9eSttoth 	/* directory's name is written out right after the dirent */
199288addd0Sahoka 	vec[0].iov_base = fdirent;
200288addd0Sahoka 	vec[0].iov_len  = sizeof(*fdirent);
201288addd0Sahoka 	vec[1].iov_base = name;
202288addd0Sahoka 	vec[1].iov_len  = namelen;
203288addd0Sahoka 
204288addd0Sahoka retry:
205bca84b9eSttoth 	/* setting up the next eraseblock where we will write */
206288addd0Sahoka 	if (prio == ALLOC_GC) {
207288addd0Sahoka 		/* the GC calls this function */
208288addd0Sahoka 		err = chfs_reserve_space_gc(chmp, CHFS_PAD(size));
209288addd0Sahoka 		if (err)
210288addd0Sahoka 			goto out;
211288addd0Sahoka 	} else {
212288addd0Sahoka 		chfs_gc_trigger(chmp);
213288addd0Sahoka 		if (prio == ALLOC_NORMAL)
214288addd0Sahoka 			err = chfs_reserve_space_normal(chmp,
215288addd0Sahoka 			    CHFS_PAD(size), ALLOC_NORMAL);
216288addd0Sahoka 		else
217288addd0Sahoka 			err = chfs_reserve_space_normal(chmp,
218288addd0Sahoka 			    CHFS_PAD(size), ALLOC_DELETION);
219288addd0Sahoka 		if (err)
220288addd0Sahoka 			goto out;
221288addd0Sahoka 	}
222288addd0Sahoka 
223bca84b9eSttoth 	/* allocating a new node reference */
224288addd0Sahoka 	nref = chfs_alloc_node_ref(chmp->chm_nextblock);
225288addd0Sahoka 	if (!nref) {
226288addd0Sahoka 		err = ENOMEM;
227288addd0Sahoka 		goto out;
228288addd0Sahoka 	}
229288addd0Sahoka 
230288addd0Sahoka 	mutex_enter(&chmp->chm_lock_sizes);
231288addd0Sahoka 
232288addd0Sahoka 	nref->nref_offset = chmp->chm_ebh->eb_size - chmp->chm_nextblock->free_size;
233288addd0Sahoka 	chfs_change_size_free(chmp, chmp->chm_nextblock, -CHFS_PAD(size));
234288addd0Sahoka 
235bca84b9eSttoth 	/* write it into the writebuffer */
236288addd0Sahoka 	err = chfs_write_wbuf(chmp, vec, 2, nref->nref_offset, &retlen);
237288addd0Sahoka 	if (err || retlen != CHFS_PAD(size)) {
238bca84b9eSttoth 		/* there was an error during write */
239288addd0Sahoka 		chfs_err("error while writing out flash dirent node to the media\n");
240288addd0Sahoka 		chfs_err("err: %d | size: %zu | retlen : %zu\n",
241288addd0Sahoka 		    err, CHFS_PAD(size), retlen);
242288addd0Sahoka 		chfs_change_size_dirty(chmp,
243288addd0Sahoka 		    chmp->chm_nextblock, CHFS_PAD(size));
244288addd0Sahoka 		if (retries) {
245288addd0Sahoka 			err = EIO;
246288addd0Sahoka 			mutex_exit(&chmp->chm_lock_sizes);
247288addd0Sahoka 			goto out;
248288addd0Sahoka 		}
249288addd0Sahoka 
250bca84b9eSttoth 		/* try again */
251288addd0Sahoka 		retries++;
252288addd0Sahoka 		mutex_exit(&chmp->chm_lock_sizes);
253288addd0Sahoka 		goto retry;
254288addd0Sahoka 	}
255288addd0Sahoka 
256288addd0Sahoka 
257bca84b9eSttoth 	/* everything went well */
258288addd0Sahoka 	chfs_change_size_used(chmp,
259288addd0Sahoka 	    &chmp->chm_blocks[nref->nref_lnr], CHFS_PAD(size));
260288addd0Sahoka 	mutex_exit(&chmp->chm_lock_sizes);
261288addd0Sahoka 	KASSERT(chmp->chm_blocks[nref->nref_lnr].used_size <= chmp->chm_ebh->eb_size);
2623fae61eeSttoth 
263bca84b9eSttoth 	/* add the new nref to the directory chain of vnode cache */
264288addd0Sahoka 	fd->nref = nref;
265288addd0Sahoka 	if (prio != ALLOC_DELETION) {
2663fae61eeSttoth 		mutex_enter(&chmp->chm_lock_vnocache);
267288addd0Sahoka 		chfs_add_node_to_list(chmp,
268288addd0Sahoka 			pdir->chvc, nref, &pdir->chvc->dirents);
2693fae61eeSttoth 		mutex_exit(&chmp->chm_lock_vnocache);
270288addd0Sahoka 	}
271288addd0Sahoka out:
272288addd0Sahoka 	chfs_free_flash_dirent(fdirent);
273288addd0Sahoka 	return err;
274288addd0Sahoka }
275288addd0Sahoka 
276bca84b9eSttoth /* chfs_write_flash_dnode - writes out a data node to flash */
277288addd0Sahoka int
chfs_write_flash_dnode(struct chfs_mount * chmp,struct vnode * vp,struct buf * bp,struct chfs_full_dnode * fd)278288addd0Sahoka chfs_write_flash_dnode(struct chfs_mount *chmp, struct vnode *vp,
279288addd0Sahoka     struct buf *bp, struct chfs_full_dnode *fd)
280288addd0Sahoka {
281288addd0Sahoka 	KASSERT(mutex_owned(&chmp->chm_lock_mountfields));
282288addd0Sahoka 
283288addd0Sahoka 	int err = 0, retries = 0;
284288addd0Sahoka 	size_t size, retlen;
285288addd0Sahoka 	off_t ofs;
286288addd0Sahoka 	struct chfs_flash_data_node *dnode;
287288addd0Sahoka 	struct chfs_node_ref *nref;
288288addd0Sahoka 	struct chfs_inode *ip = VTOI(vp);
289288addd0Sahoka 	struct iovec vec[2];
290288addd0Sahoka 	uint32_t len;
291288addd0Sahoka 	void *tmpbuf = NULL;
292288addd0Sahoka 
293288addd0Sahoka 	KASSERT(ip->ino != CHFS_ROOTINO);
294288addd0Sahoka 
295288addd0Sahoka 	dnode = chfs_alloc_flash_dnode();
296288addd0Sahoka 	if (!dnode)
297288addd0Sahoka 		return ENOMEM;
298288addd0Sahoka 
299288addd0Sahoka 	/* initialize flash data node */
300288addd0Sahoka 	ofs = bp->b_blkno * PAGE_SIZE;
301288addd0Sahoka 	len = MIN((vp->v_size - ofs), bp->b_resid);
302288addd0Sahoka 	size = sizeof(*dnode) + len;
303288addd0Sahoka 
304288addd0Sahoka 	dnode->magic = htole16(CHFS_FS_MAGIC_BITMASK);
305288addd0Sahoka 	dnode->type = htole16(CHFS_NODETYPE_DATA);
306288addd0Sahoka 	dnode->length = htole32(CHFS_PAD(size));
307288addd0Sahoka 	dnode->hdr_crc = htole32(crc32(0, (uint8_t *)dnode,
308288addd0Sahoka 		CHFS_NODE_HDR_SIZE - 4));
309288addd0Sahoka 	dnode->vno = htole64(ip->ino);
310288addd0Sahoka 	dnode->version = htole64(++ip->chvc->highest_version);
311288addd0Sahoka 	dnode->offset = htole64(ofs);
312288addd0Sahoka 	dnode->data_length = htole32(len);
313288addd0Sahoka 	dnode->data_crc = htole32(crc32(0, (uint8_t *)bp->b_data, len));
314288addd0Sahoka 	dnode->node_crc = htole32(crc32(0, (uint8_t *)dnode,
315288addd0Sahoka 		sizeof(*dnode) - 4));
316288addd0Sahoka 
317f9d6d5cbSagc 	dbg("dnode @%llu %ub v%llu\n", (unsigned long long)dnode->offset,
318f9d6d5cbSagc 		dnode->data_length, (unsigned long long)dnode->version);
319288addd0Sahoka 
320bca84b9eSttoth 	/* pad data if needed */
321288addd0Sahoka 	if (CHFS_PAD(size) - sizeof(*dnode)) {
322288addd0Sahoka 		tmpbuf = kmem_zalloc(CHFS_PAD(size)
323288addd0Sahoka 		    - sizeof(*dnode), KM_SLEEP);
324288addd0Sahoka 		memcpy(tmpbuf, bp->b_data, len);
325288addd0Sahoka 	}
326288addd0Sahoka 
327bca84b9eSttoth 	/* creating iovecs for writebuffer
328bca84b9eSttoth 	 * data is written out right after the data node */
329288addd0Sahoka 	vec[0].iov_base = dnode;
330288addd0Sahoka 	vec[0].iov_len = sizeof(*dnode);
331288addd0Sahoka 	vec[1].iov_base = tmpbuf;
332288addd0Sahoka 	vec[1].iov_len = CHFS_PAD(size) - sizeof(*dnode);
333288addd0Sahoka 
334288addd0Sahoka 	fd->ofs = ofs;
335288addd0Sahoka 	fd->size = len;
336288addd0Sahoka 
337288addd0Sahoka retry:
338288addd0Sahoka 	/* Reserve space for data node. This will set up the next eraseblock
339288addd0Sahoka 	 * where to we will write.
340288addd0Sahoka 	 */
341288addd0Sahoka 	chfs_gc_trigger(chmp);
342288addd0Sahoka 	err = chfs_reserve_space_normal(chmp,
343288addd0Sahoka 	    CHFS_PAD(size), ALLOC_NORMAL);
344288addd0Sahoka 	if (err)
345288addd0Sahoka 		goto out;
346288addd0Sahoka 
347bca84b9eSttoth 	/* allocating a new node reference */
348288addd0Sahoka 	nref = chfs_alloc_node_ref(chmp->chm_nextblock);
349288addd0Sahoka 	if (!nref) {
350288addd0Sahoka 		err = ENOMEM;
351288addd0Sahoka 		goto out;
352288addd0Sahoka 	}
353288addd0Sahoka 
354288addd0Sahoka 	nref->nref_offset =
355288addd0Sahoka 	    chmp->chm_ebh->eb_size - chmp->chm_nextblock->free_size;
356288addd0Sahoka 
357288addd0Sahoka 	KASSERT(nref->nref_offset < chmp->chm_ebh->eb_size);
358288addd0Sahoka 
359288addd0Sahoka 	mutex_enter(&chmp->chm_lock_sizes);
360288addd0Sahoka 
361288addd0Sahoka 	chfs_change_size_free(chmp,
362288addd0Sahoka 	    chmp->chm_nextblock, -CHFS_PAD(size));
363288addd0Sahoka 
364bca84b9eSttoth 	/* write it into the writebuffer */
365288addd0Sahoka 	err = chfs_write_wbuf(chmp, vec, 2, nref->nref_offset, &retlen);
366288addd0Sahoka 	if (err || retlen != CHFS_PAD(size)) {
367bca84b9eSttoth 		/* there was an error during write */
368288addd0Sahoka 		chfs_err("error while writing out flash data node to the media\n");
369288addd0Sahoka 		chfs_err("err: %d | size: %zu | retlen : %zu\n",
370288addd0Sahoka 		    err, size, retlen);
371288addd0Sahoka 		chfs_change_size_dirty(chmp,
372288addd0Sahoka 		    chmp->chm_nextblock, CHFS_PAD(size));
373288addd0Sahoka 		if (retries) {
374288addd0Sahoka 			err = EIO;
375288addd0Sahoka 			mutex_exit(&chmp->chm_lock_sizes);
376288addd0Sahoka 			goto out;
377288addd0Sahoka 		}
378288addd0Sahoka 
379bca84b9eSttoth 		/* try again */
380288addd0Sahoka 		retries++;
381288addd0Sahoka 		mutex_exit(&chmp->chm_lock_sizes);
382288addd0Sahoka 		goto retry;
383288addd0Sahoka 	}
384bca84b9eSttoth 	/* everything went well */
385288addd0Sahoka 	ip->write_size += fd->size;
386288addd0Sahoka 	chfs_change_size_used(chmp,
387288addd0Sahoka 	    &chmp->chm_blocks[nref->nref_lnr], CHFS_PAD(size));
388288addd0Sahoka 	mutex_exit(&chmp->chm_lock_sizes);
389288addd0Sahoka 
3903fae61eeSttoth 	mutex_enter(&chmp->chm_lock_vnocache);
3913fae61eeSttoth 	if (fd->nref != NULL) {
3923fae61eeSttoth 		chfs_remove_frags_of_node(chmp, &ip->fragtree, fd->nref);
3933fae61eeSttoth 		chfs_remove_and_obsolete(chmp, ip->chvc, fd->nref, &ip->chvc->dnode);
3943fae61eeSttoth 	}
3953fae61eeSttoth 
396bca84b9eSttoth 	/* add the new nref to the data node chain of vnode cache */
397288addd0Sahoka 	KASSERT(chmp->chm_blocks[nref->nref_lnr].used_size <= chmp->chm_ebh->eb_size);
398288addd0Sahoka 	fd->nref = nref;
399288addd0Sahoka 	chfs_add_node_to_list(chmp, ip->chvc, nref, &ip->chvc->dnode);
4003fae61eeSttoth 	mutex_exit(&chmp->chm_lock_vnocache);
401288addd0Sahoka out:
402288addd0Sahoka 	chfs_free_flash_dnode(dnode);
403288addd0Sahoka 	if (CHFS_PAD(size) - sizeof(*dnode)) {
404288addd0Sahoka 		kmem_free(tmpbuf, CHFS_PAD(size) - sizeof(*dnode));
405288addd0Sahoka 	}
406288addd0Sahoka 
407288addd0Sahoka 	return err;
408288addd0Sahoka }
409288addd0Sahoka 
410bca84b9eSttoth /*
411288addd0Sahoka  * chfs_do_link - makes a copy from a node
412288addd0Sahoka  * This function writes the dirent of the new node to the media.
413288addd0Sahoka  */
414288addd0Sahoka int
chfs_do_link(struct chfs_inode * ip,struct chfs_inode * parent,const char * name,int namelen,enum chtype type)4154024b549Sttoth chfs_do_link(struct chfs_inode *ip, struct chfs_inode *parent, const char *name, int namelen, enum chtype type)
416288addd0Sahoka {
417288addd0Sahoka 	int error = 0;
418288addd0Sahoka 	struct vnode *vp = ITOV(ip);
419288addd0Sahoka 	struct ufsmount *ump = VFSTOUFS(vp->v_mount);
420288addd0Sahoka 	struct chfs_mount *chmp = ump->um_chfs;
421288addd0Sahoka 	struct chfs_dirent *newfd = NULL;
422288addd0Sahoka 
423bca84b9eSttoth 	/* setting up the new directory entry */
424288addd0Sahoka 	newfd = chfs_alloc_dirent(namelen + 1);
425288addd0Sahoka 
426288addd0Sahoka 	newfd->vno = ip->ino;
427288addd0Sahoka 	newfd->type = type;
428288addd0Sahoka 	newfd->nsize = namelen;
429288addd0Sahoka 	memcpy(newfd->name, name, namelen);
430288addd0Sahoka 	newfd->name[newfd->nsize] = 0;
431288addd0Sahoka 
432288addd0Sahoka 	ip->chvc->nlink++;
433288addd0Sahoka 	parent->chvc->nlink++;
434288addd0Sahoka 	ip->iflag |= IN_CHANGE;
435288addd0Sahoka 	chfs_update(vp, NULL, NULL, UPDATE_WAIT);
436288addd0Sahoka 
437288addd0Sahoka 	mutex_enter(&chmp->chm_lock_mountfields);
438288addd0Sahoka 
439bca84b9eSttoth 	/* update vnode information */
440288addd0Sahoka 	error = chfs_write_flash_vnode(chmp, ip, ALLOC_NORMAL);
4413aa54cacSandvar 	if (error) {
4423aa54cacSandvar 		mutex_exit(&chmp->chm_lock_mountfields);
443288addd0Sahoka 		return error;
4443aa54cacSandvar 	}
445288addd0Sahoka 
446bca84b9eSttoth 	/* write out the new dirent */
447288addd0Sahoka 	error = chfs_write_flash_dirent(chmp,
448288addd0Sahoka 	    parent, ip, newfd, ip->ino, ALLOC_NORMAL);
449288addd0Sahoka 	/* TODO: what should we do if error isn't zero? */
450288addd0Sahoka 
451288addd0Sahoka 	mutex_exit(&chmp->chm_lock_mountfields);
452288addd0Sahoka 
453288addd0Sahoka 	/* add fd to the fd list */
454288addd0Sahoka 	TAILQ_INSERT_TAIL(&parent->dents, newfd, fds);
455288addd0Sahoka 
456288addd0Sahoka 	return error;
457288addd0Sahoka }
458288addd0Sahoka 
459288addd0Sahoka 
460bca84b9eSttoth /*
461288addd0Sahoka  * chfs_do_unlink - delete a node
462bca84b9eSttoth  * This function set the nlink and vno of the node to zero and
463bca84b9eSttoth  * write its dirent to the media.
464288addd0Sahoka  */
465288addd0Sahoka int
chfs_do_unlink(struct chfs_inode * ip,struct chfs_inode * parent,const char * name,int namelen)466288addd0Sahoka chfs_do_unlink(struct chfs_inode *ip,
467288addd0Sahoka     struct chfs_inode *parent, const char *name, int namelen)
468288addd0Sahoka {
469288addd0Sahoka 	struct chfs_dirent *fd, *tmpfd;
470288addd0Sahoka 	int error = 0;
471288addd0Sahoka 	struct vnode *vp = ITOV(ip);
472288addd0Sahoka 	struct ufsmount *ump = VFSTOUFS(vp->v_mount);
473288addd0Sahoka 	struct chfs_mount *chmp = ump->um_chfs;
474288addd0Sahoka 	struct chfs_node_ref *nref;
475288addd0Sahoka 
476288addd0Sahoka 	vflushbuf(vp, 0);
477288addd0Sahoka 
478288addd0Sahoka 	mutex_enter(&chmp->chm_lock_mountfields);
479288addd0Sahoka 
480288addd0Sahoka 	/* remove the full direntry from the parent dents list */
481288addd0Sahoka 	TAILQ_FOREACH_SAFE(fd, &parent->dents, fds, tmpfd) {
482288addd0Sahoka 		if (fd->vno == ip->ino &&
483288addd0Sahoka 		    fd->nsize == namelen &&
484288addd0Sahoka 		    !memcmp(fd->name, name, fd->nsize)) {
4853fae61eeSttoth 
486bca84b9eSttoth 			/* remove every fragment of the file */
4873fae61eeSttoth 			chfs_kill_fragtree(chmp, &ip->fragtree);
4883fae61eeSttoth 
489bca84b9eSttoth 			/* decrease number of links to the file */
4904024b549Sttoth 			if (fd->type == CHT_DIR && ip->chvc->nlink == 2)
491288addd0Sahoka 				ip->chvc->nlink = 0;
492288addd0Sahoka 			else
493288addd0Sahoka 				ip->chvc->nlink--;
494288addd0Sahoka 
4954024b549Sttoth 			fd->type = CHT_BLANK;
496288addd0Sahoka 
497bca84b9eSttoth 			/* remove from parent's directory entries */
498288addd0Sahoka 			TAILQ_REMOVE(&parent->dents, fd, fds);
499288addd0Sahoka 
5003fae61eeSttoth 			mutex_enter(&chmp->chm_lock_vnocache);
501288addd0Sahoka 
5023fae61eeSttoth 			dbg("FD->NREF vno: %llu, lnr: %u, ofs: %u\n",
5033fae61eeSttoth 			    fd->vno, fd->nref->nref_lnr, fd->nref->nref_offset);
5043fae61eeSttoth 			chfs_remove_and_obsolete(chmp, parent->chvc, fd->nref,
5053fae61eeSttoth 				&parent->chvc->dirents);
506288addd0Sahoka 
507288addd0Sahoka 			error = chfs_write_flash_dirent(chmp,
508288addd0Sahoka 			    parent, ip, fd, 0, ALLOC_DELETION);
509288addd0Sahoka 
5103fae61eeSttoth 			dbg("FD->NREF vno: %llu, lnr: %u, ofs: %u\n",
5113fae61eeSttoth 			    fd->vno, fd->nref->nref_lnr, fd->nref->nref_offset);
512bca84b9eSttoth 			/* set nref_next field */
5133fae61eeSttoth 			chfs_add_node_to_list(chmp, parent->chvc, fd->nref,
5143fae61eeSttoth 				&parent->chvc->dirents);
515bca84b9eSttoth 			/* remove from the list */
5163fae61eeSttoth 			chfs_remove_and_obsolete(chmp, parent->chvc, fd->nref,
5173fae61eeSttoth 				&parent->chvc->dirents);
518288addd0Sahoka 
519bca84b9eSttoth 			/* clean dnode list */
5203fae61eeSttoth 			while (ip->chvc->dnode != (struct chfs_node_ref *)ip->chvc) {
521288addd0Sahoka 				nref = ip->chvc->dnode;
5223fae61eeSttoth 				chfs_remove_frags_of_node(chmp, &ip->fragtree, nref);
5233fae61eeSttoth 				chfs_remove_and_obsolete(chmp, ip->chvc, nref, &ip->chvc->dnode);
524288addd0Sahoka 			}
525288addd0Sahoka 
526bca84b9eSttoth 			/* clean vnode information (list) */
5273fae61eeSttoth 			while (ip->chvc->v != (struct chfs_node_ref *)ip->chvc) {
528288addd0Sahoka 				nref = ip->chvc->v;
5293fae61eeSttoth 				chfs_remove_and_obsolete(chmp, ip->chvc, nref, &ip->chvc->v);
530288addd0Sahoka 			}
531288addd0Sahoka 
532bca84b9eSttoth 			/* decrease number of links to parent */
533288addd0Sahoka 			parent->chvc->nlink--;
5343fae61eeSttoth 
5353fae61eeSttoth 			mutex_exit(&chmp->chm_lock_vnocache);
536288addd0Sahoka 			//TODO: if error
537288addd0Sahoka 		}
538288addd0Sahoka 	}
539288addd0Sahoka 	mutex_exit(&chmp->chm_lock_mountfields);
540288addd0Sahoka 
541288addd0Sahoka 	return error;
542288addd0Sahoka }
543