xref: /netbsd/sys/ufs/chfs/chfs_write.c (revision 98907fc3)
1*98907fc3Sandvar /*	$NetBSD: chfs_write.c,v 1.7 2021/12/07 21:37:37 andvar Exp $	*/
2060d2ed9Sahoka 
3060d2ed9Sahoka /*-
4060d2ed9Sahoka  * Copyright (c) 2010 Department of Software Engineering,
5060d2ed9Sahoka  *		      University of Szeged, Hungary
6060d2ed9Sahoka  * Copyright (C) 2010 David Tengeri <dtengeri@inf.u-szeged.hu>
7060d2ed9Sahoka  * Copyright (C) 2010 Tamas Toth <ttoth@inf.u-szeged.hu>
8060d2ed9Sahoka  * Copyright (C) 2010 Adam Hoka <ahoka@NetBSD.org>
9060d2ed9Sahoka  * All rights reserved.
10060d2ed9Sahoka  *
11060d2ed9Sahoka  * This code is derived from software contributed to The NetBSD Foundation
12060d2ed9Sahoka  * by the Department of Software Engineering, University of Szeged, Hungary
13060d2ed9Sahoka  *
14060d2ed9Sahoka  * Redistribution and use in source and binary forms, with or without
15060d2ed9Sahoka  * modification, are permitted provided that the following conditions
16060d2ed9Sahoka  * are met:
17060d2ed9Sahoka  * 1. Redistributions of source code must retain the above copyright
18060d2ed9Sahoka  *    notice, this list of conditions and the following disclaimer.
19060d2ed9Sahoka  * 2. Redistributions in binary form must reproduce the above copyright
20060d2ed9Sahoka  *    notice, this list of conditions and the following disclaimer in the
21060d2ed9Sahoka  *    documentation and/or other materials provided with the distribution.
22060d2ed9Sahoka  *
23060d2ed9Sahoka  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24060d2ed9Sahoka  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25060d2ed9Sahoka  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26060d2ed9Sahoka  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27060d2ed9Sahoka  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28060d2ed9Sahoka  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29060d2ed9Sahoka  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
30060d2ed9Sahoka  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31060d2ed9Sahoka  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32060d2ed9Sahoka  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33060d2ed9Sahoka  * SUCH DAMAGE.
34060d2ed9Sahoka  */
35060d2ed9Sahoka 
36060d2ed9Sahoka 
37060d2ed9Sahoka #include <sys/param.h>
38060d2ed9Sahoka #include <sys/buf.h>
39060d2ed9Sahoka 
40060d2ed9Sahoka #include "chfs.h"
41060d2ed9Sahoka 
42aa98cbbaSttoth 
43aa98cbbaSttoth /* chfs_write_flash_vnode - writes out a vnode information to flash */
44060d2ed9Sahoka int
chfs_write_flash_vnode(struct chfs_mount * chmp,struct chfs_inode * ip,int prio)45060d2ed9Sahoka chfs_write_flash_vnode(struct chfs_mount *chmp,
46060d2ed9Sahoka     struct chfs_inode *ip, int prio)
47060d2ed9Sahoka {
48060d2ed9Sahoka 	KASSERT(mutex_owned(&chmp->chm_lock_mountfields));
49060d2ed9Sahoka 
50060d2ed9Sahoka 	struct chfs_flash_vnode *fvnode;
51060d2ed9Sahoka 	struct chfs_vnode_cache* chvc;
52060d2ed9Sahoka 	struct chfs_node_ref *nref;
53060d2ed9Sahoka 	struct iovec vec;
54060d2ed9Sahoka 	size_t size, retlen;
55060d2ed9Sahoka 	int err = 0, retries = 0;
56060d2ed9Sahoka 
57aa98cbbaSttoth 	/* root vnode is in-memory only */
58060d2ed9Sahoka 	if (ip->ino == CHFS_ROOTINO)
59060d2ed9Sahoka 		return 0;
60060d2ed9Sahoka 
61060d2ed9Sahoka 	fvnode = chfs_alloc_flash_vnode();
62060d2ed9Sahoka 	if (!fvnode)
63060d2ed9Sahoka 		return ENOMEM;
64060d2ed9Sahoka 
65060d2ed9Sahoka 	chvc = ip->chvc;
66060d2ed9Sahoka 
67aa98cbbaSttoth 	/* setting up flash_vnode's fields */
68060d2ed9Sahoka 	size = sizeof(*fvnode);
69060d2ed9Sahoka 	fvnode->magic = htole16(CHFS_FS_MAGIC_BITMASK);
70060d2ed9Sahoka 	fvnode->type = htole16(CHFS_NODETYPE_VNODE);
71060d2ed9Sahoka 	fvnode->length = htole32(CHFS_PAD(size));
72060d2ed9Sahoka 	fvnode->hdr_crc = htole32(crc32(0, (uint8_t *)fvnode,
73060d2ed9Sahoka 		CHFS_NODE_HDR_SIZE - 4));
74060d2ed9Sahoka 	fvnode->vno = htole64(ip->ino);
75060d2ed9Sahoka 	fvnode->version = htole64(++ip->chvc->highest_version);
76060d2ed9Sahoka 	fvnode->mode = htole32(ip->mode);
77060d2ed9Sahoka 	fvnode->dn_size = htole32(ip->size);
78060d2ed9Sahoka 	fvnode->atime = htole32(ip->atime);
79060d2ed9Sahoka 	fvnode->ctime = htole32(ip->ctime);
80060d2ed9Sahoka 	fvnode->mtime = htole32(ip->mtime);
81060d2ed9Sahoka 	fvnode->gid = htole32(ip->gid);
82060d2ed9Sahoka 	fvnode->uid = htole32(ip->uid);
83060d2ed9Sahoka 	fvnode->node_crc = htole32(crc32(0, (uint8_t *)fvnode, size - 4));
84060d2ed9Sahoka 
85060d2ed9Sahoka retry:
86aa98cbbaSttoth 	/* setting up the next eraseblock where we will write */
87060d2ed9Sahoka 	if (prio == ALLOC_GC) {
88aa98cbbaSttoth 		/* GC called this function */
89060d2ed9Sahoka 		err = chfs_reserve_space_gc(chmp, CHFS_PAD(size));
90060d2ed9Sahoka 		if (err)
91060d2ed9Sahoka 			goto out;
92060d2ed9Sahoka 	} else {
93060d2ed9Sahoka 		chfs_gc_trigger(chmp);
94060d2ed9Sahoka 		if (prio == ALLOC_NORMAL)
95060d2ed9Sahoka 			err = chfs_reserve_space_normal(chmp,
96060d2ed9Sahoka 			    CHFS_PAD(size), ALLOC_NORMAL);
97060d2ed9Sahoka 		else
98060d2ed9Sahoka 			err = chfs_reserve_space_normal(chmp,
99060d2ed9Sahoka 			    CHFS_PAD(size), ALLOC_DELETION);
100060d2ed9Sahoka 		if (err)
101060d2ed9Sahoka 			goto out;
102060d2ed9Sahoka 	}
103060d2ed9Sahoka 
104aa98cbbaSttoth 	/* allocating a new node reference */
105060d2ed9Sahoka 	nref = chfs_alloc_node_ref(chmp->chm_nextblock);
106060d2ed9Sahoka 	if (!nref) {
107060d2ed9Sahoka 		err = ENOMEM;
108060d2ed9Sahoka 		goto out;
109060d2ed9Sahoka 	}
110060d2ed9Sahoka 
111060d2ed9Sahoka 	mutex_enter(&chmp->chm_lock_sizes);
112060d2ed9Sahoka 
113*98907fc3Sandvar 	/* calculating offset and sizes  */
114060d2ed9Sahoka 	nref->nref_offset = chmp->chm_ebh->eb_size - chmp->chm_nextblock->free_size;
115060d2ed9Sahoka 	chfs_change_size_free(chmp, chmp->chm_nextblock, -CHFS_PAD(size));
116060d2ed9Sahoka 	vec.iov_base = fvnode;
117060d2ed9Sahoka 	vec.iov_len = CHFS_PAD(size);
118aa98cbbaSttoth 
119aa98cbbaSttoth 	/* write it into the writebuffer */
120060d2ed9Sahoka 	err = chfs_write_wbuf(chmp, &vec, 1, nref->nref_offset, &retlen);
121060d2ed9Sahoka 	if (err || retlen != CHFS_PAD(size)) {
122aa98cbbaSttoth 		/* there was an error during write */
123060d2ed9Sahoka 		chfs_err("error while writing out flash vnode to the media\n");
124060d2ed9Sahoka 		chfs_err("err: %d | size: %zu | retlen : %zu\n",
125060d2ed9Sahoka 		    err, CHFS_PAD(size), retlen);
126060d2ed9Sahoka 		chfs_change_size_dirty(chmp,
127060d2ed9Sahoka 		    chmp->chm_nextblock, CHFS_PAD(size));
128060d2ed9Sahoka 		if (retries) {
129060d2ed9Sahoka 			err = EIO;
130060d2ed9Sahoka 			mutex_exit(&chmp->chm_lock_sizes);
131060d2ed9Sahoka 			goto out;
132060d2ed9Sahoka 		}
133060d2ed9Sahoka 
134aa98cbbaSttoth 		/* try again */
135060d2ed9Sahoka 		retries++;
136060d2ed9Sahoka 		mutex_exit(&chmp->chm_lock_sizes);
137060d2ed9Sahoka 		goto retry;
138060d2ed9Sahoka 	}
139aa98cbbaSttoth 
140aa98cbbaSttoth 	/* everything went well */
141060d2ed9Sahoka 	chfs_change_size_used(chmp,
142060d2ed9Sahoka 	    &chmp->chm_blocks[nref->nref_lnr], CHFS_PAD(size));
143060d2ed9Sahoka 	mutex_exit(&chmp->chm_lock_sizes);
144060d2ed9Sahoka 
145aa98cbbaSttoth 	/* add the new nref to vnode cache */
1467982b4ffSttoth 	mutex_enter(&chmp->chm_lock_vnocache);
147060d2ed9Sahoka 	chfs_add_vnode_ref_to_vc(chmp, chvc, nref);
1487982b4ffSttoth 	mutex_exit(&chmp->chm_lock_vnocache);
149060d2ed9Sahoka 	KASSERT(chmp->chm_blocks[nref->nref_lnr].used_size <= chmp->chm_ebh->eb_size);
150060d2ed9Sahoka out:
151060d2ed9Sahoka 	chfs_free_flash_vnode(fvnode);
152060d2ed9Sahoka 	return err;
153060d2ed9Sahoka }
154060d2ed9Sahoka 
155aa98cbbaSttoth /* chfs_write_flash_dirent - writes out a directory entry to flash */
156060d2ed9Sahoka 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)157060d2ed9Sahoka chfs_write_flash_dirent(struct chfs_mount *chmp, struct chfs_inode *pdir,
158060d2ed9Sahoka     struct chfs_inode *ip, struct chfs_dirent *fd,
159060d2ed9Sahoka     ino_t ino, int prio)
160060d2ed9Sahoka {
161060d2ed9Sahoka 	KASSERT(mutex_owned(&chmp->chm_lock_mountfields));
162060d2ed9Sahoka 
163060d2ed9Sahoka 	struct chfs_flash_dirent_node *fdirent;
164060d2ed9Sahoka 	struct chfs_node_ref *nref;
165060d2ed9Sahoka 	struct iovec vec[2];
166060d2ed9Sahoka 	size_t size, retlen;
167060d2ed9Sahoka 	int err = 0, retries = 0;
168060d2ed9Sahoka 	uint8_t *name;
169060d2ed9Sahoka 	size_t namelen;
170060d2ed9Sahoka 
171060d2ed9Sahoka 	KASSERT(fd->vno != CHFS_ROOTINO);
172060d2ed9Sahoka 
173aa98cbbaSttoth 	/* setting up flash_dirent's fields */
174060d2ed9Sahoka 	fdirent = chfs_alloc_flash_dirent();
175060d2ed9Sahoka 	if (!fdirent)
176060d2ed9Sahoka 		return ENOMEM;
177060d2ed9Sahoka 
178060d2ed9Sahoka 	size = sizeof(*fdirent) + fd->nsize;
179060d2ed9Sahoka 	namelen = CHFS_PAD(size) - sizeof(*fdirent);
180060d2ed9Sahoka 
181060d2ed9Sahoka 	name = kmem_zalloc(namelen, KM_SLEEP);
182060d2ed9Sahoka 	memcpy(name, fd->name, fd->nsize);
183060d2ed9Sahoka 
184060d2ed9Sahoka 	fdirent->magic = htole16(CHFS_FS_MAGIC_BITMASK);
185060d2ed9Sahoka 	fdirent->type = htole16(CHFS_NODETYPE_DIRENT);
186060d2ed9Sahoka 	fdirent->length = htole32(CHFS_PAD(size));
187060d2ed9Sahoka 	fdirent->hdr_crc = htole32(crc32(0, (uint8_t *)fdirent,
188060d2ed9Sahoka 		CHFS_NODE_HDR_SIZE - 4));
189060d2ed9Sahoka 	fdirent->vno = htole64(ino);
190060d2ed9Sahoka 	fdirent->pvno = htole64(pdir->ino);
191060d2ed9Sahoka 	fdirent->version = htole64(++pdir->chvc->highest_version);
192060d2ed9Sahoka 	fdirent->mctime = ip?ip->ctime:0;
193060d2ed9Sahoka 	fdirent->nsize = fd->nsize;
194060d2ed9Sahoka 	fdirent->dtype = fd->type;
195060d2ed9Sahoka 	fdirent->name_crc = crc32(0, (uint8_t *)&(fd->name), fd->nsize);
196060d2ed9Sahoka 	fdirent->node_crc = crc32(0, (uint8_t *)fdirent, sizeof(*fdirent) - 4);
197060d2ed9Sahoka 
198aa98cbbaSttoth 	/* directory's name is written out right after the dirent */
199060d2ed9Sahoka 	vec[0].iov_base = fdirent;
200060d2ed9Sahoka 	vec[0].iov_len  = sizeof(*fdirent);
201060d2ed9Sahoka 	vec[1].iov_base = name;
202060d2ed9Sahoka 	vec[1].iov_len  = namelen;
203060d2ed9Sahoka 
204060d2ed9Sahoka retry:
205aa98cbbaSttoth 	/* setting up the next eraseblock where we will write */
206060d2ed9Sahoka 	if (prio == ALLOC_GC) {
207060d2ed9Sahoka 		/* the GC calls this function */
208060d2ed9Sahoka 		err = chfs_reserve_space_gc(chmp, CHFS_PAD(size));
209060d2ed9Sahoka 		if (err)
210060d2ed9Sahoka 			goto out;
211060d2ed9Sahoka 	} else {
212060d2ed9Sahoka 		chfs_gc_trigger(chmp);
213060d2ed9Sahoka 		if (prio == ALLOC_NORMAL)
214060d2ed9Sahoka 			err = chfs_reserve_space_normal(chmp,
215060d2ed9Sahoka 			    CHFS_PAD(size), ALLOC_NORMAL);
216060d2ed9Sahoka 		else
217060d2ed9Sahoka 			err = chfs_reserve_space_normal(chmp,
218060d2ed9Sahoka 			    CHFS_PAD(size), ALLOC_DELETION);
219060d2ed9Sahoka 		if (err)
220060d2ed9Sahoka 			goto out;
221060d2ed9Sahoka 	}
222060d2ed9Sahoka 
223aa98cbbaSttoth 	/* allocating a new node reference */
224060d2ed9Sahoka 	nref = chfs_alloc_node_ref(chmp->chm_nextblock);
225060d2ed9Sahoka 	if (!nref) {
226060d2ed9Sahoka 		err = ENOMEM;
227060d2ed9Sahoka 		goto out;
228060d2ed9Sahoka 	}
229060d2ed9Sahoka 
230060d2ed9Sahoka 	mutex_enter(&chmp->chm_lock_sizes);
231060d2ed9Sahoka 
232060d2ed9Sahoka 	nref->nref_offset = chmp->chm_ebh->eb_size - chmp->chm_nextblock->free_size;
233060d2ed9Sahoka 	chfs_change_size_free(chmp, chmp->chm_nextblock, -CHFS_PAD(size));
234060d2ed9Sahoka 
235aa98cbbaSttoth 	/* write it into the writebuffer */
236060d2ed9Sahoka 	err = chfs_write_wbuf(chmp, vec, 2, nref->nref_offset, &retlen);
237060d2ed9Sahoka 	if (err || retlen != CHFS_PAD(size)) {
238aa98cbbaSttoth 		/* there was an error during write */
239060d2ed9Sahoka 		chfs_err("error while writing out flash dirent node to the media\n");
240060d2ed9Sahoka 		chfs_err("err: %d | size: %zu | retlen : %zu\n",
241060d2ed9Sahoka 		    err, CHFS_PAD(size), retlen);
242060d2ed9Sahoka 		chfs_change_size_dirty(chmp,
243060d2ed9Sahoka 		    chmp->chm_nextblock, CHFS_PAD(size));
244060d2ed9Sahoka 		if (retries) {
245060d2ed9Sahoka 			err = EIO;
246060d2ed9Sahoka 			mutex_exit(&chmp->chm_lock_sizes);
247060d2ed9Sahoka 			goto out;
248060d2ed9Sahoka 		}
249060d2ed9Sahoka 
250aa98cbbaSttoth 		/* try again */
251060d2ed9Sahoka 		retries++;
252060d2ed9Sahoka 		mutex_exit(&chmp->chm_lock_sizes);
253060d2ed9Sahoka 		goto retry;
254060d2ed9Sahoka 	}
255060d2ed9Sahoka 
256060d2ed9Sahoka 
257aa98cbbaSttoth 	/* everything went well */
258060d2ed9Sahoka 	chfs_change_size_used(chmp,
259060d2ed9Sahoka 	    &chmp->chm_blocks[nref->nref_lnr], CHFS_PAD(size));
260060d2ed9Sahoka 	mutex_exit(&chmp->chm_lock_sizes);
261060d2ed9Sahoka 	KASSERT(chmp->chm_blocks[nref->nref_lnr].used_size <= chmp->chm_ebh->eb_size);
2627982b4ffSttoth 
263aa98cbbaSttoth 	/* add the new nref to the directory chain of vnode cache */
264060d2ed9Sahoka 	fd->nref = nref;
265060d2ed9Sahoka 	if (prio != ALLOC_DELETION) {
2667982b4ffSttoth 		mutex_enter(&chmp->chm_lock_vnocache);
267060d2ed9Sahoka 		chfs_add_node_to_list(chmp,
268060d2ed9Sahoka 			pdir->chvc, nref, &pdir->chvc->dirents);
2697982b4ffSttoth 		mutex_exit(&chmp->chm_lock_vnocache);
270060d2ed9Sahoka 	}
271060d2ed9Sahoka out:
272060d2ed9Sahoka 	chfs_free_flash_dirent(fdirent);
273060d2ed9Sahoka 	return err;
274060d2ed9Sahoka }
275060d2ed9Sahoka 
276aa98cbbaSttoth /* chfs_write_flash_dnode - writes out a data node to flash */
277060d2ed9Sahoka int
chfs_write_flash_dnode(struct chfs_mount * chmp,struct vnode * vp,struct buf * bp,struct chfs_full_dnode * fd)278060d2ed9Sahoka chfs_write_flash_dnode(struct chfs_mount *chmp, struct vnode *vp,
279060d2ed9Sahoka     struct buf *bp, struct chfs_full_dnode *fd)
280060d2ed9Sahoka {
281060d2ed9Sahoka 	KASSERT(mutex_owned(&chmp->chm_lock_mountfields));
282060d2ed9Sahoka 
283060d2ed9Sahoka 	int err = 0, retries = 0;
284060d2ed9Sahoka 	size_t size, retlen;
285060d2ed9Sahoka 	off_t ofs;
286060d2ed9Sahoka 	struct chfs_flash_data_node *dnode;
287060d2ed9Sahoka 	struct chfs_node_ref *nref;
288060d2ed9Sahoka 	struct chfs_inode *ip = VTOI(vp);
289060d2ed9Sahoka 	struct iovec vec[2];
290060d2ed9Sahoka 	uint32_t len;
291060d2ed9Sahoka 	void *tmpbuf = NULL;
292060d2ed9Sahoka 
293060d2ed9Sahoka 	KASSERT(ip->ino != CHFS_ROOTINO);
294060d2ed9Sahoka 
295060d2ed9Sahoka 	dnode = chfs_alloc_flash_dnode();
296060d2ed9Sahoka 	if (!dnode)
297060d2ed9Sahoka 		return ENOMEM;
298060d2ed9Sahoka 
299060d2ed9Sahoka 	/* initialize flash data node */
300060d2ed9Sahoka 	ofs = bp->b_blkno * PAGE_SIZE;
301060d2ed9Sahoka 	len = MIN((vp->v_size - ofs), bp->b_resid);
302060d2ed9Sahoka 	size = sizeof(*dnode) + len;
303060d2ed9Sahoka 
304060d2ed9Sahoka 	dnode->magic = htole16(CHFS_FS_MAGIC_BITMASK);
305060d2ed9Sahoka 	dnode->type = htole16(CHFS_NODETYPE_DATA);
306060d2ed9Sahoka 	dnode->length = htole32(CHFS_PAD(size));
307060d2ed9Sahoka 	dnode->hdr_crc = htole32(crc32(0, (uint8_t *)dnode,
308060d2ed9Sahoka 		CHFS_NODE_HDR_SIZE - 4));
309060d2ed9Sahoka 	dnode->vno = htole64(ip->ino);
310060d2ed9Sahoka 	dnode->version = htole64(++ip->chvc->highest_version);
311060d2ed9Sahoka 	dnode->offset = htole64(ofs);
312060d2ed9Sahoka 	dnode->data_length = htole32(len);
313060d2ed9Sahoka 	dnode->data_crc = htole32(crc32(0, (uint8_t *)bp->b_data, len));
314060d2ed9Sahoka 	dnode->node_crc = htole32(crc32(0, (uint8_t *)dnode,
315060d2ed9Sahoka 		sizeof(*dnode) - 4));
316060d2ed9Sahoka 
31791acea70Sagc 	dbg("dnode @%llu %ub v%llu\n", (unsigned long long)dnode->offset,
31891acea70Sagc 		dnode->data_length, (unsigned long long)dnode->version);
319060d2ed9Sahoka 
320aa98cbbaSttoth 	/* pad data if needed */
321060d2ed9Sahoka 	if (CHFS_PAD(size) - sizeof(*dnode)) {
322060d2ed9Sahoka 		tmpbuf = kmem_zalloc(CHFS_PAD(size)
323060d2ed9Sahoka 		    - sizeof(*dnode), KM_SLEEP);
324060d2ed9Sahoka 		memcpy(tmpbuf, bp->b_data, len);
325060d2ed9Sahoka 	}
326060d2ed9Sahoka 
327aa98cbbaSttoth 	/* creating iovecs for writebuffer
328aa98cbbaSttoth 	 * data is written out right after the data node */
329060d2ed9Sahoka 	vec[0].iov_base = dnode;
330060d2ed9Sahoka 	vec[0].iov_len = sizeof(*dnode);
331060d2ed9Sahoka 	vec[1].iov_base = tmpbuf;
332060d2ed9Sahoka 	vec[1].iov_len = CHFS_PAD(size) - sizeof(*dnode);
333060d2ed9Sahoka 
334060d2ed9Sahoka 	fd->ofs = ofs;
335060d2ed9Sahoka 	fd->size = len;
336060d2ed9Sahoka 
337060d2ed9Sahoka retry:
338060d2ed9Sahoka 	/* Reserve space for data node. This will set up the next eraseblock
339060d2ed9Sahoka 	 * where to we will write.
340060d2ed9Sahoka 	 */
341060d2ed9Sahoka 	chfs_gc_trigger(chmp);
342060d2ed9Sahoka 	err = chfs_reserve_space_normal(chmp,
343060d2ed9Sahoka 	    CHFS_PAD(size), ALLOC_NORMAL);
344060d2ed9Sahoka 	if (err)
345060d2ed9Sahoka 		goto out;
346060d2ed9Sahoka 
347aa98cbbaSttoth 	/* allocating a new node reference */
348060d2ed9Sahoka 	nref = chfs_alloc_node_ref(chmp->chm_nextblock);
349060d2ed9Sahoka 	if (!nref) {
350060d2ed9Sahoka 		err = ENOMEM;
351060d2ed9Sahoka 		goto out;
352060d2ed9Sahoka 	}
353060d2ed9Sahoka 
354060d2ed9Sahoka 	nref->nref_offset =
355060d2ed9Sahoka 	    chmp->chm_ebh->eb_size - chmp->chm_nextblock->free_size;
356060d2ed9Sahoka 
357060d2ed9Sahoka 	KASSERT(nref->nref_offset < chmp->chm_ebh->eb_size);
358060d2ed9Sahoka 
359060d2ed9Sahoka 	mutex_enter(&chmp->chm_lock_sizes);
360060d2ed9Sahoka 
361060d2ed9Sahoka 	chfs_change_size_free(chmp,
362060d2ed9Sahoka 	    chmp->chm_nextblock, -CHFS_PAD(size));
363060d2ed9Sahoka 
364aa98cbbaSttoth 	/* write it into the writebuffer */
365060d2ed9Sahoka 	err = chfs_write_wbuf(chmp, vec, 2, nref->nref_offset, &retlen);
366060d2ed9Sahoka 	if (err || retlen != CHFS_PAD(size)) {
367aa98cbbaSttoth 		/* there was an error during write */
368060d2ed9Sahoka 		chfs_err("error while writing out flash data node to the media\n");
369060d2ed9Sahoka 		chfs_err("err: %d | size: %zu | retlen : %zu\n",
370060d2ed9Sahoka 		    err, size, retlen);
371060d2ed9Sahoka 		chfs_change_size_dirty(chmp,
372060d2ed9Sahoka 		    chmp->chm_nextblock, CHFS_PAD(size));
373060d2ed9Sahoka 		if (retries) {
374060d2ed9Sahoka 			err = EIO;
375060d2ed9Sahoka 			mutex_exit(&chmp->chm_lock_sizes);
376060d2ed9Sahoka 			goto out;
377060d2ed9Sahoka 		}
378060d2ed9Sahoka 
379aa98cbbaSttoth 		/* try again */
380060d2ed9Sahoka 		retries++;
381060d2ed9Sahoka 		mutex_exit(&chmp->chm_lock_sizes);
382060d2ed9Sahoka 		goto retry;
383060d2ed9Sahoka 	}
384aa98cbbaSttoth 	/* everything went well */
385060d2ed9Sahoka 	ip->write_size += fd->size;
386060d2ed9Sahoka 	chfs_change_size_used(chmp,
387060d2ed9Sahoka 	    &chmp->chm_blocks[nref->nref_lnr], CHFS_PAD(size));
388060d2ed9Sahoka 	mutex_exit(&chmp->chm_lock_sizes);
389060d2ed9Sahoka 
3907982b4ffSttoth 	mutex_enter(&chmp->chm_lock_vnocache);
3917982b4ffSttoth 	if (fd->nref != NULL) {
3927982b4ffSttoth 		chfs_remove_frags_of_node(chmp, &ip->fragtree, fd->nref);
3937982b4ffSttoth 		chfs_remove_and_obsolete(chmp, ip->chvc, fd->nref, &ip->chvc->dnode);
3947982b4ffSttoth 	}
3957982b4ffSttoth 
396aa98cbbaSttoth 	/* add the new nref to the data node chain of vnode cache */
397060d2ed9Sahoka 	KASSERT(chmp->chm_blocks[nref->nref_lnr].used_size <= chmp->chm_ebh->eb_size);
398060d2ed9Sahoka 	fd->nref = nref;
399060d2ed9Sahoka 	chfs_add_node_to_list(chmp, ip->chvc, nref, &ip->chvc->dnode);
4007982b4ffSttoth 	mutex_exit(&chmp->chm_lock_vnocache);
401060d2ed9Sahoka out:
402060d2ed9Sahoka 	chfs_free_flash_dnode(dnode);
403060d2ed9Sahoka 	if (CHFS_PAD(size) - sizeof(*dnode)) {
404060d2ed9Sahoka 		kmem_free(tmpbuf, CHFS_PAD(size) - sizeof(*dnode));
405060d2ed9Sahoka 	}
406060d2ed9Sahoka 
407060d2ed9Sahoka 	return err;
408060d2ed9Sahoka }
409060d2ed9Sahoka 
410aa98cbbaSttoth /*
411060d2ed9Sahoka  * chfs_do_link - makes a copy from a node
412060d2ed9Sahoka  * This function writes the dirent of the new node to the media.
413060d2ed9Sahoka  */
414060d2ed9Sahoka int
chfs_do_link(struct chfs_inode * ip,struct chfs_inode * parent,const char * name,int namelen,enum chtype type)415e6a23d44Sttoth chfs_do_link(struct chfs_inode *ip, struct chfs_inode *parent, const char *name, int namelen, enum chtype type)
416060d2ed9Sahoka {
417060d2ed9Sahoka 	int error = 0;
418060d2ed9Sahoka 	struct vnode *vp = ITOV(ip);
419060d2ed9Sahoka 	struct ufsmount *ump = VFSTOUFS(vp->v_mount);
420060d2ed9Sahoka 	struct chfs_mount *chmp = ump->um_chfs;
421060d2ed9Sahoka 	struct chfs_dirent *newfd = NULL;
422060d2ed9Sahoka 
423aa98cbbaSttoth 	/* setting up the new directory entry */
424060d2ed9Sahoka 	newfd = chfs_alloc_dirent(namelen + 1);
425060d2ed9Sahoka 
426060d2ed9Sahoka 	newfd->vno = ip->ino;
427060d2ed9Sahoka 	newfd->type = type;
428060d2ed9Sahoka 	newfd->nsize = namelen;
429060d2ed9Sahoka 	memcpy(newfd->name, name, namelen);
430060d2ed9Sahoka 	newfd->name[newfd->nsize] = 0;
431060d2ed9Sahoka 
432060d2ed9Sahoka 	ip->chvc->nlink++;
433060d2ed9Sahoka 	parent->chvc->nlink++;
434060d2ed9Sahoka 	ip->iflag |= IN_CHANGE;
435060d2ed9Sahoka 	chfs_update(vp, NULL, NULL, UPDATE_WAIT);
436060d2ed9Sahoka 
437060d2ed9Sahoka 	mutex_enter(&chmp->chm_lock_mountfields);
438060d2ed9Sahoka 
439aa98cbbaSttoth 	/* update vnode information */
440060d2ed9Sahoka 	error = chfs_write_flash_vnode(chmp, ip, ALLOC_NORMAL);
441a9b5b353Sandvar 	if (error) {
442a9b5b353Sandvar 		mutex_exit(&chmp->chm_lock_mountfields);
443060d2ed9Sahoka 		return error;
444a9b5b353Sandvar 	}
445060d2ed9Sahoka 
446aa98cbbaSttoth 	/* write out the new dirent */
447060d2ed9Sahoka 	error = chfs_write_flash_dirent(chmp,
448060d2ed9Sahoka 	    parent, ip, newfd, ip->ino, ALLOC_NORMAL);
449060d2ed9Sahoka 	/* TODO: what should we do if error isn't zero? */
450060d2ed9Sahoka 
451060d2ed9Sahoka 	mutex_exit(&chmp->chm_lock_mountfields);
452060d2ed9Sahoka 
453060d2ed9Sahoka 	/* add fd to the fd list */
454060d2ed9Sahoka 	TAILQ_INSERT_TAIL(&parent->dents, newfd, fds);
455060d2ed9Sahoka 
456060d2ed9Sahoka 	return error;
457060d2ed9Sahoka }
458060d2ed9Sahoka 
459060d2ed9Sahoka 
460aa98cbbaSttoth /*
461060d2ed9Sahoka  * chfs_do_unlink - delete a node
462aa98cbbaSttoth  * This function set the nlink and vno of the node to zero and
463aa98cbbaSttoth  * write its dirent to the media.
464060d2ed9Sahoka  */
465060d2ed9Sahoka int
chfs_do_unlink(struct chfs_inode * ip,struct chfs_inode * parent,const char * name,int namelen)466060d2ed9Sahoka chfs_do_unlink(struct chfs_inode *ip,
467060d2ed9Sahoka     struct chfs_inode *parent, const char *name, int namelen)
468060d2ed9Sahoka {
469060d2ed9Sahoka 	struct chfs_dirent *fd, *tmpfd;
470060d2ed9Sahoka 	int error = 0;
471060d2ed9Sahoka 	struct vnode *vp = ITOV(ip);
472060d2ed9Sahoka 	struct ufsmount *ump = VFSTOUFS(vp->v_mount);
473060d2ed9Sahoka 	struct chfs_mount *chmp = ump->um_chfs;
474060d2ed9Sahoka 	struct chfs_node_ref *nref;
475060d2ed9Sahoka 
476060d2ed9Sahoka 	vflushbuf(vp, 0);
477060d2ed9Sahoka 
478060d2ed9Sahoka 	mutex_enter(&chmp->chm_lock_mountfields);
479060d2ed9Sahoka 
480060d2ed9Sahoka 	/* remove the full direntry from the parent dents list */
481060d2ed9Sahoka 	TAILQ_FOREACH_SAFE(fd, &parent->dents, fds, tmpfd) {
482060d2ed9Sahoka 		if (fd->vno == ip->ino &&
483060d2ed9Sahoka 		    fd->nsize == namelen &&
484060d2ed9Sahoka 		    !memcmp(fd->name, name, fd->nsize)) {
4857982b4ffSttoth 
486aa98cbbaSttoth 			/* remove every fragment of the file */
4877982b4ffSttoth 			chfs_kill_fragtree(chmp, &ip->fragtree);
4887982b4ffSttoth 
489aa98cbbaSttoth 			/* decrease number of links to the file */
490e6a23d44Sttoth 			if (fd->type == CHT_DIR && ip->chvc->nlink == 2)
491060d2ed9Sahoka 				ip->chvc->nlink = 0;
492060d2ed9Sahoka 			else
493060d2ed9Sahoka 				ip->chvc->nlink--;
494060d2ed9Sahoka 
495e6a23d44Sttoth 			fd->type = CHT_BLANK;
496060d2ed9Sahoka 
497aa98cbbaSttoth 			/* remove from parent's directory entries */
498060d2ed9Sahoka 			TAILQ_REMOVE(&parent->dents, fd, fds);
499060d2ed9Sahoka 
5007982b4ffSttoth 			mutex_enter(&chmp->chm_lock_vnocache);
501060d2ed9Sahoka 
5027982b4ffSttoth 			dbg("FD->NREF vno: %llu, lnr: %u, ofs: %u\n",
5037982b4ffSttoth 			    fd->vno, fd->nref->nref_lnr, fd->nref->nref_offset);
5047982b4ffSttoth 			chfs_remove_and_obsolete(chmp, parent->chvc, fd->nref,
5057982b4ffSttoth 				&parent->chvc->dirents);
506060d2ed9Sahoka 
507060d2ed9Sahoka 			error = chfs_write_flash_dirent(chmp,
508060d2ed9Sahoka 			    parent, ip, fd, 0, ALLOC_DELETION);
509060d2ed9Sahoka 
5107982b4ffSttoth 			dbg("FD->NREF vno: %llu, lnr: %u, ofs: %u\n",
5117982b4ffSttoth 			    fd->vno, fd->nref->nref_lnr, fd->nref->nref_offset);
512aa98cbbaSttoth 			/* set nref_next field */
5137982b4ffSttoth 			chfs_add_node_to_list(chmp, parent->chvc, fd->nref,
5147982b4ffSttoth 				&parent->chvc->dirents);
515aa98cbbaSttoth 			/* remove from the list */
5167982b4ffSttoth 			chfs_remove_and_obsolete(chmp, parent->chvc, fd->nref,
5177982b4ffSttoth 				&parent->chvc->dirents);
518060d2ed9Sahoka 
519aa98cbbaSttoth 			/* clean dnode list */
5207982b4ffSttoth 			while (ip->chvc->dnode != (struct chfs_node_ref *)ip->chvc) {
521060d2ed9Sahoka 				nref = ip->chvc->dnode;
5227982b4ffSttoth 				chfs_remove_frags_of_node(chmp, &ip->fragtree, nref);
5237982b4ffSttoth 				chfs_remove_and_obsolete(chmp, ip->chvc, nref, &ip->chvc->dnode);
524060d2ed9Sahoka 			}
525060d2ed9Sahoka 
526aa98cbbaSttoth 			/* clean vnode information (list) */
5277982b4ffSttoth 			while (ip->chvc->v != (struct chfs_node_ref *)ip->chvc) {
528060d2ed9Sahoka 				nref = ip->chvc->v;
5297982b4ffSttoth 				chfs_remove_and_obsolete(chmp, ip->chvc, nref, &ip->chvc->v);
530060d2ed9Sahoka 			}
531060d2ed9Sahoka 
532aa98cbbaSttoth 			/* decrease number of links to parent */
533060d2ed9Sahoka 			parent->chvc->nlink--;
5347982b4ffSttoth 
5357982b4ffSttoth 			mutex_exit(&chmp->chm_lock_vnocache);
536060d2ed9Sahoka 			//TODO: if error
537060d2ed9Sahoka 		}
538060d2ed9Sahoka 	}
539060d2ed9Sahoka 	mutex_exit(&chmp->chm_lock_mountfields);
540060d2ed9Sahoka 
541060d2ed9Sahoka 	return error;
542060d2ed9Sahoka }
543