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