1 /* $NetBSD: chfs_write.c,v 1.2 2011/11/24 21:09:37 agc Exp $ */
4 * Copyright (c) 2010 Department of Software Engineering,
5 * University of Szeged, Hungary
6 * Copyright (C) 2010 David Tengeri <dtengeri@inf.u-szeged.hu>
7 * Copyright (C) 2010 Tamas Toth <ttoth@inf.u-szeged.hu>
8 * Copyright (C) 2010 Adam Hoka <ahoka@NetBSD.org>
11 * This code is derived from software contributed to The NetBSD Foundation
12 * by the Department of Software Engineering, University of Szeged, Hungary
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions
17 * 1. Redistributions of source code must retain the above copyright
18 * notice, this list of conditions and the following disclaimer.
19 * 2. Redistributions in binary form must reproduce the above copyright
20 * notice, this list of conditions and the following disclaimer in the
21 * documentation and/or other materials provided with the distribution.
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
30 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39 * Created on: 2010.02.17.
43 #include <sys/param.h>
49 chfs_write_flash_vnode(struct chfs_mount
*chmp
,
50 struct chfs_inode
*ip
, int prio
)
52 KASSERT(mutex_owned(&chmp
->chm_lock_mountfields
));
54 struct chfs_flash_vnode
*fvnode
;
55 struct chfs_vnode_cache
* chvc
;
56 struct chfs_node_ref
*nref
;
59 int err
= 0, retries
= 0;
61 if (ip
->ino
== CHFS_ROOTINO
)
64 fvnode
= chfs_alloc_flash_vnode();
70 /* setting up flash_vnode members */
71 size
= sizeof(*fvnode
);
72 //dbg("size: %zu | PADDED: %zu\n", size, CHFS_PAD(size));
73 fvnode
->magic
= htole16(CHFS_FS_MAGIC_BITMASK
);
74 fvnode
->type
= htole16(CHFS_NODETYPE_VNODE
);
75 fvnode
->length
= htole32(CHFS_PAD(size
));
76 fvnode
->hdr_crc
= htole32(crc32(0, (uint8_t *)fvnode
,
77 CHFS_NODE_HDR_SIZE
- 4));
78 fvnode
->vno
= htole64(ip
->ino
);
79 fvnode
->version
= htole64(++ip
->chvc
->highest_version
);
80 fvnode
->mode
= htole32(ip
->mode
);
81 fvnode
->dn_size
= htole32(ip
->size
);
82 fvnode
->atime
= htole32(ip
->atime
);
83 fvnode
->ctime
= htole32(ip
->ctime
);
84 fvnode
->mtime
= htole32(ip
->mtime
);
85 fvnode
->gid
= htole32(ip
->gid
);
86 fvnode
->uid
= htole32(ip
->uid
);
87 fvnode
->node_crc
= htole32(crc32(0, (uint8_t *)fvnode
, size
- 4));
89 /* write out flash_vnode */
91 if (prio
== ALLOC_GC
) {
92 /* the GC calls this function */
93 err
= chfs_reserve_space_gc(chmp
, CHFS_PAD(size
));
97 chfs_gc_trigger(chmp
);
98 if (prio
== ALLOC_NORMAL
)
99 err
= chfs_reserve_space_normal(chmp
,
100 CHFS_PAD(size
), ALLOC_NORMAL
);
102 err
= chfs_reserve_space_normal(chmp
,
103 CHFS_PAD(size
), ALLOC_DELETION
);
108 nref
= chfs_alloc_node_ref(chmp
->chm_nextblock
);
114 mutex_enter(&chmp
->chm_lock_sizes
);
116 nref
->nref_offset
= chmp
->chm_ebh
->eb_size
- chmp
->chm_nextblock
->free_size
;
117 chfs_change_size_free(chmp
, chmp
->chm_nextblock
, -CHFS_PAD(size
));
118 vec
.iov_base
= fvnode
;
119 vec
.iov_len
= CHFS_PAD(size
);
120 err
= chfs_write_wbuf(chmp
, &vec
, 1, nref
->nref_offset
, &retlen
);
121 if (err
|| retlen
!= CHFS_PAD(size
)) {
122 chfs_err("error while writing out flash vnode to the media\n");
123 chfs_err("err: %d | size: %zu | retlen : %zu\n",
124 err
, CHFS_PAD(size
), retlen
);
125 chfs_change_size_dirty(chmp
,
126 chmp
->chm_nextblock
, CHFS_PAD(size
));
129 mutex_exit(&chmp
->chm_lock_sizes
);
134 mutex_exit(&chmp
->chm_lock_sizes
);
137 //Everything went well
138 chfs_change_size_used(chmp
,
139 &chmp
->chm_blocks
[nref
->nref_lnr
], CHFS_PAD(size
));
140 mutex_exit(&chmp
->chm_lock_sizes
);
142 chfs_add_vnode_ref_to_vc(chmp
, chvc
, nref
);
143 KASSERT(chmp
->chm_blocks
[nref
->nref_lnr
].used_size
<= chmp
->chm_ebh
->eb_size
);
145 chfs_free_flash_vnode(fvnode
);
150 chfs_write_flash_dirent(struct chfs_mount
*chmp
, struct chfs_inode
*pdir
,
151 struct chfs_inode
*ip
, struct chfs_dirent
*fd
,
154 KASSERT(mutex_owned(&chmp
->chm_lock_mountfields
));
156 struct chfs_flash_dirent_node
*fdirent
;
157 struct chfs_node_ref
*nref
;
160 int err
= 0, retries
= 0;
164 KASSERT(fd
->vno
!= CHFS_ROOTINO
);
166 fdirent
= chfs_alloc_flash_dirent();
170 size
= sizeof(*fdirent
) + fd
->nsize
;
171 namelen
= CHFS_PAD(size
) - sizeof(*fdirent
);
173 name
= kmem_zalloc(namelen
, KM_SLEEP
);
174 memcpy(name
, fd
->name
, fd
->nsize
);
175 //dbg("namelen: %zu | nsize: %hhu\n", namelen, fd->nsize);
178 //dbg("size: %zu | PADDED: %zu\n", size, CHFS_PAD(size));
179 fdirent
->magic
= htole16(CHFS_FS_MAGIC_BITMASK
);
180 fdirent
->type
= htole16(CHFS_NODETYPE_DIRENT
);
181 fdirent
->length
= htole32(CHFS_PAD(size
));
182 fdirent
->hdr_crc
= htole32(crc32(0, (uint8_t *)fdirent
,
183 CHFS_NODE_HDR_SIZE
- 4));
184 fdirent
->vno
= htole64(ino
);
185 fdirent
->pvno
= htole64(pdir
->ino
);
186 fdirent
->version
= htole64(++pdir
->chvc
->highest_version
);
187 fdirent
->mctime
= ip
?ip
->ctime
:0;
188 fdirent
->nsize
= fd
->nsize
;
189 fdirent
->dtype
= fd
->type
;
190 fdirent
->name_crc
= crc32(0, (uint8_t *)&(fd
->name
), fd
->nsize
);
191 fdirent
->node_crc
= crc32(0, (uint8_t *)fdirent
, sizeof(*fdirent
) - 4);
193 vec
[0].iov_base
= fdirent
;
194 vec
[0].iov_len
= sizeof(*fdirent
);
195 vec
[1].iov_base
= name
;
196 vec
[1].iov_len
= namelen
;
199 if (prio
== ALLOC_GC
) {
200 /* the GC calls this function */
201 err
= chfs_reserve_space_gc(chmp
, CHFS_PAD(size
));
205 chfs_gc_trigger(chmp
);
206 if (prio
== ALLOC_NORMAL
)
207 err
= chfs_reserve_space_normal(chmp
,
208 CHFS_PAD(size
), ALLOC_NORMAL
);
210 err
= chfs_reserve_space_normal(chmp
,
211 CHFS_PAD(size
), ALLOC_DELETION
);
216 nref
= chfs_alloc_node_ref(chmp
->chm_nextblock
);
222 mutex_enter(&chmp
->chm_lock_sizes
);
224 nref
->nref_offset
= chmp
->chm_ebh
->eb_size
- chmp
->chm_nextblock
->free_size
;
225 chfs_change_size_free(chmp
, chmp
->chm_nextblock
, -CHFS_PAD(size
));
227 err
= chfs_write_wbuf(chmp
, vec
, 2, nref
->nref_offset
, &retlen
);
228 if (err
|| retlen
!= CHFS_PAD(size
)) {
229 chfs_err("error while writing out flash dirent node to the media\n");
230 chfs_err("err: %d | size: %zu | retlen : %zu\n",
231 err
, CHFS_PAD(size
), retlen
);
232 chfs_change_size_dirty(chmp
,
233 chmp
->chm_nextblock
, CHFS_PAD(size
));
236 mutex_exit(&chmp
->chm_lock_sizes
);
241 mutex_exit(&chmp
->chm_lock_sizes
);
246 // Everything went well
247 chfs_change_size_used(chmp
,
248 &chmp
->chm_blocks
[nref
->nref_lnr
], CHFS_PAD(size
));
249 mutex_exit(&chmp
->chm_lock_sizes
);
250 KASSERT(chmp
->chm_blocks
[nref
->nref_lnr
].used_size
<= chmp
->chm_ebh
->eb_size
);
252 if (prio
!= ALLOC_DELETION
) {
253 chfs_add_node_to_list(chmp
,
254 pdir
->chvc
, nref
, &pdir
->chvc
->dirents
);
257 chfs_free_flash_dirent(fdirent
);
262 * chfs_write_flash_dnode - write out a data node to flash
263 * @chmp: chfs mount structure
264 * @vp: vnode where the data belongs to
265 * @bp: buffer contains data
268 chfs_write_flash_dnode(struct chfs_mount
*chmp
, struct vnode
*vp
,
269 struct buf
*bp
, struct chfs_full_dnode
*fd
)
271 KASSERT(mutex_owned(&chmp
->chm_lock_mountfields
));
273 int err
= 0, retries
= 0;
276 struct chfs_flash_data_node
*dnode
;
277 struct chfs_node_ref
*nref
;
278 struct chfs_inode
*ip
= VTOI(vp
);
283 KASSERT(ip
->ino
!= CHFS_ROOTINO
);
285 dnode
= chfs_alloc_flash_dnode();
289 /* initialize flash data node */
290 ofs
= bp
->b_blkno
* PAGE_SIZE
;
291 //dbg("vp->v_size: %ju, bp->b_blkno: %ju, bp-b_data: %p,"
292 // " bp->b_resid: %ju\n",
293 // (uintmax_t )vp->v_size, (uintmax_t )bp->b_blkno,
294 // bp->b_data, (uintmax_t )bp->b_resid);
295 //dbg("[XXX]vp->v_size - ofs: %llu\n", (vp->v_size - ofs));
296 len
= MIN((vp
->v_size
- ofs
), bp
->b_resid
);
297 size
= sizeof(*dnode
) + len
;
299 dnode
->magic
= htole16(CHFS_FS_MAGIC_BITMASK
);
300 dnode
->type
= htole16(CHFS_NODETYPE_DATA
);
301 dnode
->length
= htole32(CHFS_PAD(size
));
302 dnode
->hdr_crc
= htole32(crc32(0, (uint8_t *)dnode
,
303 CHFS_NODE_HDR_SIZE
- 4));
304 dnode
->vno
= htole64(ip
->ino
);
305 dnode
->version
= htole64(++ip
->chvc
->highest_version
);
306 dnode
->offset
= htole64(ofs
);
307 dnode
->data_length
= htole32(len
);
308 dnode
->data_crc
= htole32(crc32(0, (uint8_t *)bp
->b_data
, len
));
309 dnode
->node_crc
= htole32(crc32(0, (uint8_t *)dnode
,
310 sizeof(*dnode
) - 4));
312 dbg("dnode @%llu %ub v%llu\n", (unsigned long long)dnode
->offset
,
313 dnode
->data_length
, (unsigned long long)dnode
->version
);
315 if (CHFS_PAD(size
) - sizeof(*dnode
)) {
316 tmpbuf
= kmem_zalloc(CHFS_PAD(size
)
317 - sizeof(*dnode
), KM_SLEEP
);
318 memcpy(tmpbuf
, bp
->b_data
, len
);
321 /* creating iovecs for wbuf */
322 vec
[0].iov_base
= dnode
;
323 vec
[0].iov_len
= sizeof(*dnode
);
324 vec
[1].iov_base
= tmpbuf
;
325 vec
[1].iov_len
= CHFS_PAD(size
) - sizeof(*dnode
);
333 /* Reserve space for data node. This will set up the next eraseblock
334 * where to we will write.
337 chfs_gc_trigger(chmp
);
338 err
= chfs_reserve_space_normal(chmp
,
339 CHFS_PAD(size
), ALLOC_NORMAL
);
343 nref
= chfs_alloc_node_ref(chmp
->chm_nextblock
);
350 chmp
->chm_ebh
->eb_size
- chmp
->chm_nextblock
->free_size
;
352 KASSERT(nref
->nref_offset
< chmp
->chm_ebh
->eb_size
);
354 mutex_enter(&chmp
->chm_lock_sizes
);
356 chfs_change_size_free(chmp
,
357 chmp
->chm_nextblock
, -CHFS_PAD(size
));
359 //dbg("vno: %llu nref lnr: %u offset: %u\n",
360 // dnode->vno, nref->nref_lnr, nref->nref_offset);
362 err
= chfs_write_wbuf(chmp
, vec
, 2, nref
->nref_offset
, &retlen
);
363 if (err
|| retlen
!= CHFS_PAD(size
)) {
364 chfs_err("error while writing out flash data node to the media\n");
365 chfs_err("err: %d | size: %zu | retlen : %zu\n",
367 chfs_change_size_dirty(chmp
,
368 chmp
->chm_nextblock
, CHFS_PAD(size
));
371 mutex_exit(&chmp
->chm_lock_sizes
);
376 mutex_exit(&chmp
->chm_lock_sizes
);
379 /* Everything went well */
380 ip
->write_size
+= fd
->size
;
381 chfs_change_size_used(chmp
,
382 &chmp
->chm_blocks
[nref
->nref_lnr
], CHFS_PAD(size
));
383 mutex_exit(&chmp
->chm_lock_sizes
);
385 KASSERT(chmp
->chm_blocks
[nref
->nref_lnr
].used_size
<= chmp
->chm_ebh
->eb_size
);
387 chfs_add_node_to_list(chmp
, ip
->chvc
, nref
, &ip
->chvc
->dnode
);
389 chfs_free_flash_dnode(dnode
);
390 if (CHFS_PAD(size
) - sizeof(*dnode
)) {
391 kmem_free(tmpbuf
, CHFS_PAD(size
) - sizeof(*dnode
));
398 * chfs_do_link - makes a copy from a node
400 * @oldfd: dirent of old node
401 * @parent: parent of new node
402 * @name: name of new node
403 * @namelen: length of name
404 * This function writes the dirent of the new node to the media.
407 chfs_do_link(struct chfs_inode
*ip
, struct chfs_inode
*parent
, const char *name
, int namelen
, enum vtype type
)
410 struct vnode
*vp
= ITOV(ip
);
411 struct ufsmount
*ump
= VFSTOUFS(vp
->v_mount
);
412 struct chfs_mount
*chmp
= ump
->um_chfs
;
413 struct chfs_dirent
*newfd
= NULL
;
414 // struct chfs_dirent *fd = NULL;
416 //dbg("link vno: %llu\n", ip->ino);
418 newfd
= chfs_alloc_dirent(namelen
+ 1);
420 newfd
->vno
= ip
->ino
;
422 newfd
->nsize
= namelen
;
423 memcpy(newfd
->name
, name
, namelen
);
424 newfd
->name
[newfd
->nsize
] = 0;
425 // newfd->next = NULL;
428 parent
->chvc
->nlink
++;
429 ip
->iflag
|= IN_CHANGE
;
430 chfs_update(vp
, NULL
, NULL
, UPDATE_WAIT
);
432 mutex_enter(&chmp
->chm_lock_mountfields
);
434 error
= chfs_write_flash_vnode(chmp
, ip
, ALLOC_NORMAL
);
438 error
= chfs_write_flash_dirent(chmp
,
439 parent
, ip
, newfd
, ip
->ino
, ALLOC_NORMAL
);
440 /* TODO: what should we do if error isn't zero? */
442 mutex_exit(&chmp
->chm_lock_mountfields
);
444 /* add fd to the fd list */
445 TAILQ_INSERT_TAIL(&parent
->dents
, newfd
, fds
);
449 parent
->dents
= newfd
;
462 * chfs_do_unlink - delete a node
463 * @ip: node what we'd like to delete
464 * @parent: parent of the node
465 * @name: name of the node
466 * @namelen: length of name
467 * This function set the nlink and vno of the node zero and write its dirent to the media.
470 chfs_do_unlink(struct chfs_inode
*ip
,
471 struct chfs_inode
*parent
, const char *name
, int namelen
)
473 struct chfs_dirent
*fd
, *tmpfd
;
475 struct vnode
*vp
= ITOV(ip
);
476 struct ufsmount
*ump
= VFSTOUFS(vp
->v_mount
);
477 struct chfs_mount
*chmp
= ump
->um_chfs
;
478 struct chfs_node_ref
*nref
;
480 //dbg("unlink vno: %llu\n", ip->ino);
484 mutex_enter(&chmp
->chm_lock_mountfields
);
486 /* remove the full direntry from the parent dents list */
487 TAILQ_FOREACH_SAFE(fd
, &parent
->dents
, fds
, tmpfd
) {
488 if (fd
->vno
== ip
->ino
&&
489 fd
->nsize
== namelen
&&
490 !memcmp(fd
->name
, name
, fd
->nsize
)) {
491 if (fd
->type
== VDIR
&& ip
->chvc
->nlink
== 2)
498 TAILQ_REMOVE(&parent
->dents
, fd
, fds
);
500 /* remove nref from dirents list */
501 nref
= parent
->chvc
->dirents
;
502 if (nref
== fd
->nref
) {
503 nref
->nref_next
= fd
->nref
->nref_next
;
505 while (nref
->nref_next
&& nref
->nref_next
!= fd
->nref
)
506 nref
= nref
->nref_next
;
508 nref
->nref_next
= fd
->nref
->nref_next
;
511 //dbg("FD->NREF vno: %llu, lnr: %u, ofs: %u\n",
512 // fd->vno, fd->nref->nref_lnr, fd->nref->nref_offset);
513 chfs_mark_node_obsolete(chmp
, fd
->nref
);
515 error
= chfs_write_flash_dirent(chmp
,
516 parent
, ip
, fd
, 0, ALLOC_DELETION
);
518 //dbg("FD->NREF vno: %llu, lnr: %u, ofs: %u\n",
519 // fd->vno, fd->nref->nref_lnr, fd->nref->nref_offset);
520 chfs_mark_node_obsolete(chmp
, fd
->nref
);
522 nref
= ip
->chvc
->dnode
;
523 while (nref
!= (struct chfs_node_ref
*)ip
->chvc
) {
524 //dbg("DATA NREF\n");
525 chfs_mark_node_obsolete(chmp
, nref
);
526 nref
= nref
->nref_next
;
528 ip
->chvc
->dnode
= (struct chfs_node_ref
*)ip
->chvc
;
531 while (nref
!= (struct chfs_node_ref
*)ip
->chvc
) {
533 chfs_mark_node_obsolete(chmp
, nref
);
534 nref
= nref
->nref_next
;
536 ip
->chvc
->v
= ip
->chvc
->v
->nref_next
;
538 parent
->chvc
->nlink
--;
542 mutex_exit(&chmp
->chm_lock_mountfields
);