1 /* $NetBSD: chfs_gc.c,v 1.5 2013/10/20 17:18:38 christos 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);
64 * chfs_gc_trigger - wakes up GC thread, if it should run
65 * Must be called with chm_lock_mountfields held.
68 chfs_gc_trigger(struct chfs_mount
*chmp
)
70 struct garbage_collector_thread
*gc
= &chmp
->chm_gc_thread
;
72 if (gc
->gcth_running
&&
73 chfs_gc_thread_should_wake(chmp
)) {
74 cv_signal(&gc
->gcth_wakeup
);
79 /* chfs_gc_thread - garbage collector's thread */
81 chfs_gc_thread(void *data
)
83 struct chfs_mount
*chmp
= data
;
84 struct garbage_collector_thread
*gc
= &chmp
->chm_gc_thread
;
86 dbg_gc("[GC THREAD] thread started\n");
88 mutex_enter(&chmp
->chm_lock_mountfields
);
89 while (gc
->gcth_running
) {
90 /* we must call chfs_gc_thread_should_wake with chm_lock_mountfields
91 * held, which is a bit awkwardly done here, but we cant relly
92 * do it otherway with the current design...
94 if (chfs_gc_thread_should_wake(chmp
)) {
95 if (chfs_gcollect_pass(chmp
) == ENOSPC
) {
96 mutex_exit(&chmp
->chm_lock_mountfields
);
97 panic("No space for garbage collection\n");
98 /* XXX why break here? i have added a panic
99 * here to see if it gets triggered -ahoka
103 /* XXX gcollect_pass drops the mutex */
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");
115 /* chfs_gc_thread_start - starts GC */
117 chfs_gc_thread_start(struct chfs_mount
*chmp
)
119 struct garbage_collector_thread
*gc
= &chmp
->chm_gc_thread
;
121 cv_init(&gc
->gcth_wakeup
, "chfsgccv");
123 gc
->gcth_running
= true;
124 kthread_create(PRI_NONE
, /*KTHREAD_MPSAFE |*/ KTHREAD_MUSTJOIN
,
125 NULL
, chfs_gc_thread
, chmp
, &gc
->gcth_thread
,
129 /* chfs_gc_thread_start - stops GC */
131 chfs_gc_thread_stop(struct chfs_mount
*chmp
)
133 struct garbage_collector_thread
*gc
= &chmp
->chm_gc_thread
;
135 /* check if it is actually running */
136 if (gc
->gcth_running
) {
137 gc
->gcth_running
= false;
141 cv_signal(&gc
->gcth_wakeup
);
142 dbg_gc("[GC THREAD] stop signal sent\n");
144 kthread_join(gc
->gcth_thread
);
145 #ifdef BROKEN_KTH_JOIN
146 kpause("chfsthjoin", false, mstohz(1000), NULL
);
149 cv_destroy(&gc
->gcth_wakeup
);
153 * chfs_gc_thread_should_wake - checks if GC thread should wake up
154 * Must be called with chm_lock_mountfields held.
155 * Returns 1, if GC should wake up and 0 else.
158 chfs_gc_thread_should_wake(struct chfs_mount
*chmp
)
160 int nr_very_dirty
= 0;
161 struct chfs_eraseblock
*cheb
;
164 KASSERT(mutex_owned(&chmp
->chm_lock_mountfields
));
166 /* Erase pending queue is not empty. */
167 if (!TAILQ_EMPTY(&chmp
->chm_erase_pending_queue
)) {
168 dbg_gc("erase_pending\n");
172 /* There is something unchecked in the filesystem. */
173 if (chmp
->chm_unchecked_size
) {
174 dbg_gc("unchecked\n");
178 dirty
= chmp
->chm_dirty_size
- chmp
->chm_nr_erasable_blocks
*
179 chmp
->chm_ebh
->eb_size
;
181 /* Number of free and erasable blocks are critical. */
182 if (chmp
->chm_nr_free_blocks
+ chmp
->chm_nr_erasable_blocks
<
183 chmp
->chm_resv_blocks_gctrigger
&& (dirty
> chmp
->chm_nospc_dirty
)) {
184 dbg_gc("free: %d + erasable: %d < resv: %d\n",
185 chmp
->chm_nr_free_blocks
, chmp
->chm_nr_erasable_blocks
,
186 chmp
->chm_resv_blocks_gctrigger
);
187 dbg_gc("dirty: %d > nospc_dirty: %d\n",
188 dirty
, chmp
->chm_nospc_dirty
);
193 /* There is too much very dirty blocks. */
194 TAILQ_FOREACH(cheb
, &chmp
->chm_very_dirty_queue
, queue
) {
196 if (nr_very_dirty
== chmp
->chm_vdirty_blocks_gctrigger
) {
197 dbg_gc("nr_very_dirty\n");
202 /* Everythin OK, GC shouldn't run. */
206 /* chfs_gc_release_inode - does nothing yet */
208 chfs_gc_release_inode(struct chfs_mount
*chmp
,
209 struct chfs_inode
*ip
)
211 dbg_gc("release inode\n");
214 /* chfs_gc_fetch_inode - assign the given inode to the GC */
216 chfs_gc_fetch_inode(struct chfs_mount
*chmp
, ino_t vno
,
219 struct vnode
*vp
= NULL
;
220 struct chfs_vnode_cache
*vc
;
221 struct chfs_inode
*ip
;
222 dbg_gc("fetch inode %llu\n", (unsigned long long)vno
);
225 dbg_gc("unlinked\n");
226 vp
= chfs_vnode_lookup(chmp
, vno
);
228 mutex_enter(&chmp
->chm_lock_vnocache
);
229 vc
= chfs_vnode_cache_get(chmp
, vno
);
231 mutex_exit(&chmp
->chm_lock_vnocache
);
234 if (vc
->state
!= VNO_STATE_CHECKEDABSENT
) {
235 mutex_exit(&chmp
->chm_lock_vnocache
);
236 /* XXX why do we need the delay here?! */
237 KASSERT(mutex_owned(&chmp
->chm_lock_mountfields
));
239 &chmp
->chm_gc_thread
.gcth_wakeup
,
240 &chmp
->chm_lock_mountfields
, mstohz(50));
242 mutex_exit(&chmp
->chm_lock_vnocache
);
247 dbg_gc("vnode lookup\n");
248 vp
= chfs_vnode_lookup(chmp
, vno
);
250 dbg_gc("vp to ip\n");
257 extern rb_tree_ops_t frag_rbtree_ops
;
259 /* chfs_check - checks an inode with minimal initialization */
261 chfs_check(struct chfs_mount
*chmp
, struct chfs_vnode_cache
*chvc
)
263 KASSERT(mutex_owned(&chmp
->chm_lock_vnocache
));
265 struct chfs_inode
*ip
;
269 /* Get a new inode. */
270 ip
= pool_get(&chfs_inode_pool
, PR_WAITOK
);
275 vp
= kmem_zalloc(sizeof(struct vnode
), KM_SLEEP
);
277 /* Minimal initialization. */
283 rb_tree_init(&ip
->fragtree
, &frag_rbtree_ops
);
284 TAILQ_INIT(&ip
->dents
);
286 /* Build the node. */
287 mutex_exit(&chmp
->chm_lock_vnocache
);
288 ret
= chfs_read_inode_internal(chmp
, ip
);
289 mutex_enter(&chmp
->chm_lock_vnocache
);
291 chfs_clear_inode(chmp
, ip
);
295 pool_put(&chfs_inode_pool
, ip
);
300 /* chfs_clear_inode - kills a minimal inode */
302 chfs_clear_inode(struct chfs_mount
*chmp
, struct chfs_inode
*ip
)
304 KASSERT(mutex_owned(&chmp
->chm_lock_vnocache
));
306 struct chfs_dirent
*fd
, *tmpfd
;
307 struct chfs_vnode_cache
*chvc
;
308 struct chfs_node_ref
*nref
;
311 /* shouldnt this be: */
312 //bool deleted = (chvc && !(chvc->pvno || chvc->nlink));
313 int deleted
= (chvc
&& !(chvc
->pvno
| chvc
->nlink
));
315 /* Set actual state. */
316 if (chvc
&& chvc
->state
!= VNO_STATE_CHECKING
) {
317 chvc
->state
= VNO_STATE_CLEARING
;
320 /* Remove vnode information. */
321 while (deleted
&& chvc
->v
!= (struct chfs_node_ref
*)chvc
) {
323 chfs_remove_and_obsolete(chmp
, chvc
, nref
, &chvc
->v
);
327 chfs_kill_fragtree(chmp
, &ip
->fragtree
);
330 TAILQ_FOREACH_SAFE(fd
, &ip
->dents
, fds
, tmpfd
) {
331 chfs_free_dirent(fd
);
334 /* Remove node from vnode cache. */
335 if (chvc
&& chvc
->state
== VNO_STATE_CHECKING
) {
336 chvc
->state
= VNO_STATE_CHECKEDABSENT
;
337 if ((struct chfs_vnode_cache
*)chvc
->v
== chvc
&&
338 (struct chfs_vnode_cache
*)chvc
->dirents
== chvc
&&
339 (struct chfs_vnode_cache
*)chvc
->dnode
== chvc
)
340 chfs_vnode_cache_remove(chmp
, chvc
);
344 /* find_gc_block - finds the next block for GC */
345 struct chfs_eraseblock
*
346 find_gc_block(struct chfs_mount
*chmp
)
348 struct chfs_eraseblock
*ret
;
349 struct chfs_eraseblock_queue
*nextqueue
;
351 KASSERT(mutex_owned(&chmp
->chm_lock_mountfields
));
353 /* Get a random number. */
357 int n
= now
.tv_nsec
% 128;
360 /* Find an eraseblock queue. */
361 if (n
<50 && !TAILQ_EMPTY(&chmp
->chm_erase_pending_queue
)) {
362 dbg_gc("Picking block from erase_pending_queue to GC next\n");
363 nextqueue
= &chmp
->chm_erase_pending_queue
;
364 } else if (n
<110 && !TAILQ_EMPTY(&chmp
->chm_very_dirty_queue
) ) {
365 dbg_gc("Picking block from very_dirty_queue to GC next\n");
366 nextqueue
= &chmp
->chm_very_dirty_queue
;
367 } else if (n
<126 && !TAILQ_EMPTY(&chmp
->chm_dirty_queue
) ) {
368 dbg_gc("Picking block from dirty_queue to GC next\n");
369 nextqueue
= &chmp
->chm_dirty_queue
;
370 } else if (!TAILQ_EMPTY(&chmp
->chm_clean_queue
)) {
371 dbg_gc("Picking block from clean_queue to GC next\n");
372 nextqueue
= &chmp
->chm_clean_queue
;
373 } else if (!TAILQ_EMPTY(&chmp
->chm_dirty_queue
)) {
374 dbg_gc("Picking block from dirty_queue to GC next"
375 " (clean_queue was empty)\n");
376 nextqueue
= &chmp
->chm_dirty_queue
;
377 } else if (!TAILQ_EMPTY(&chmp
->chm_very_dirty_queue
)) {
378 dbg_gc("Picking block from very_dirty_queue to GC next"
379 " (clean_queue and dirty_queue were empty)\n");
380 nextqueue
= &chmp
->chm_very_dirty_queue
;
381 } else if (!TAILQ_EMPTY(&chmp
->chm_erase_pending_queue
)) {
382 dbg_gc("Picking block from erase_pending_queue to GC next"
383 " (clean_queue and {very_,}dirty_queue were empty)\n");
384 nextqueue
= &chmp
->chm_erase_pending_queue
;
385 } else if (!TAILQ_EMPTY(&chmp
->chm_erasable_pending_wbuf_queue
)) {
386 dbg_gc("Synching wbuf in order to reuse "
387 "erasable_pendig_wbuf_queue blocks\n");
388 rw_enter(&chmp
->chm_lock_wbuf
, RW_WRITER
);
389 chfs_flush_pending_wbuf(chmp
);
390 rw_exit(&chmp
->chm_lock_wbuf
);
393 dbg_gc("CHFS: no clean, dirty _or_ erasable"
394 " blocks to GC from! Where are they all?\n");
398 /* Get the first block of the queue. */
399 ret
= TAILQ_FIRST(nextqueue
);
400 if (chmp
->chm_nextblock
) {
401 dbg_gc("nextblock num: %u - gcblock num: %u\n",
402 chmp
->chm_nextblock
->lnr
, ret
->lnr
);
403 if (ret
== chmp
->chm_nextblock
)
406 TAILQ_REMOVE(nextqueue
, ret
, queue
);
409 chmp
->chm_gcblock
= ret
;
411 ret
->gc_node
= ret
->first_node
;
414 dbg_gc("Oops! ret->gc_node at LEB: %u is NULL\n", ret
->lnr
);
415 panic("CHFS BUG - one LEB's gc_node is NULL\n");
418 /* TODO wasted size? */
422 /* chfs_gcollect_pass - this is the main function of GC */
424 chfs_gcollect_pass(struct chfs_mount
*chmp
)
426 struct chfs_vnode_cache
*vc
;
427 struct chfs_eraseblock
*eb
;
428 struct chfs_node_ref
*nref
;
429 uint32_t gcblock_dirty
;
430 struct chfs_inode
*ip
;
435 KASSERT(mutex_owned(&chmp
->chm_lock_mountfields
));
437 /* Check all vnodes. */
439 mutex_enter(&chmp
->chm_lock_sizes
);
441 /* Check unchecked size. */
442 dbg_gc("unchecked size == %u\n", chmp
->chm_unchecked_size
);
443 if (!chmp
->chm_unchecked_size
)
446 /* Compare vnode number to the maximum. */
447 if (chmp
->chm_checked_vno
> chmp
->chm_max_vno
) {
448 mutex_exit(&chmp
->chm_lock_sizes
);
449 dbg_gc("checked_vno (#%llu) > max_vno (#%llu)\n",
450 (unsigned long long)chmp
->chm_checked_vno
,
451 (unsigned long long)chmp
->chm_max_vno
);
455 mutex_exit(&chmp
->chm_lock_sizes
);
457 mutex_enter(&chmp
->chm_lock_vnocache
);
458 dbg_gc("checking vno #%llu\n",
459 (unsigned long long)chmp
->chm_checked_vno
);
460 dbg_gc("get vnode cache\n");
462 /* OK, Get and check the vnode cache. */
463 vc
= chfs_vnode_cache_get(chmp
, chmp
->chm_checked_vno
++);
467 mutex_exit(&chmp
->chm_lock_vnocache
);
471 if ((vc
->pvno
| vc
->nlink
) == 0) {
472 dbg_gc("(pvno | nlink) == 0\n");
473 mutex_exit(&chmp
->chm_lock_vnocache
);
477 /* Find out the state of the vnode. */
480 case VNO_STATE_CHECKEDABSENT
:
482 case VNO_STATE_PRESENT
:
483 mutex_exit(&chmp
->chm_lock_vnocache
);
488 case VNO_STATE_CHECKING
:
489 mutex_exit(&chmp
->chm_lock_vnocache
);
490 dbg_gc("VNO_STATE GC or CHECKING\n");
491 panic("CHFS BUG - vc state gc or checking\n");
493 case VNO_STATE_READING
:
494 chmp
->chm_checked_vno
--;
495 mutex_exit(&chmp
->chm_lock_vnocache
);
496 /* XXX why do we need the delay here?! */
497 kpause("chvncrea", true, mstohz(50), NULL
);
502 mutex_exit(&chmp
->chm_lock_vnocache
);
504 panic("CHFS BUG - vc state is other what we"
507 case VNO_STATE_UNCHECKED
:
511 /* We found an unchecked vnode. */
513 vc
->state
= VNO_STATE_CHECKING
;
515 /* XXX check if this is too heavy to call under
518 ret
= chfs_check(chmp
, vc
);
519 vc
->state
= VNO_STATE_CHECKEDABSENT
;
521 mutex_exit(&chmp
->chm_lock_vnocache
);
526 eb
= chmp
->chm_gcblock
;
529 eb
= find_gc_block(chmp
);
534 if (!TAILQ_EMPTY(&chmp
->chm_erase_pending_queue
)) {
535 mutex_exit(&chmp
->chm_lock_sizes
);
538 mutex_exit(&chmp
->chm_lock_sizes
);
542 if (!eb
->used_size
) {
543 dbg_gc("!eb->used_size\n");
549 gcblock_dirty
= eb
->dirty_size
;
551 /* Find a node which wasn't obsoleted yet.
552 * Obsoleted nodes will be simply deleted after the whole block has checked. */
553 while(CHFS_REF_OBSOLETE(nref
)) {
555 if (nref
== chmp
->chm_blocks
[nref
->nref_lnr
].last_node
) {
556 dbg_gc("THIS NODE IS THE LAST NODE OF ITS EB\n");
559 nref
= node_next(nref
);
562 mutex_exit(&chmp
->chm_lock_sizes
);
563 panic("CHFS BUG - nref is NULL)\n");
567 /* We found a "not obsoleted" node. */
569 KASSERT(nref
->nref_lnr
== chmp
->chm_gcblock
->lnr
);
571 /* Check if node is in any chain. */
572 if (!nref
->nref_next
) {
573 /* This node is not in any chain. Simply collect it, or obsolete. */
574 mutex_exit(&chmp
->chm_lock_sizes
);
575 if (CHFS_REF_FLAGS(nref
) == CHFS_PRISTINE_NODE_MASK
) {
576 chfs_gcollect_pristine(chmp
, eb
, NULL
, nref
);
578 chfs_mark_node_obsolete(chmp
, nref
);
583 mutex_exit(&chmp
->chm_lock_sizes
);
585 mutex_enter(&chmp
->chm_lock_vnocache
);
587 dbg_gc("nref lnr: %u - offset: %u\n", nref
->nref_lnr
, nref
->nref_offset
);
588 vc
= chfs_nref_to_vc(nref
);
590 /* Check the state of the node. */
593 case VNO_STATE_CHECKEDABSENT
:
594 if (CHFS_REF_FLAGS(nref
) == CHFS_PRISTINE_NODE_MASK
) {
595 vc
->state
= VNO_STATE_GC
;
599 case VNO_STATE_PRESENT
:
602 case VNO_STATE_UNCHECKED
:
604 case VNO_STATE_CHECKING
:
607 mutex_exit(&chmp
->chm_lock_vnocache
);
608 panic("CHFS BUG - vc state unchecked,"
609 " checking or gc (vno #%llu, num #%d)\n",
610 (unsigned long long)vc
->vno
, vc
->state
);
612 case VNO_STATE_READING
:
613 /* Node is in use at this time. */
614 mutex_exit(&chmp
->chm_lock_vnocache
);
615 kpause("chvncrea", true, mstohz(50), NULL
);
619 if (vc
->state
== VNO_STATE_GC
) {
620 dbg_gc("vc->state == VNO_STATE_GC\n");
621 vc
->state
= VNO_STATE_CHECKEDABSENT
;
622 mutex_exit(&chmp
->chm_lock_vnocache
);
623 ret
= chfs_gcollect_pristine(chmp
, eb
, NULL
, nref
);
625 //TODO wake_up(&chmp->chm_vnocache_wq);
628 mutex_enter(&chmp
->chm_lock_vnocache
);
631 /* Collect living node. */
635 mutex_exit(&chmp
->chm_lock_vnocache
);
637 ip
= chfs_gc_fetch_inode(chmp
, vno
, !(pvno
| nlink
));
645 chfs_gcollect_live(chmp
, eb
, nref
, ip
);
647 chfs_gc_release_inode(chmp
, ip
);
650 if (eb
->dirty_size
== gcblock_dirty
&&
651 !CHFS_REF_OBSOLETE(eb
->gc_node
)) {
652 dbg_gc("ERROR collecting node at %u failed.\n",
653 CHFS_GET_OFS(eb
->gc_node
->nref_offset
));
659 KASSERT(mutex_owned(&chmp
->chm_lock_mountfields
));
660 mutex_enter(&chmp
->chm_lock_sizes
);
664 if (chmp
->chm_gcblock
) {
665 /* This is only for debugging. */
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 /* Check the state of GC block. */
681 if (chmp
->chm_gcblock
&& chmp
->chm_gcblock
->dirty_size
+
682 chmp
->chm_gcblock
->wasted_size
== chmp
->chm_ebh
->eb_size
) {
683 dbg_gc("Block at leb #%u completely obsoleted by GC, "
684 "Moving to erase_pending_queue\n", chmp
->chm_gcblock
->lnr
);
685 TAILQ_INSERT_TAIL(&chmp
->chm_erase_pending_queue
,
686 chmp
->chm_gcblock
, queue
);
687 chmp
->chm_gcblock
= NULL
;
688 chmp
->chm_nr_erasable_blocks
++;
689 if (!TAILQ_EMPTY(&chmp
->chm_erase_pending_queue
)) {
690 ret
= chfs_remap_leb(chmp
);
694 mutex_exit(&chmp
->chm_lock_sizes
);
700 /* chfs_gcollect_pristine - collects a pristine node */
702 chfs_gcollect_pristine(struct chfs_mount
*chmp
, struct chfs_eraseblock
*cheb
,
703 struct chfs_vnode_cache
*chvc
, struct chfs_node_ref
*nref
)
705 struct chfs_node_ref
*newnref
;
706 struct chfs_flash_node_hdr
*nhdr
;
707 struct chfs_flash_vnode
*fvnode
;
708 struct chfs_flash_dirent_node
*fdirent
;
709 struct chfs_flash_data_node
*fdata
;
710 int ret
, retries
= 0;
712 size_t totlen
= chfs_nref_len(chmp
, cheb
, nref
);
717 dbg_gc("gcollect_pristine\n");
719 data
= kmem_alloc(totlen
, KM_SLEEP
);
723 ofs
= CHFS_GET_OFS(nref
->nref_offset
);
726 ret
= chfs_read_leb(chmp
, nref
->nref_lnr
, data
, ofs
, totlen
, &retlen
);
728 dbg_gc("reading error\n");
731 if (retlen
!= totlen
) {
732 dbg_gc("read size error\n");
735 nhdr
= (struct chfs_flash_node_hdr
*)data
;
737 /* Check the header. */
738 if (le16toh(nhdr
->magic
) != CHFS_FS_MAGIC_BITMASK
) {
739 dbg_gc("node header magic number error\n");
742 crc
= crc32(0, (uint8_t *)nhdr
, CHFS_NODE_HDR_SIZE
- 4);
743 if (crc
!= le32toh(nhdr
->hdr_crc
)) {
744 dbg_gc("node header crc error\n");
748 /* Read the remaining parts. */
749 switch(le16toh(nhdr
->type
)) {
750 case CHFS_NODETYPE_VNODE
:
751 /* vnode information node */
752 fvnode
= (struct chfs_flash_vnode
*)data
;
753 crc
= crc32(0, (uint8_t *)fvnode
, sizeof(struct chfs_flash_vnode
) - 4);
754 if (crc
!= le32toh(fvnode
->node_crc
)) {
755 dbg_gc("vnode crc error\n");
759 case CHFS_NODETYPE_DIRENT
:
761 fdirent
= (struct chfs_flash_dirent_node
*)data
;
762 crc
= crc32(0, (uint8_t *)fdirent
, sizeof(struct chfs_flash_dirent_node
) - 4);
763 if (crc
!= le32toh(fdirent
->node_crc
)) {
764 dbg_gc("dirent crc error\n");
767 crc
= crc32(0, fdirent
->name
, fdirent
->nsize
);
768 if (crc
!= le32toh(fdirent
->name_crc
)) {
769 dbg_gc("dirent name crc error\n");
773 case CHFS_NODETYPE_DATA
:
775 fdata
= (struct chfs_flash_data_node
*)data
;
776 crc
= crc32(0, (uint8_t *)fdata
, sizeof(struct chfs_flash_data_node
) - 4);
777 if (crc
!= le32toh(fdata
->node_crc
)) {
778 dbg_gc("data node crc error\n");
785 dbg_gc("unknown node have vnode cache\n");
789 /* CRC's OK, write node to its new place */
791 ret
= chfs_reserve_space_gc(chmp
, totlen
);
795 newnref
= chfs_alloc_node_ref(chmp
->chm_nextblock
);
799 ofs
= chmp
->chm_ebh
->eb_size
- chmp
->chm_nextblock
->free_size
;
800 newnref
->nref_offset
= ofs
;
802 /* write out the whole node */
803 vec
.iov_base
= (void *)data
;
804 vec
.iov_len
= totlen
;
805 mutex_enter(&chmp
->chm_lock_sizes
);
806 ret
= chfs_write_wbuf(chmp
, &vec
, 1, ofs
, &retlen
);
808 if (ret
|| retlen
!= totlen
) {
809 /* error while writing */
810 chfs_err("error while writing out to the media\n");
811 chfs_err("err: %d | size: %zu | retlen : %zu\n",
812 ret
, totlen
, retlen
);
814 chfs_change_size_dirty(chmp
, chmp
->chm_nextblock
, totlen
);
816 mutex_exit(&chmp
->chm_lock_sizes
);
822 mutex_exit(&chmp
->chm_lock_sizes
);
826 /* update vnode information */
827 mutex_exit(&chmp
->chm_lock_sizes
);
828 //TODO should we set free_size?
829 mutex_enter(&chmp
->chm_lock_vnocache
);
830 chfs_add_vnode_ref_to_vc(chmp
, chvc
, newnref
);
831 mutex_exit(&chmp
->chm_lock_vnocache
);
836 /* chfs_gcollect_live - collects a living node */
838 chfs_gcollect_live(struct chfs_mount
*chmp
,
839 struct chfs_eraseblock
*cheb
, struct chfs_node_ref
*nref
,
840 struct chfs_inode
*ip
)
842 struct chfs_node_frag
*frag
;
843 struct chfs_full_dnode
*fn
= NULL
;
844 int start
= 0, end
= 0, nrfrags
= 0;
845 struct chfs_dirent
*fd
= NULL
;
849 dbg_gc("gcollect_live\n");
851 if (chmp
->chm_gcblock
!= cheb
) {
852 dbg_gc("GC block is no longer gcblock. Restart.\n");
856 if (CHFS_REF_OBSOLETE(nref
)) {
857 dbg_gc("node to be GC'd was obsoleted in the meantime.\n");
862 if (ip
->chvc
->v
== nref
) {
863 chfs_gcollect_vnode(chmp
, ip
);
867 /* Find data node. */
868 dbg_gc("find full dnode\n");
869 for(frag
= frag_first(&ip
->fragtree
);
870 frag
; frag
= frag_next(&ip
->fragtree
, frag
)) {
871 if (frag
->node
&& frag
->node
->nref
== nref
) {
873 end
= frag
->ofs
+ frag
->size
;
876 if (nrfrags
== frag
->node
->frags
)
881 /* It's a pristine node, or dnode (or hole? XXX have we hole nodes?) */
883 if (CHFS_REF_FLAGS(nref
) == CHFS_PRISTINE_NODE_MASK
) {
884 ret
= chfs_gcollect_pristine(chmp
,
885 cheb
, ip
->chvc
, nref
);
887 frag
->node
->nref
= ip
->chvc
->v
;
892 ret
= chfs_gcollect_dnode(chmp
, cheb
, ip
, fn
, start
, end
);
896 /* Is it a dirent? */
897 dbg_gc("find full dirent\n");
899 TAILQ_FOREACH(fd
, &ip
->dents
, fds
) {
900 if (fd
->nref
== nref
) {
906 if (is_dirent
&& fd
->vno
) {
908 ret
= chfs_gcollect_dirent(chmp
, cheb
, ip
, fd
);
909 } else if (is_dirent
) {
910 /* Already deleted dirent. */
911 ret
= chfs_gcollect_deletion_dirent(chmp
, cheb
, ip
, fd
);
913 dbg_gc("Nref at leb #%u offset 0x%08x wasn't in node list"
915 nref
->nref_lnr
, CHFS_GET_OFS(nref
->nref_offset
),
916 (unsigned long long)ip
->ino
);
917 if (CHFS_REF_OBSOLETE(nref
)) {
918 dbg_gc("But it's obsolete so we don't mind"
927 /* chfs_gcollect_vnode - collects a vnode information node */
929 chfs_gcollect_vnode(struct chfs_mount
*chmp
, struct chfs_inode
*ip
)
932 dbg_gc("gcollect_vnode\n");
934 /* Simply write the new vnode information to the flash
935 * with GC's space allocation */
936 ret
= chfs_write_flash_vnode(chmp
, ip
, ALLOC_GC
);
941 /* chfs_gcollect_dirent - collects a dirent */
943 chfs_gcollect_dirent(struct chfs_mount
*chmp
,
944 struct chfs_eraseblock
*cheb
, struct chfs_inode
*parent
,
945 struct chfs_dirent
*fd
)
947 struct vnode
*vnode
= NULL
;
948 struct chfs_inode
*ip
;
949 dbg_gc("gcollect_dirent\n");
952 vnode
= chfs_vnode_lookup(chmp
, fd
->vno
);
954 /* XXX maybe KASSERT or panic on this? */
961 /* Remove and obsolete the previous version. */
962 mutex_enter(&chmp
->chm_lock_vnocache
);
963 chfs_remove_and_obsolete(chmp
, parent
->chvc
, fd
->nref
,
964 &parent
->chvc
->dirents
);
965 mutex_exit(&chmp
->chm_lock_vnocache
);
967 /* Write the new dirent to the flash. */
968 return chfs_write_flash_dirent(chmp
,
969 parent
, ip
, fd
, fd
->vno
, ALLOC_GC
);
973 * chfs_gcollect_deletion_dirent -
974 * collects a dirent what was marked as deleted
977 chfs_gcollect_deletion_dirent(struct chfs_mount
*chmp
,
978 struct chfs_eraseblock
*cheb
, struct chfs_inode
*parent
,
979 struct chfs_dirent
*fd
)
981 struct chfs_flash_dirent_node chfdn
;
982 struct chfs_node_ref
*nref
;
983 size_t retlen
, name_len
, nref_len
;
988 dbg_gc("gcollect_deletion_dirent\n");
991 name_len
= strlen(fd
->name
);
992 name_crc
= crc32(0, fd
->name
, name_len
);
994 nref_len
= chfs_nref_len(chmp
, cheb
, fd
->nref
);
996 (void)chfs_vnode_lookup(chmp
, fd
->vno
);
998 /* Find it in parent dirents. */
999 for (nref
= parent
->chvc
->dirents
;
1000 nref
!= (void*)parent
->chvc
;
1001 nref
= nref
->nref_next
) {
1003 if (!CHFS_REF_OBSOLETE(nref
))
1006 /* if node refs have different length, skip */
1007 if (chfs_nref_len(chmp
, NULL
, nref
) != nref_len
)
1010 if (CHFS_GET_OFS(nref
->nref_offset
) ==
1011 CHFS_GET_OFS(fd
->nref
->nref_offset
)) {
1015 /* read it from flash */
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 mutex_enter(&chmp
->chm_lock_vnocache
);
1050 chfs_remove_and_obsolete(chmp
, parent
->chvc
, fd
->nref
,
1051 &parent
->chvc
->dirents
);
1052 mutex_exit(&chmp
->chm_lock_vnocache
);
1053 return chfs_write_flash_dirent(chmp
,
1054 parent
, NULL
, fd
, fd
->vno
, ALLOC_GC
);
1057 /* Simply remove it from the parent dirents. */
1058 TAILQ_REMOVE(&parent
->dents
, fd
, fds
);
1059 chfs_free_dirent(fd
);
1063 /* chfs_gcollect_dnode - */
1065 chfs_gcollect_dnode(struct chfs_mount
*chmp
,
1066 struct chfs_eraseblock
*orig_cheb
, struct chfs_inode
*ip
,
1067 struct chfs_full_dnode
*fn
, uint32_t orig_start
, uint32_t orig_end
)
1069 struct chfs_node_ref
*nref
;
1070 struct chfs_full_dnode
*newfn
;
1071 struct chfs_flash_data_node
*fdnode
;
1072 int ret
= 0, retries
= 0;
1077 dbg_gc("gcollect_dnode\n");
1081 KASSERT(orig_cheb
->lnr
== fn
->nref
->nref_lnr
);
1082 totlen
= chfs_nref_len(chmp
, orig_cheb
, fn
->nref
);
1083 data
= kmem_alloc(totlen
, KM_SLEEP
);
1085 /* Read the node from the flash. */
1086 ret
= chfs_read_leb(chmp
, fn
->nref
->nref_lnr
, data
, fn
->nref
->nref_offset
,
1089 fdnode
= (struct chfs_flash_data_node
*)data
;
1090 fdnode
->version
= htole64(++ip
->chvc
->highest_version
);
1091 fdnode
->node_crc
= htole32(crc32(0, (uint8_t *)fdnode
,
1092 sizeof(*fdnode
) - 4));
1094 vec
.iov_base
= (void *)data
;
1095 vec
.iov_len
= totlen
;
1098 /* Set the next block where we can write. */
1099 ret
= chfs_reserve_space_gc(chmp
, totlen
);
1103 nref
= chfs_alloc_node_ref(chmp
->chm_nextblock
);
1109 mutex_enter(&chmp
->chm_lock_sizes
);
1111 nref
->nref_offset
= chmp
->chm_ebh
->eb_size
- chmp
->chm_nextblock
->free_size
;
1112 KASSERT(nref
->nref_offset
% 4 == 0);
1113 chfs_change_size_free(chmp
, chmp
->chm_nextblock
, -totlen
);
1115 /* Write it to the writebuffer. */
1116 ret
= chfs_write_wbuf(chmp
, &vec
, 1, nref
->nref_offset
, &retlen
);
1117 if (ret
|| retlen
!= totlen
) {
1118 /* error during writing */
1119 chfs_err("error while writing out to the media\n");
1120 chfs_err("err: %d | size: %d | retlen : %zu\n",
1121 ret
, totlen
, retlen
);
1122 chfs_change_size_dirty(chmp
, chmp
->chm_nextblock
, totlen
);
1125 mutex_exit(&chmp
->chm_lock_sizes
);
1131 mutex_exit(&chmp
->chm_lock_sizes
);
1135 dbg_gc("new nref lnr: %u - offset: %u\n", nref
->nref_lnr
, nref
->nref_offset
);
1137 chfs_change_size_used(chmp
, &chmp
->chm_blocks
[nref
->nref_lnr
], totlen
);
1138 mutex_exit(&chmp
->chm_lock_sizes
);
1139 KASSERT(chmp
->chm_blocks
[nref
->nref_lnr
].used_size
<= chmp
->chm_ebh
->eb_size
);
1141 /* Set fields of the new node. */
1142 newfn
= chfs_alloc_full_dnode();
1144 newfn
->ofs
= fn
->ofs
;
1145 newfn
->size
= fn
->size
;
1148 mutex_enter(&chmp
->chm_lock_vnocache
);
1149 /* Remove every part of the old node. */
1150 chfs_remove_frags_of_node(chmp
, &ip
->fragtree
, fn
->nref
);
1151 chfs_remove_and_obsolete(chmp
, ip
->chvc
, fn
->nref
, &ip
->chvc
->dnode
);
1153 /* Add the new nref to inode. */
1154 chfs_add_full_dnode_to_inode(chmp
, ip
, newfn
);
1155 chfs_add_node_to_list(chmp
,
1156 ip
->chvc
, newfn
->nref
, &ip
->chvc
->dnode
);
1157 mutex_exit(&chmp
->chm_lock_vnocache
);
1160 kmem_free(data
, totlen
);