1 /* $NetBSD: chfs_gc.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 Tamas Toth <ttoth@inf.u-szeged.hu>
7 * Copyright (c) 2010 Adam Hoka <ahoka@NetBSD.org>
10 * This code is derived from software contributed to The NetBSD Foundation
11 * by the Department of Software Engineering, University of Szeged, Hungary
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 void chfs_gc_release_inode(struct chfs_mount
*,
39 struct chfs_inode
*chfs_gc_fetch_inode(struct chfs_mount
*,
41 int chfs_check(struct chfs_mount
*, struct chfs_vnode_cache
*);
42 void chfs_clear_inode(struct chfs_mount
*, struct chfs_inode
*);
45 struct chfs_eraseblock
*find_gc_block(struct chfs_mount
*);
46 int chfs_gcollect_pristine(struct chfs_mount
*,
47 struct chfs_eraseblock
*,
48 struct chfs_vnode_cache
*, struct chfs_node_ref
*);
49 int chfs_gcollect_live(struct chfs_mount
*,
50 struct chfs_eraseblock
*, struct chfs_node_ref
*,
52 int chfs_gcollect_vnode(struct chfs_mount
*, struct chfs_inode
*);
53 int chfs_gcollect_dirent(struct chfs_mount
*,
54 struct chfs_eraseblock
*, struct chfs_inode
*,
55 struct chfs_dirent
*);
56 int chfs_gcollect_deletion_dirent(struct chfs_mount
*,
57 struct chfs_eraseblock
*, struct chfs_inode
*,
58 struct chfs_dirent
*);
59 int chfs_gcollect_dnode(struct chfs_mount
*,
60 struct chfs_eraseblock
*, struct chfs_inode
*,
61 struct chfs_full_dnode
*, uint32_t, uint32_t);
63 /* must be called with chm_lock_mountfields held */
65 chfs_gc_trigger(struct chfs_mount
*chmp
)
67 struct garbage_collector_thread
*gc
= &chmp
->chm_gc_thread
;
69 //mutex_enter(&chmp->chm_lock_sizes);
70 if (gc
->gcth_running
&&
71 chfs_gc_thread_should_wake(chmp
)) {
72 cv_signal(&gc
->gcth_wakeup
);
74 //mutex_exit(&chmp->chm_lock_sizes);
79 chfs_gc_thread(void *data
)
81 struct chfs_mount
*chmp
= data
;
82 struct garbage_collector_thread
*gc
= &chmp
->chm_gc_thread
;
84 dbg_gc("[GC THREAD] thread started\n");
86 mutex_enter(&chmp
->chm_lock_mountfields
);
87 while (gc
->gcth_running
) {
88 /* we must call chfs_gc_thread_should_wake with chm_lock_mountfields
89 * held, which is a bit awkwardly done here, but we cant relly
90 * do it otherway with the current design...
92 if (chfs_gc_thread_should_wake(chmp
)) {
93 // mutex_exit(&chmp->chm_lock_mountfields);
94 if (chfs_gcollect_pass(chmp
) == ENOSPC
) {
95 dbg_gc("No space for garbage collection\n");
96 panic("No space for garbage collection\n");
97 /* XXX why break here? i have added a panic
98 * here to see if it gets triggered -ahoka
102 /* XXX gcollect_pass drops the mutex */
103 mutex_enter(&chmp
->chm_lock_mountfields
);
106 cv_timedwait_sig(&gc
->gcth_wakeup
,
107 &chmp
->chm_lock_mountfields
, mstohz(100));
109 mutex_exit(&chmp
->chm_lock_mountfields
);
111 dbg_gc("[GC THREAD] thread stopped\n");
116 chfs_gc_thread_start(struct chfs_mount
*chmp
)
118 struct garbage_collector_thread
*gc
= &chmp
->chm_gc_thread
;
120 cv_init(&gc
->gcth_wakeup
, "chfsgccv");
122 gc
->gcth_running
= true;
123 kthread_create(PRI_NONE
, /*KTHREAD_MPSAFE |*/ KTHREAD_MUSTJOIN
,
124 NULL
, chfs_gc_thread
, chmp
, &gc
->gcth_thread
,
129 chfs_gc_thread_stop(struct chfs_mount
*chmp
)
131 struct garbage_collector_thread
*gc
= &chmp
->chm_gc_thread
;
133 /* check if it is actually running. if not, do nothing */
134 if (gc
->gcth_running
) {
135 gc
->gcth_running
= false;
139 cv_signal(&gc
->gcth_wakeup
);
140 dbg_gc("[GC THREAD] stop signal sent\n");
142 kthread_join(gc
->gcth_thread
);
143 #ifdef BROKEN_KTH_JOIN
144 kpause("chfsthjoin", false, mstohz(1000), NULL
);
147 cv_destroy(&gc
->gcth_wakeup
);
150 /* must be called with chm_lock_mountfields held */
152 chfs_gc_thread_should_wake(struct chfs_mount
*chmp
)
154 int nr_very_dirty
= 0;
155 struct chfs_eraseblock
*cheb
;
158 KASSERT(mutex_owned(&chmp
->chm_lock_mountfields
));
160 if (!TAILQ_EMPTY(&chmp
->chm_erase_pending_queue
)) {
161 dbg_gc("erase_pending\n");
165 if (chmp
->chm_unchecked_size
) {
166 dbg_gc("unchecked\n");
170 dirty
= chmp
->chm_dirty_size
- chmp
->chm_nr_erasable_blocks
*
171 chmp
->chm_ebh
->eb_size
;
173 if (chmp
->chm_nr_free_blocks
+ chmp
->chm_nr_erasable_blocks
<
174 chmp
->chm_resv_blocks_gctrigger
&& (dirty
> chmp
->chm_nospc_dirty
)) {
175 dbg_gc("free: %d + erasable: %d < resv: %d\n",
176 chmp
->chm_nr_free_blocks
, chmp
->chm_nr_erasable_blocks
,
177 chmp
->chm_resv_blocks_gctrigger
);
178 dbg_gc("dirty: %d > nospc_dirty: %d\n",
179 dirty
, chmp
->chm_nospc_dirty
);
184 TAILQ_FOREACH(cheb
, &chmp
->chm_very_dirty_queue
, queue
) {
186 if (nr_very_dirty
== chmp
->chm_vdirty_blocks_gctrigger
) {
187 dbg_gc("nr_very_dirty\n");
196 chfs_gc_release_inode(struct chfs_mount
*chmp
,
197 struct chfs_inode
*ip
)
199 dbg_gc("release inode\n");
200 //mutex_exit(&ip->inode_lock);
205 chfs_gc_fetch_inode(struct chfs_mount
*chmp
, ino_t vno
,
208 struct vnode
*vp
= NULL
;
209 struct chfs_vnode_cache
*vc
;
210 struct chfs_inode
*ip
;
211 dbg_gc("fetch inode %llu\n", (unsigned long long)vno
);
214 dbg_gc("unlinked\n");
215 vp
= chfs_vnode_lookup(chmp
, vno
);
217 mutex_enter(&chmp
->chm_lock_vnocache
);
218 vc
= chfs_vnode_cache_get(chmp
, vno
);
220 mutex_exit(&chmp
->chm_lock_vnocache
);
223 if (vc
->state
!= VNO_STATE_CHECKEDABSENT
) {
224 //sleep_on_spinunlock(&chmp->chm_lock_vnocache);
225 mutex_exit(&chmp
->chm_lock_vnocache
);
226 /* XXX why do we need the delay here?! */
227 // kpause("chvncabs", true, mstohz(50), NULL);
228 KASSERT(mutex_owned(&chmp
->chm_lock_mountfields
));
230 &chmp
->chm_gc_thread
.gcth_wakeup
,
231 &chmp
->chm_lock_mountfields
, mstohz(50));
233 // KASSERT(!mutex_owned(&chmp->chm_lock_vnocache));
235 mutex_exit(&chmp
->chm_lock_vnocache
);
240 dbg_gc("vnode lookup\n");
241 vp
= chfs_vnode_lookup(chmp
, vno
);
242 //VFS_VGET(chmp->chm_fsmp, vno, &vp);
244 dbg_gc("vp to ip\n");
247 //mutex_enter(&ip->inode_lock);
252 extern rb_tree_ops_t frag_rbtree_ops
;
255 chfs_check(struct chfs_mount
*chmp
, struct chfs_vnode_cache
*chvc
)
257 struct chfs_inode
*ip
;
261 ip
= pool_get(&chfs_inode_pool
, PR_WAITOK
);
266 vp
= kmem_zalloc(sizeof(struct vnode
), KM_SLEEP
);
273 rb_tree_init(&ip
->fragtree
, &frag_rbtree_ops
);
274 TAILQ_INIT(&ip
->dents
);
276 ret
= chfs_read_inode_internal(chmp
, ip
);
278 chfs_clear_inode(chmp
, ip
);
281 pool_put(&chfs_inode_pool
, ip
);
287 chfs_clear_inode(struct chfs_mount
*chmp
, struct chfs_inode
*ip
)
289 struct chfs_dirent
*fd
, *tmpfd
;
290 struct chfs_vnode_cache
*chvc
;
293 /* XXX not sure if this is the correct locking */
294 // mutex_enter(&chmp->chm_lock_vnocache);
296 /* shouldnt this be: */
297 //bool deleted = (chvc && !(chvc->pvno || chvc->nlink));
298 int deleted
= (chvc
&& !(chvc
->pvno
| chvc
->nlink
));
300 if (chvc
&& chvc
->state
!= VNO_STATE_CHECKING
) {
301 // chfs_vnode_cache_state_set(chmp, chvc, VNO_STATE_CLEARING);
302 chvc
->state
= VNO_STATE_CLEARING
;
305 if (chvc
->v
&& ((struct chfs_vnode_cache
*)chvc
->v
!= chvc
)) {
307 chfs_mark_node_obsolete(chmp
, chvc
->v
);
308 //chfs_free_refblock(chvc->v);
310 // mutex_enter(&chmp->chm_lock_vnocache);
312 chfs_kill_fragtree(&ip
->fragtree
);
314 fd = TAILQ_FIRST(&ip->dents);
316 TAILQ_REMOVE(&ip->dents, fd, fds);
317 chfs_free_dirent(fd);
318 fd = TAILQ_FIRST(&ip->dents);
322 TAILQ_FOREACH_SAFE(fd
, &ip
->dents
, fds
, tmpfd
) {
323 chfs_free_dirent(fd
);
326 if (chvc
&& chvc
->state
== VNO_STATE_CHECKING
) {
327 chfs_vnode_cache_set_state(chmp
,
328 chvc
, VNO_STATE_CHECKEDABSENT
);
329 if ((struct chfs_vnode_cache
*)chvc
->v
== chvc
&&
330 (struct chfs_vnode_cache
*)chvc
->dirents
== chvc
&&
331 (struct chfs_vnode_cache
*)chvc
->dnode
== chvc
)
332 chfs_vnode_cache_remove(chmp
, chvc
);
337 struct chfs_eraseblock
*
338 find_gc_block(struct chfs_mount
*chmp
)
340 struct chfs_eraseblock
*ret
;
341 struct chfs_eraseblock_queue
*nextqueue
;
343 KASSERT(mutex_owned(&chmp
->chm_lock_mountfields
));
348 int n
= now
.tv_nsec
% 128;
350 //dbg_gc("n = %d\n", n);
352 /* if (!TAILQ_EMPTY(&chmp->chm_bad_used_queue) && chmp->chm_nr_free_blocks > chmp->chm_nr_resv_blocks_gcbad) {
353 dbg_gc("Picking block from bad_used_queue to GC next\n");
354 nextqueue = &chmp->chm_bad_used_queue;
355 } else */if (n
<50 && !TAILQ_EMPTY(&chmp
->chm_erase_pending_queue
)) {
356 dbg_gc("Picking block from erase_pending_queue to GC next\n");
357 nextqueue
= &chmp
->chm_erase_pending_queue
;
358 } else if (n
<110 && !TAILQ_EMPTY(&chmp
->chm_very_dirty_queue
) ) {
359 dbg_gc("Picking block from very_dirty_queue to GC next\n");
360 nextqueue
= &chmp
->chm_very_dirty_queue
;
361 } else if (n
<126 && !TAILQ_EMPTY(&chmp
->chm_dirty_queue
) ) {
362 dbg_gc("Picking block from dirty_queue to GC next\n");
363 nextqueue
= &chmp
->chm_dirty_queue
;
364 } else if (!TAILQ_EMPTY(&chmp
->chm_clean_queue
)) {
365 dbg_gc("Picking block from clean_queue to GC next\n");
366 nextqueue
= &chmp
->chm_clean_queue
;
367 } else if (!TAILQ_EMPTY(&chmp
->chm_dirty_queue
)) {
368 dbg_gc("Picking block from dirty_queue to GC next"
369 " (clean_queue was empty)\n");
370 nextqueue
= &chmp
->chm_dirty_queue
;
371 } else if (!TAILQ_EMPTY(&chmp
->chm_very_dirty_queue
)) {
372 dbg_gc("Picking block from very_dirty_queue to GC next"
373 " (clean_queue and dirty_queue were empty)\n");
374 nextqueue
= &chmp
->chm_very_dirty_queue
;
375 } else if (!TAILQ_EMPTY(&chmp
->chm_erase_pending_queue
)) {
376 dbg_gc("Picking block from erase_pending_queue to GC next"
377 " (clean_queue and {very_,}dirty_queue were empty)\n");
378 nextqueue
= &chmp
->chm_erase_pending_queue
;
379 } else if (!TAILQ_EMPTY(&chmp
->chm_erasable_pending_wbuf_queue
)) {
380 dbg_gc("Synching wbuf in order to reuse "
381 "erasable_pendig_wbuf_queue blocks\n");
382 rw_enter(&chmp
->chm_lock_wbuf
, RW_WRITER
);
383 chfs_flush_pending_wbuf(chmp
);
384 rw_exit(&chmp
->chm_lock_wbuf
);
387 dbg_gc("CHFS: no clean, dirty _or_ erasable"
388 " blocks to GC from! Where are they all?\n");
392 ret
= TAILQ_FIRST(nextqueue
);
393 if (chmp
->chm_nextblock
) {
394 dbg_gc("nextblock num: %u - gcblock num: %u\n",
395 chmp
->chm_nextblock
->lnr
, ret
->lnr
);
396 if (ret
== chmp
->chm_nextblock
)
398 //KASSERT(ret != chmp->chm_nextblock);
399 //dbg_gc("first node lnr: %u ofs: %u\n", ret->first_node->lnr, ret->first_node->offset);
400 //dbg_gc("last node lnr: %u ofs: %u\n", ret->last_node->lnr, ret->last_node->offset);
402 TAILQ_REMOVE(nextqueue
, ret
, queue
);
403 chmp
->chm_gcblock
= ret
;
404 ret
->gc_node
= ret
->first_node
;
407 dbg_gc("Oops! ret->gc_node at LEB: %u is NULL\n", ret
->lnr
);
408 panic("CHFS BUG - one LEB's gc_node is NULL\n");
411 /* TODO wasted size? */
417 chfs_gcollect_pass(struct chfs_mount
*chmp
)
419 struct chfs_vnode_cache
*vc
;
420 struct chfs_eraseblock
*eb
;
421 struct chfs_node_ref
*nref
;
422 uint32_t gcblock_dirty
;
423 struct chfs_inode
*ip
;
428 KASSERT(mutex_owned(&chmp
->chm_lock_mountfields
));
430 // mutex_enter(&chmp->chm_lock_mountfields);
432 mutex_enter(&chmp
->chm_lock_sizes
);
434 dbg_gc("unchecked size == %u\n", chmp
->chm_unchecked_size
);
435 if (!chmp
->chm_unchecked_size
)
438 if (chmp
->chm_checked_vno
> chmp
->chm_max_vno
) {
439 mutex_exit(&chmp
->chm_lock_sizes
);
440 mutex_exit(&chmp
->chm_lock_mountfields
);
441 dbg_gc("checked_vno (#%llu) > max_vno (#%llu)\n",
442 (unsigned long long)chmp
->chm_checked_vno
,
443 (unsigned long long)chmp
->chm_max_vno
);
447 mutex_exit(&chmp
->chm_lock_sizes
);
449 mutex_enter(&chmp
->chm_lock_vnocache
);
450 dbg_gc("checking vno #%llu\n",
451 (unsigned long long)chmp
->chm_checked_vno
);
452 dbg_gc("get vnode cache\n");
453 vc
= chfs_vnode_cache_get(chmp
, chmp
->chm_checked_vno
++);
457 mutex_exit(&chmp
->chm_lock_vnocache
);
461 if ((vc
->pvno
| vc
->nlink
) == 0) {
462 dbg_gc("(pvno | nlink) == 0\n");
463 mutex_exit(&chmp
->chm_lock_vnocache
);
469 case VNO_STATE_CHECKEDABSENT
:
470 case VNO_STATE_PRESENT
:
471 mutex_exit(&chmp
->chm_lock_vnocache
);
475 case VNO_STATE_CHECKING
:
476 mutex_exit(&chmp
->chm_lock_vnocache
);
477 mutex_exit(&chmp
->chm_lock_mountfields
);
478 dbg_gc("VNO_STATE GC or CHECKING\n");
479 panic("CHFS BUG - vc state gc or checking\n");
481 case VNO_STATE_READING
:
482 chmp
->chm_checked_vno
--;
483 mutex_exit(&chmp
->chm_lock_vnocache
);
484 /* XXX why do we need the delay here?! */
485 kpause("chvncrea", true, mstohz(50), NULL
);
487 // sleep_on_spinunlock(&chmp->chm_lock_vnocache);
488 // KASSERT(!mutex_owned(&chmp->chm_lock_vnocache));
489 mutex_exit(&chmp
->chm_lock_mountfields
);
493 mutex_exit(&chmp
->chm_lock_vnocache
);
494 mutex_exit(&chmp
->chm_lock_mountfields
);
496 panic("CHFS BUG - vc state is other what we"
499 case VNO_STATE_UNCHECKED
:
503 chfs_vnode_cache_set_state(chmp
, vc
, VNO_STATE_CHECKING
);
505 /* XXX check if this is too heavy to call under
508 ret
= chfs_check(chmp
, vc
);
509 dbg_gc("set state\n");
510 chfs_vnode_cache_set_state(chmp
,
511 vc
, VNO_STATE_CHECKEDABSENT
);
513 mutex_exit(&chmp
->chm_lock_vnocache
);
514 mutex_exit(&chmp
->chm_lock_mountfields
);
520 eb
= chmp
->chm_gcblock
;
523 eb
= find_gc_block(chmp
);
528 if (!TAILQ_EMPTY(&chmp
->chm_erase_pending_queue
)) {
529 mutex_exit(&chmp
->chm_lock_sizes
);
530 mutex_exit(&chmp
->chm_lock_mountfields
);
533 mutex_exit(&chmp
->chm_lock_sizes
);
534 mutex_exit(&chmp
->chm_lock_mountfields
);
538 if (!eb
->used_size
) {
539 dbg_gc("!eb->used_size\n");
544 //dbg_gc("gc use: %u\n", chmp->chm_nextblock->lnr);
545 //dbg_gc("nref: %u %u\n", nref->nref_lnr, nref->nref_offset);
546 gcblock_dirty
= eb
->dirty_size
;
548 while(CHFS_REF_OBSOLETE(nref
)) {
549 //dbg_gc("obsoleted nref lnr: %u - offset: %u\n", nref->nref_lnr, nref->nref_offset);
551 if (nref
== chmp
->chm_blocks
[nref
->nref_lnr
].last_node
) {
552 dbg_gc("THIS NODE IS THE LAST NODE OF ITS EB\n");
555 nref
= node_next(nref
);
559 mutex_exit(&chmp
->chm_lock_sizes
);
560 mutex_exit(&chmp
->chm_lock_mountfields
);
561 panic("CHFS BUG - nref is NULL)\n");
565 //dbg_gc("nref the chosen one lnr: %u - offset: %u\n", nref->nref_lnr, nref->nref_offset);
566 KASSERT(nref
->nref_lnr
== chmp
->chm_gcblock
->lnr
);
568 if (!nref
->nref_next
) {
569 //dbg_gc("!nref->nref_next\n");
570 mutex_exit(&chmp
->chm_lock_sizes
);
571 if (CHFS_REF_FLAGS(nref
) == CHFS_PRISTINE_NODE_MASK
) {
572 chfs_gcollect_pristine(chmp
, eb
, NULL
, nref
);
574 chfs_mark_node_obsolete(chmp
, nref
);
579 dbg_gc("nref lnr: %u - offset: %u\n", nref
->nref_lnr
, nref
->nref_offset
);
580 vc
= chfs_nref_to_vc(nref
);
582 mutex_exit(&chmp
->chm_lock_sizes
);
584 //dbg_gc("enter vnocache lock on #%llu\n", vc->vno);
585 mutex_enter(&chmp
->chm_lock_vnocache
);
589 case VNO_STATE_CHECKEDABSENT
:
590 if (CHFS_REF_FLAGS(nref
) == CHFS_PRISTINE_NODE_MASK
) {
591 chfs_vnode_cache_set_state(chmp
, vc
, VNO_STATE_GC
);
595 case VNO_STATE_PRESENT
:
598 case VNO_STATE_UNCHECKED
:
599 case VNO_STATE_CHECKING
:
601 mutex_exit(&chmp
->chm_lock_vnocache
);
602 mutex_exit(&chmp
->chm_lock_mountfields
);
603 panic("CHFS BUG - vc state unchecked,"
604 " checking or gc (vno #%llu, num #%d)\n",
605 (unsigned long long)vc
->vno
, vc
->state
);
607 case VNO_STATE_READING
:
608 mutex_exit(&chmp
->chm_lock_vnocache
);
609 /* XXX why do we need the delay here?! */
610 kpause("chvncrea", true, mstohz(50), NULL
);
612 // sleep_on_spinunlock(&chmp->chm_lock_vnocache);
613 // KASSERT(!mutex_owned(&chmp->chm_lock_vnocache));
614 mutex_exit(&chmp
->chm_lock_mountfields
);
618 if (vc
->state
== VNO_STATE_GC
) {
619 dbg_gc("vc->state == VNO_STATE_GC\n");
620 mutex_exit(&chmp
->chm_lock_vnocache
);
621 ret
= chfs_gcollect_pristine(chmp
, eb
, NULL
, nref
);
623 // chfs_vnode_cache_state_set(chmp,
624 // vc, VNO_STATE_CHECKEDABSENT);
626 vc
->state
= VNO_STATE_CHECKEDABSENT
;
627 //TODO wake_up(&chmp->chm_vnocache_wq);
630 mutex_enter(&chmp
->chm_lock_vnocache
);
636 mutex_exit(&chmp
->chm_lock_vnocache
);
638 ip
= chfs_gc_fetch_inode(chmp
, vno
, !(pvno
| nlink
));
646 chfs_gcollect_live(chmp
, eb
, nref
, ip
);
648 chfs_gc_release_inode(chmp
, ip
);
651 if (eb
->dirty_size
== gcblock_dirty
&&
652 !CHFS_REF_OBSOLETE(eb
->gc_node
)) {
653 dbg_gc("ERROR collecting node at %u failed.\n",
654 CHFS_GET_OFS(eb
->gc_node
->nref_offset
));
660 KASSERT(mutex_owned(&chmp
->chm_lock_mountfields
));
661 mutex_enter(&chmp
->chm_lock_sizes
);
665 if (chmp
->chm_gcblock
) {
666 dbg_gc("eb used size = %u\n", chmp
->chm_gcblock
->used_size
);
667 dbg_gc("eb free size = %u\n", chmp
->chm_gcblock
->free_size
);
668 dbg_gc("eb dirty size = %u\n", chmp
->chm_gcblock
->dirty_size
);
669 dbg_gc("eb unchecked size = %u\n",
670 chmp
->chm_gcblock
->unchecked_size
);
671 dbg_gc("eb wasted size = %u\n", chmp
->chm_gcblock
->wasted_size
);
673 KASSERT(chmp
->chm_gcblock
->used_size
+ chmp
->chm_gcblock
->free_size
+
674 chmp
->chm_gcblock
->dirty_size
+
675 chmp
->chm_gcblock
->unchecked_size
+
676 chmp
->chm_gcblock
->wasted_size
== chmp
->chm_ebh
->eb_size
);
680 if (chmp
->chm_gcblock
&& chmp
->chm_gcblock
->dirty_size
+
681 chmp
->chm_gcblock
->wasted_size
== chmp
->chm_ebh
->eb_size
) {
682 dbg_gc("Block at leb #%u completely obsoleted by GC, "
683 "Moving to erase_pending_queue\n", chmp
->chm_gcblock
->lnr
);
684 TAILQ_INSERT_TAIL(&chmp
->chm_erase_pending_queue
,
685 chmp
->chm_gcblock
, queue
);
686 chmp
->chm_gcblock
= NULL
;
687 chmp
->chm_nr_erasable_blocks
++;
688 if (!TAILQ_EMPTY(&chmp
->chm_erase_pending_queue
)) {
689 ret
= chfs_remap_leb(chmp
);
693 mutex_exit(&chmp
->chm_lock_sizes
);
694 mutex_exit(&chmp
->chm_lock_mountfields
);
701 chfs_gcollect_pristine(struct chfs_mount
*chmp
, struct chfs_eraseblock
*cheb
,
702 struct chfs_vnode_cache
*chvc
, struct chfs_node_ref
*nref
)
704 struct chfs_node_ref
*newnref
;
705 struct chfs_flash_node_hdr
*nhdr
;
706 struct chfs_flash_vnode
*fvnode
;
707 struct chfs_flash_dirent_node
*fdirent
;
708 struct chfs_flash_data_node
*fdata
;
709 int ret
, retries
= 0;
711 size_t totlen
= chfs_nref_len(chmp
, cheb
, nref
);
716 dbg_gc("gcollect_pristine\n");
718 data
= kmem_alloc(totlen
, KM_SLEEP
);
722 ofs
= CHFS_GET_OFS(nref
->nref_offset
);
724 ret
= chfs_read_leb(chmp
, nref
->nref_lnr
, data
, ofs
, totlen
, &retlen
);
726 dbg_gc("reading error\n");
729 if (retlen
!= totlen
) {
730 dbg_gc("read size error\n");
733 nhdr
= (struct chfs_flash_node_hdr
*)data
;
734 /* check the header */
735 if (le16toh(nhdr
->magic
) != CHFS_FS_MAGIC_BITMASK
) {
736 dbg_gc("node header magic number error\n");
739 crc
= crc32(0, (uint8_t *)nhdr
, CHFS_NODE_HDR_SIZE
- 4);
740 if (crc
!= le32toh(nhdr
->hdr_crc
)) {
741 dbg_gc("node header crc error\n");
745 switch(le16toh(nhdr
->type
)) {
746 case CHFS_NODETYPE_VNODE
:
747 fvnode
= (struct chfs_flash_vnode
*)data
;
748 crc
= crc32(0, (uint8_t *)fvnode
, sizeof(struct chfs_flash_vnode
) - 4);
749 if (crc
!= le32toh(fvnode
->node_crc
)) {
750 dbg_gc("vnode crc error\n");
754 case CHFS_NODETYPE_DIRENT
:
755 fdirent
= (struct chfs_flash_dirent_node
*)data
;
756 crc
= crc32(0, (uint8_t *)fdirent
, sizeof(struct chfs_flash_dirent_node
) - 4);
757 if (crc
!= le32toh(fdirent
->node_crc
)) {
758 dbg_gc("dirent crc error\n");
761 crc
= crc32(0, fdirent
->name
, fdirent
->nsize
);
762 if (crc
!= le32toh(fdirent
->name_crc
)) {
763 dbg_gc("dirent name crc error\n");
767 case CHFS_NODETYPE_DATA
:
768 fdata
= (struct chfs_flash_data_node
*)data
;
769 crc
= crc32(0, (uint8_t *)fdata
, sizeof(struct chfs_flash_data_node
) - 4);
770 if (crc
!= le32toh(fdata
->node_crc
)) {
771 dbg_gc("data node crc error\n");
777 dbg_gc("unknown node have vnode cache\n");
781 /* CRC's OK, write node to its new place */
783 ret
= chfs_reserve_space_gc(chmp
, totlen
);
787 newnref
= chfs_alloc_node_ref(chmp
->chm_nextblock
);
791 ofs
= chmp
->chm_ebh
->eb_size
- chmp
->chm_nextblock
->free_size
;
792 newnref
->nref_offset
= ofs
;
794 vec
.iov_base
= (void *)data
;
795 vec
.iov_len
= totlen
;
796 mutex_enter(&chmp
->chm_lock_sizes
);
797 ret
= chfs_write_wbuf(chmp
, &vec
, 1, ofs
, &retlen
);
799 if (ret
|| retlen
!= totlen
) {
800 chfs_err("error while writing out to the media\n");
801 chfs_err("err: %d | size: %zu | retlen : %zu\n",
802 ret
, totlen
, retlen
);
804 chfs_change_size_dirty(chmp
, chmp
->chm_nextblock
, totlen
);
806 mutex_exit(&chmp
->chm_lock_sizes
);
811 mutex_exit(&chmp
->chm_lock_sizes
);
815 mutex_exit(&chmp
->chm_lock_sizes
);
816 //TODO should we set free_size?
817 chfs_mark_node_obsolete(chmp
, nref
);
818 chfs_add_vnode_ref_to_vc(chmp
, chvc
, newnref
);
824 chfs_gcollect_live(struct chfs_mount
*chmp
,
825 struct chfs_eraseblock
*cheb
, struct chfs_node_ref
*nref
,
826 struct chfs_inode
*ip
)
828 struct chfs_node_frag
*frag
;
829 struct chfs_full_dnode
*fn
= NULL
;
830 int start
= 0, end
= 0, nrfrags
= 0;
831 struct chfs_dirent
*fd
= NULL
;
835 dbg_gc("gcollect_live\n");
837 if (chmp
->chm_gcblock
!= cheb
) {
838 dbg_gc("GC block is no longer gcblock. Restart.\n");
842 if (CHFS_REF_OBSOLETE(nref
)) {
843 dbg_gc("node to be GC'd was obsoleted in the meantime.\n");
848 if (ip
->chvc
->v
== nref
) {
849 chfs_gcollect_vnode(chmp
, ip
);
854 dbg_gc("find full dnode\n");
855 for(frag
= frag_first(&ip
->fragtree
);
856 frag
; frag
= frag_next(&ip
->fragtree
, frag
)) {
857 if (frag
->node
&& frag
->node
->nref
== nref
) {
859 end
= frag
->ofs
+ frag
->size
;
862 if (nrfrags
== frag
->node
->frags
)
867 /* It's a pristine node, or dnode (or hole? XXX have we hole nodes?) */
869 if (CHFS_REF_FLAGS(nref
) == CHFS_PRISTINE_NODE_MASK
) {
870 ret
= chfs_gcollect_pristine(chmp
,
871 cheb
, ip
->chvc
, nref
);
873 frag
->node
->nref
= ip
->chvc
->v
;
878 //ret = chfs_gcollect_hole(chmp, cheb, ip, fn, start, end);
879 ret
= chfs_gcollect_dnode(chmp
, cheb
, ip
, fn
, start
, end
);
885 dbg_gc("find full dirent\n");
887 TAILQ_FOREACH(fd
, &ip
->dents
, fds
) {
888 if (fd
->nref
== nref
) {
894 if (is_dirent
&& fd
->vno
) {
895 ret
= chfs_gcollect_dirent(chmp
, cheb
, ip
, fd
);
896 } else if (is_dirent
) {
897 ret
= chfs_gcollect_deletion_dirent(chmp
, cheb
, ip
, fd
);
899 dbg_gc("Nref at leb #%u offset 0x%08x wasn't in node list"
901 nref
->nref_lnr
, CHFS_GET_OFS(nref
->nref_offset
),
902 (unsigned long long)ip
->ino
);
903 if (CHFS_REF_OBSOLETE(nref
)) {
904 dbg_gc("But it's obsolete so we don't mind"
914 chfs_gcollect_vnode(struct chfs_mount
*chmp
, struct chfs_inode
*ip
)
917 dbg_gc("gcollect_vnode\n");
919 ret
= chfs_write_flash_vnode(chmp
, ip
, ALLOC_GC
);
925 chfs_gcollect_dirent(struct chfs_mount
*chmp
,
926 struct chfs_eraseblock
*cheb
, struct chfs_inode
*parent
,
927 struct chfs_dirent
*fd
)
929 struct vnode
*vnode
= NULL
;
930 struct chfs_inode
*ip
;
931 struct chfs_node_ref
*prev
;
932 dbg_gc("gcollect_dirent\n");
934 vnode
= chfs_vnode_lookup(chmp
, fd
->vno
);
936 /* XXX maybe KASSERT or panic on this? */
943 prev
= parent
->chvc
->dirents
;
944 if (prev
== fd
->nref
) {
945 parent
->chvc
->dirents
= prev
->nref_next
;
946 dbg_gc("fd nref removed from dirents list\n");
950 if (prev
->nref_next
== fd
->nref
) {
951 prev
->nref_next
= fd
->nref
->nref_next
;
952 dbg_gc("fd nref removed from dirents list\n");
955 prev
= prev
->nref_next
;
959 chfs_mark_node_obsolete(chmp
, fd
->nref
);
960 return chfs_write_flash_dirent(chmp
,
961 parent
, ip
, fd
, fd
->vno
, ALLOC_GC
);
964 /* Check dirents what are marked as deleted. */
966 chfs_gcollect_deletion_dirent(struct chfs_mount
*chmp
,
967 struct chfs_eraseblock
*cheb
, struct chfs_inode
*parent
,
968 struct chfs_dirent
*fd
)
970 struct chfs_flash_dirent_node chfdn
;
971 struct chfs_node_ref
*nref
;
972 size_t retlen
, name_len
, nref_len
;
977 struct vnode
*vnode
= NULL
;
979 dbg_gc("gcollect_deletion_dirent\n");
981 name_len
= strlen(fd
->name
);
982 name_crc
= crc32(0, fd
->name
, name_len
);
984 nref_len
= chfs_nref_len(chmp
, cheb
, fd
->nref
);
986 vnode
= chfs_vnode_lookup(chmp
, fd
->vno
);
988 //dbg_gc("ip from vnode\n");
989 //VFS_VGET(chmp->chm_fsmp, fd->vno, &vnode);
993 //dbg_gc("mutex enter erase_completion_lock\n");
995 // dbg_gc("alloc chfdn\n");
996 // chfdn = kmem_alloc(nref_len, KM_SLEEP);
1000 for (nref
= parent
->chvc
->dirents
;
1001 nref
!= (void*)parent
->chvc
;
1002 nref
= nref
->nref_next
) {
1004 if (!CHFS_REF_OBSOLETE(nref
))
1007 /* if node refs have different length, skip */
1008 if (chfs_nref_len(chmp
, NULL
, nref
) != nref_len
)
1011 if (CHFS_GET_OFS(nref
->nref_offset
) ==
1012 CHFS_GET_OFS(fd
->nref
->nref_offset
)) {
1016 ret
= chfs_read_leb(chmp
,
1017 nref
->nref_lnr
, (void*)&chfdn
, CHFS_GET_OFS(nref
->nref_offset
),
1021 dbg_gc("Read error: %d\n", ret
);
1025 if (retlen
!= nref_len
) {
1026 dbg_gc("Error reading node:"
1027 " read: %zu insted of: %zu\n", retlen
, nref_len
);
1031 /* if node type doesn't match, skip */
1032 if (le16toh(chfdn
.type
) != CHFS_NODETYPE_DIRENT
)
1035 /* if crc doesn't match, skip */
1036 if (le32toh(chfdn
.name_crc
) != name_crc
)
1039 /* if length of name different, or this is an another deletion
1042 if (chfdn
.nsize
!= name_len
|| !le64toh(chfdn
.vno
))
1045 /* check actual name */
1046 if (memcmp(chfdn
.name
, fd
->name
, name_len
))
1049 // kmem_free(chfdn, nref_len);
1051 chfs_mark_node_obsolete(chmp
, fd
->nref
);
1052 return chfs_write_flash_dirent(chmp
,
1053 parent
, NULL
, fd
, fd
->vno
, ALLOC_GC
);
1056 // kmem_free(chfdn, nref_len);
1058 TAILQ_REMOVE(&parent
->dents
, fd
, fds
);
1059 chfs_free_dirent(fd
);
1064 chfs_gcollect_dnode(struct chfs_mount
*chmp
,
1065 struct chfs_eraseblock
*orig_cheb
, struct chfs_inode
*ip
,
1066 struct chfs_full_dnode
*fn
, uint32_t orig_start
, uint32_t orig_end
)
1068 struct chfs_node_ref
*nref
, *prev
;
1069 struct chfs_full_dnode
*newfn
;
1070 struct chfs_flash_data_node
*fdnode
;
1071 int ret
= 0, retries
= 0;
1076 dbg_gc("gcollect_dnode\n");
1078 //uint32_t used_size;
1080 /* TODO GC merging frags, should we use it?
1082 uint32_t start, end;
1087 if (chmp->chm_nr_free_blocks + chmp->chm_nr_erasable_blocks > chmp->chm_resv_blocks_gcmerge) {
1088 struct chfs_node_frag *frag;
1091 min = start & (PAGE_CACHE_SIZE-1);
1092 max = min + PAGE_CACHE_SIZE;
1094 frag = (struct chfs_node_frag *)rb_tree_find_node_leq(&ip->i_chfs_ext.fragtree, &start);
1095 KASSERT(frag->ofs == start);
1097 while ((frag = frag_prev(&ip->i_chfs_ext.fragtree, frag)) && frag->ofs >= min) {
1098 if (frag->ofs > min) {
1103 if (!frag->node || !frag->node->nref) {
1106 struct chfs_node_ref *nref = frag->node->nref;
1107 struct chfs_eraseblock *cheb;
1109 cheb = &chmp->chm_blocks[nref->nref_lnr];
1111 if (cheb == chmp->chm_gcblock)
1114 //TODO is this a clean block?
1122 frag = (struct chfs_node_frag *)rb_tree_find_node_leq(&ip->i_chfs_ext.fragtree, &(end));
1124 while ((frag = frag_next(&ip->i_chfs_ext.fragtree, frag)) && (frag->ofs + frag->size <= max)) {
1125 if (frag->ofs + frag->size < max) {
1126 end = frag->ofs + frag->size;
1130 if (!frag->node || !frag->node->nref) {
1133 struct chfs_node_ref *nref = frag->node->nref;
1134 struct chfs_eraseblock *cheb;
1136 cheb = &chmp->chm_blocks[nref->nref_lnr];
1138 if (cheb == chmp->chm_gcblock)
1139 end = frag->ofs + frag->size;
1141 //TODO is this a clean block?
1143 end = frag->ofs + frag->size;
1149 frag_last(&ip->i_chfs_ext.fragtree)->ofs +
1150 frag_last(&ip->i_chfs_ext.fragtree)->size);
1151 KASSERT(end >= orig_end);
1152 KASSERT(start <= orig_start);
1155 KASSERT(orig_cheb
->lnr
== fn
->nref
->nref_lnr
);
1156 totlen
= chfs_nref_len(chmp
, orig_cheb
, fn
->nref
);
1157 data
= kmem_alloc(totlen
, KM_SLEEP
);
1159 ret
= chfs_read_leb(chmp
, fn
->nref
->nref_lnr
, data
, fn
->nref
->nref_offset
,
1162 fdnode
= (struct chfs_flash_data_node
*)data
;
1163 fdnode
->version
= htole64(++ip
->chvc
->highest_version
);
1164 fdnode
->node_crc
= htole32(crc32(0, (uint8_t *)fdnode
,
1165 sizeof(*fdnode
) - 4));
1167 vec
.iov_base
= (void *)data
;
1168 vec
.iov_len
= totlen
;
1171 ret
= chfs_reserve_space_gc(chmp
, totlen
);
1175 nref
= chfs_alloc_node_ref(chmp
->chm_nextblock
);
1181 mutex_enter(&chmp
->chm_lock_sizes
);
1183 nref
->nref_offset
= chmp
->chm_ebh
->eb_size
- chmp
->chm_nextblock
->free_size
;
1184 KASSERT(nref
->nref_offset
% 4 == 0);
1185 chfs_change_size_free(chmp
, chmp
->chm_nextblock
, -totlen
);
1187 ret
= chfs_write_wbuf(chmp
, &vec
, 1, nref
->nref_offset
, &retlen
);
1188 if (ret
|| retlen
!= totlen
) {
1189 chfs_err("error while writing out to the media\n");
1190 chfs_err("err: %d | size: %d | retlen : %zu\n",
1191 ret
, totlen
, retlen
);
1192 chfs_change_size_dirty(chmp
, chmp
->chm_nextblock
, totlen
);
1195 mutex_exit(&chmp
->chm_lock_sizes
);
1200 mutex_exit(&chmp
->chm_lock_sizes
);
1204 dbg_gc("new nref lnr: %u - offset: %u\n", nref
->nref_lnr
, nref
->nref_offset
);
1206 chfs_change_size_used(chmp
, &chmp
->chm_blocks
[nref
->nref_lnr
], totlen
);
1207 mutex_exit(&chmp
->chm_lock_sizes
);
1208 KASSERT(chmp
->chm_blocks
[nref
->nref_lnr
].used_size
<= chmp
->chm_ebh
->eb_size
);
1210 newfn
= chfs_alloc_full_dnode();
1212 newfn
->ofs
= fn
->ofs
;
1213 newfn
->size
= fn
->size
;
1214 newfn
->frags
= fn
->frags
;
1216 //TODO should we remove fd from dnode list?
1218 prev
= ip
->chvc
->dnode
;
1219 if (prev
== fn
->nref
) {
1220 ip
->chvc
->dnode
= prev
->nref_next
;
1224 if (prev
->nref_next
== fn
->nref
) {
1225 prev
->nref_next
= fn
->nref
->nref_next
;
1228 prev
= prev
->nref_next
;
1231 chfs_add_full_dnode_to_inode(chmp
, ip
, newfn
);
1232 chfs_add_node_to_list(chmp
,
1233 ip
->chvc
, newfn
->nref
, &ip
->chvc
->dnode
);
1236 kmem_free(data
, totlen
);