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