chfs_gc.c revision 1.3 1 /* $NetBSD: chfs_gc.c,v 1.3 2012/08/10 09:26:58 ttoth Exp $ */
2
3 /*-
4 * Copyright (c) 2010 Department of Software Engineering,
5 * University of Szeged, Hungary
6 * Copyright (c) 2010 Tamas Toth <ttoth (at) inf.u-szeged.hu>
7 * Copyright (c) 2010 Adam Hoka <ahoka (at) NetBSD.org>
8 * All rights reserved.
9 *
10 * This code is derived from software contributed to The NetBSD Foundation
11 * by the Department of Software Engineering, University of Szeged, Hungary
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
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.
21 *
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
32 * SUCH DAMAGE.
33 */
34
35 #include "chfs.h"
36
37 void chfs_gc_release_inode(struct chfs_mount *,
38 struct chfs_inode *);
39 struct chfs_inode *chfs_gc_fetch_inode(struct chfs_mount *,
40 ino_t, uint32_t);
41 int chfs_check(struct chfs_mount *, struct chfs_vnode_cache *);
42 void chfs_clear_inode(struct chfs_mount *, struct chfs_inode *);
43
44
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 *,
51 struct chfs_inode *);
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);
62
63 /* must be called with chm_lock_mountfields held */
64 void
65 chfs_gc_trigger(struct chfs_mount *chmp)
66 {
67 struct garbage_collector_thread *gc = &chmp->chm_gc_thread;
68
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);
73 }
74 //mutex_exit(&chmp->chm_lock_sizes);
75 }
76
77
78 void
79 chfs_gc_thread(void *data)
80 {
81 struct chfs_mount *chmp = data;
82 struct garbage_collector_thread *gc = &chmp->chm_gc_thread;
83
84 dbg_gc("[GC THREAD] thread started\n");
85
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...
91 */
92 if (chfs_gc_thread_should_wake(chmp)) {
93 // mutex_exit(&chmp->chm_lock_mountfields);
94 if (chfs_gcollect_pass(chmp) == ENOSPC) {
95 mutex_exit(&chmp->chm_lock_mountfields);
96 dbg_gc("No space for garbage collection\n");
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
100 */
101 break;
102 }
103 /* XXX gcollect_pass drops the mutex */
104 //mutex_enter(&chmp->chm_lock_mountfields);
105 }
106
107 cv_timedwait_sig(&gc->gcth_wakeup,
108 &chmp->chm_lock_mountfields, mstohz(100));
109 }
110 mutex_exit(&chmp->chm_lock_mountfields);
111
112 dbg_gc("[GC THREAD] thread stopped\n");
113 kthread_exit(0);
114 }
115
116 void
117 chfs_gc_thread_start(struct chfs_mount *chmp)
118 {
119 struct garbage_collector_thread *gc = &chmp->chm_gc_thread;
120
121 cv_init(&gc->gcth_wakeup, "chfsgccv");
122
123 gc->gcth_running = true;
124 kthread_create(PRI_NONE, /*KTHREAD_MPSAFE |*/ KTHREAD_MUSTJOIN,
125 NULL, chfs_gc_thread, chmp, &gc->gcth_thread,
126 "chfsgcth");
127 }
128
129 void
130 chfs_gc_thread_stop(struct chfs_mount *chmp)
131 {
132 struct garbage_collector_thread *gc = &chmp->chm_gc_thread;
133
134 /* check if it is actually running. if not, do nothing */
135 if (gc->gcth_running) {
136 gc->gcth_running = false;
137 } else {
138 return;
139 }
140 cv_signal(&gc->gcth_wakeup);
141 dbg_gc("[GC THREAD] stop signal sent\n");
142
143 kthread_join(gc->gcth_thread);
144 #ifdef BROKEN_KTH_JOIN
145 kpause("chfsthjoin", false, mstohz(1000), NULL);
146 #endif
147
148 cv_destroy(&gc->gcth_wakeup);
149 }
150
151 /* must be called with chm_lock_mountfields held */
152 int
153 chfs_gc_thread_should_wake(struct chfs_mount *chmp)
154 {
155 int nr_very_dirty = 0;
156 struct chfs_eraseblock *cheb;
157 uint32_t dirty;
158
159 KASSERT(mutex_owned(&chmp->chm_lock_mountfields));
160
161 if (!TAILQ_EMPTY(&chmp->chm_erase_pending_queue)) {
162 dbg_gc("erase_pending\n");
163 return 1;
164 }
165
166 if (chmp->chm_unchecked_size) {
167 dbg_gc("unchecked\n");
168 return 1;
169 }
170
171 dirty = chmp->chm_dirty_size - chmp->chm_nr_erasable_blocks *
172 chmp->chm_ebh->eb_size;
173
174 if (chmp->chm_nr_free_blocks + chmp->chm_nr_erasable_blocks <
175 chmp->chm_resv_blocks_gctrigger && (dirty > chmp->chm_nospc_dirty)) {
176 dbg_gc("free: %d + erasable: %d < resv: %d\n",
177 chmp->chm_nr_free_blocks, chmp->chm_nr_erasable_blocks,
178 chmp->chm_resv_blocks_gctrigger);
179 dbg_gc("dirty: %d > nospc_dirty: %d\n",
180 dirty, chmp->chm_nospc_dirty);
181
182 return 1;
183 }
184
185 TAILQ_FOREACH(cheb, &chmp->chm_very_dirty_queue, queue) {
186 nr_very_dirty++;
187 if (nr_very_dirty == chmp->chm_vdirty_blocks_gctrigger) {
188 dbg_gc("nr_very_dirty\n");
189 return 1;
190 }
191 }
192
193 return 0;
194 }
195
196 void
197 chfs_gc_release_inode(struct chfs_mount *chmp,
198 struct chfs_inode *ip)
199 {
200 dbg_gc("release inode\n");
201 //mutex_exit(&ip->inode_lock);
202 //vput(ITOV(ip));
203 }
204
205 struct chfs_inode *
206 chfs_gc_fetch_inode(struct chfs_mount *chmp, ino_t vno,
207 uint32_t unlinked)
208 {
209 struct vnode *vp = NULL;
210 struct chfs_vnode_cache *vc;
211 struct chfs_inode *ip;
212 dbg_gc("fetch inode %llu\n", (unsigned long long)vno);
213
214 if (unlinked) {
215 dbg_gc("unlinked\n");
216 vp = chfs_vnode_lookup(chmp, vno);
217 if (!vp) {
218 mutex_enter(&chmp->chm_lock_vnocache);
219 vc = chfs_vnode_cache_get(chmp, vno);
220 if (!vc) {
221 mutex_exit(&chmp->chm_lock_vnocache);
222 return NULL;
223 }
224 if (vc->state != VNO_STATE_CHECKEDABSENT) {
225 //sleep_on_spinunlock(&chmp->chm_lock_vnocache);
226 mutex_exit(&chmp->chm_lock_vnocache);
227 /* XXX why do we need the delay here?! */
228 // kpause("chvncabs", true, mstohz(50), NULL);
229 KASSERT(mutex_owned(&chmp->chm_lock_mountfields));
230 cv_timedwait_sig(
231 &chmp->chm_gc_thread.gcth_wakeup,
232 &chmp->chm_lock_mountfields, mstohz(50));
233
234 // KASSERT(!mutex_owned(&chmp->chm_lock_vnocache));
235 } else {
236 mutex_exit(&chmp->chm_lock_vnocache);
237 }
238 return NULL;
239 }
240 } else {
241 dbg_gc("vnode lookup\n");
242 vp = chfs_vnode_lookup(chmp, vno);
243 //VFS_VGET(chmp->chm_fsmp, vno, &vp);
244 }
245 dbg_gc("vp to ip\n");
246 ip = VTOI(vp);
247 KASSERT(ip);
248 //mutex_enter(&ip->inode_lock);
249
250 return ip;
251 }
252
253 extern rb_tree_ops_t frag_rbtree_ops;
254
255 int
256 chfs_check(struct chfs_mount *chmp, struct chfs_vnode_cache *chvc)
257 {
258 KASSERT(mutex_owned(&chmp->chm_lock_vnocache));
259
260 struct chfs_inode *ip;
261 struct vnode *vp;
262 int ret;
263
264 ip = pool_get(&chfs_inode_pool, PR_WAITOK);
265 if (!ip) {
266 return ENOMEM;
267 }
268
269 vp = kmem_zalloc(sizeof(struct vnode), KM_SLEEP);
270
271 ip->chvc = chvc;
272 ip->vp = vp;
273
274 vp->v_data = ip;
275
276 rb_tree_init(&ip->fragtree, &frag_rbtree_ops);
277 TAILQ_INIT(&ip->dents);
278
279 mutex_exit(&chmp->chm_lock_vnocache);
280 ret = chfs_read_inode_internal(chmp, ip);
281 mutex_enter(&chmp->chm_lock_vnocache);
282 if (!ret) {
283 chfs_clear_inode(chmp, ip);
284 }
285
286 pool_put(&chfs_inode_pool, ip);
287
288 return ret;
289 }
290
291 void
292 chfs_clear_inode(struct chfs_mount *chmp, struct chfs_inode *ip)
293 {
294 KASSERT(mutex_owned(&chmp->chm_lock_vnocache));
295
296 struct chfs_dirent *fd, *tmpfd;
297 struct chfs_vnode_cache *chvc;
298 struct chfs_node_ref *nref;
299
300 chvc = ip->chvc;
301 /* shouldnt this be: */
302 //bool deleted = (chvc && !(chvc->pvno || chvc->nlink));
303 int deleted = (chvc && !(chvc->pvno | chvc->nlink));
304
305 if (chvc && chvc->state != VNO_STATE_CHECKING) {
306 chvc->state = VNO_STATE_CLEARING;
307 }
308
309 while (deleted && chvc->v != (struct chfs_node_ref *)chvc) {
310 nref = chvc->v;
311 chfs_remove_and_obsolete(chmp, chvc, nref, &chvc->v);
312 }
313
314 chfs_kill_fragtree(chmp, &ip->fragtree);
315
316 TAILQ_FOREACH_SAFE(fd, &ip->dents, fds, tmpfd) {
317 chfs_free_dirent(fd);
318 }
319
320 if (chvc && chvc->state == VNO_STATE_CHECKING) {
321 chvc->state = VNO_STATE_CHECKEDABSENT;
322 if ((struct chfs_vnode_cache *)chvc->v == chvc &&
323 (struct chfs_vnode_cache *)chvc->dirents == chvc &&
324 (struct chfs_vnode_cache *)chvc->dnode == chvc)
325 chfs_vnode_cache_remove(chmp, chvc);
326 }
327 }
328
329 struct chfs_eraseblock *
330 find_gc_block(struct chfs_mount *chmp)
331 {
332 struct chfs_eraseblock *ret;
333 struct chfs_eraseblock_queue *nextqueue;
334
335 KASSERT(mutex_owned(&chmp->chm_lock_mountfields));
336
337 struct timespec now;
338 vfs_timestamp(&now);
339
340 int n = now.tv_nsec % 128;
341
342 //dbg_gc("n = %d\n", n);
343 again:
344 /* if (!TAILQ_EMPTY(&chmp->chm_bad_used_queue) && chmp->chm_nr_free_blocks > chmp->chm_nr_resv_blocks_gcbad) {
345 dbg_gc("Picking block from bad_used_queue to GC next\n");
346 nextqueue = &chmp->chm_bad_used_queue;
347 } else */if (n<50 && !TAILQ_EMPTY(&chmp->chm_erase_pending_queue)) {
348 dbg_gc("Picking block from erase_pending_queue to GC next\n");
349 nextqueue = &chmp->chm_erase_pending_queue;
350 } else if (n<110 && !TAILQ_EMPTY(&chmp->chm_very_dirty_queue) ) {
351 dbg_gc("Picking block from very_dirty_queue to GC next\n");
352 nextqueue = &chmp->chm_very_dirty_queue;
353 } else if (n<126 && !TAILQ_EMPTY(&chmp->chm_dirty_queue) ) {
354 dbg_gc("Picking block from dirty_queue to GC next\n");
355 nextqueue = &chmp->chm_dirty_queue;
356 } else if (!TAILQ_EMPTY(&chmp->chm_clean_queue)) {
357 dbg_gc("Picking block from clean_queue to GC next\n");
358 nextqueue = &chmp->chm_clean_queue;
359 } else if (!TAILQ_EMPTY(&chmp->chm_dirty_queue)) {
360 dbg_gc("Picking block from dirty_queue to GC next"
361 " (clean_queue was empty)\n");
362 nextqueue = &chmp->chm_dirty_queue;
363 } else if (!TAILQ_EMPTY(&chmp->chm_very_dirty_queue)) {
364 dbg_gc("Picking block from very_dirty_queue to GC next"
365 " (clean_queue and dirty_queue were empty)\n");
366 nextqueue = &chmp->chm_very_dirty_queue;
367 } else if (!TAILQ_EMPTY(&chmp->chm_erase_pending_queue)) {
368 dbg_gc("Picking block from erase_pending_queue to GC next"
369 " (clean_queue and {very_,}dirty_queue were empty)\n");
370 nextqueue = &chmp->chm_erase_pending_queue;
371 } else if (!TAILQ_EMPTY(&chmp->chm_erasable_pending_wbuf_queue)) {
372 dbg_gc("Synching wbuf in order to reuse "
373 "erasable_pendig_wbuf_queue blocks\n");
374 rw_enter(&chmp->chm_lock_wbuf, RW_WRITER);
375 chfs_flush_pending_wbuf(chmp);
376 rw_exit(&chmp->chm_lock_wbuf);
377 goto again;
378 } else {
379 dbg_gc("CHFS: no clean, dirty _or_ erasable"
380 " blocks to GC from! Where are they all?\n");
381 return NULL;
382 }
383
384 ret = TAILQ_FIRST(nextqueue);
385 if (chmp->chm_nextblock) {
386 dbg_gc("nextblock num: %u - gcblock num: %u\n",
387 chmp->chm_nextblock->lnr, ret->lnr);
388 if (ret == chmp->chm_nextblock)
389 goto again;
390 //KASSERT(ret != chmp->chm_nextblock);
391 //dbg_gc("first node lnr: %u ofs: %u\n", ret->first_node->lnr, ret->first_node->offset);
392 //dbg_gc("last node lnr: %u ofs: %u\n", ret->last_node->lnr, ret->last_node->offset);
393 }
394 TAILQ_REMOVE(nextqueue, ret, queue);
395 chmp->chm_gcblock = ret;
396 ret->gc_node = ret->first_node;
397
398 if (!ret->gc_node) {
399 dbg_gc("Oops! ret->gc_node at LEB: %u is NULL\n", ret->lnr);
400 panic("CHFS BUG - one LEB's gc_node is NULL\n");
401 }
402
403 /* TODO wasted size? */
404 return ret;
405 }
406
407
408 int
409 chfs_gcollect_pass(struct chfs_mount *chmp)
410 {
411 struct chfs_vnode_cache *vc;
412 struct chfs_eraseblock *eb;
413 struct chfs_node_ref *nref;
414 uint32_t gcblock_dirty;
415 struct chfs_inode *ip;
416 ino_t vno, pvno;
417 uint32_t nlink;
418 int ret = 0;
419
420 KASSERT(mutex_owned(&chmp->chm_lock_mountfields));
421
422 for (;;) {
423 mutex_enter(&chmp->chm_lock_sizes);
424
425 dbg_gc("unchecked size == %u\n", chmp->chm_unchecked_size);
426 if (!chmp->chm_unchecked_size)
427 break;
428
429 if (chmp->chm_checked_vno > chmp->chm_max_vno) {
430 mutex_exit(&chmp->chm_lock_sizes);
431 dbg_gc("checked_vno (#%llu) > max_vno (#%llu)\n",
432 (unsigned long long)chmp->chm_checked_vno,
433 (unsigned long long)chmp->chm_max_vno);
434 return ENOSPC;
435 }
436
437 mutex_exit(&chmp->chm_lock_sizes);
438
439 mutex_enter(&chmp->chm_lock_vnocache);
440 dbg_gc("checking vno #%llu\n",
441 (unsigned long long)chmp->chm_checked_vno);
442 dbg_gc("get vnode cache\n");
443 vc = chfs_vnode_cache_get(chmp, chmp->chm_checked_vno++);
444
445 if (!vc) {
446 dbg_gc("!vc\n");
447 mutex_exit(&chmp->chm_lock_vnocache);
448 continue;
449 }
450
451 if ((vc->pvno | vc->nlink) == 0) {
452 dbg_gc("(pvno | nlink) == 0\n");
453 mutex_exit(&chmp->chm_lock_vnocache);
454 continue;
455 }
456
457 dbg_gc("switch\n");
458 switch (vc->state) {
459 case VNO_STATE_CHECKEDABSENT:
460 case VNO_STATE_PRESENT:
461 mutex_exit(&chmp->chm_lock_vnocache);
462 continue;
463
464 case VNO_STATE_GC:
465 case VNO_STATE_CHECKING:
466 mutex_exit(&chmp->chm_lock_vnocache);
467 dbg_gc("VNO_STATE GC or CHECKING\n");
468 panic("CHFS BUG - vc state gc or checking\n");
469
470 case VNO_STATE_READING:
471 chmp->chm_checked_vno--;
472 mutex_exit(&chmp->chm_lock_vnocache);
473 /* XXX why do we need the delay here?! */
474 kpause("chvncrea", true, mstohz(50), NULL);
475
476 // sleep_on_spinunlock(&chmp->chm_lock_vnocache);
477 // KASSERT(!mutex_owned(&chmp->chm_lock_vnocache));
478 return 0;
479
480 default:
481 mutex_exit(&chmp->chm_lock_vnocache);
482 dbg_gc("default\n");
483 panic("CHFS BUG - vc state is other what we"
484 " checked\n");
485
486 case VNO_STATE_UNCHECKED:
487 ;
488 }
489
490 vc->state = VNO_STATE_CHECKING;
491
492 /* XXX check if this is too heavy to call under
493 * chm_lock_vnocache
494 */
495 ret = chfs_check(chmp, vc);
496 dbg_gc("set state\n");
497 vc->state = VNO_STATE_CHECKEDABSENT;
498
499 mutex_exit(&chmp->chm_lock_vnocache);
500 return ret;
501 }
502
503
504 eb = chmp->chm_gcblock;
505
506 if (!eb) {
507 eb = find_gc_block(chmp);
508 }
509
510 if (!eb) {
511 dbg_gc("!eb\n");
512 if (!TAILQ_EMPTY(&chmp->chm_erase_pending_queue)) {
513 mutex_exit(&chmp->chm_lock_sizes);
514 return EAGAIN;
515 }
516 mutex_exit(&chmp->chm_lock_sizes);
517 return EIO;
518 }
519
520 if (!eb->used_size) {
521 dbg_gc("!eb->used_size\n");
522 goto eraseit;
523 }
524
525 nref = eb->gc_node;
526 //dbg_gc("gc use: %u\n", chmp->chm_nextblock->lnr);
527 //dbg_gc("nref: %u %u\n", nref->nref_lnr, nref->nref_offset);
528 gcblock_dirty = eb->dirty_size;
529
530 while(CHFS_REF_OBSOLETE(nref)) {
531 //dbg_gc("obsoleted nref lnr: %u - offset: %u\n", nref->nref_lnr, nref->nref_offset);
532 #ifdef DBG_MSG_GC
533 if (nref == chmp->chm_blocks[nref->nref_lnr].last_node) {
534 dbg_gc("THIS NODE IS THE LAST NODE OF ITS EB\n");
535 }
536 #endif
537 nref = node_next(nref);
538 if (!nref) {
539 //dbg_gc("!nref\n");
540 eb->gc_node = nref;
541 mutex_exit(&chmp->chm_lock_sizes);
542 panic("CHFS BUG - nref is NULL)\n");
543 }
544 }
545 eb->gc_node = nref;
546 //dbg_gc("nref the chosen one lnr: %u - offset: %u\n", nref->nref_lnr, nref->nref_offset);
547 KASSERT(nref->nref_lnr == chmp->chm_gcblock->lnr);
548
549 if (!nref->nref_next) {
550 //dbg_gc("!nref->nref_next\n");
551 mutex_exit(&chmp->chm_lock_sizes);
552 if (CHFS_REF_FLAGS(nref) == CHFS_PRISTINE_NODE_MASK) {
553 chfs_gcollect_pristine(chmp, eb, NULL, nref);
554 } else {
555 chfs_mark_node_obsolete(chmp, nref);
556 }
557 goto lock_size;
558 }
559
560 mutex_exit(&chmp->chm_lock_sizes);
561
562 //dbg_gc("enter vnocache lock on #%llu\n", vc->vno);
563 mutex_enter(&chmp->chm_lock_vnocache);
564
565 dbg_gc("nref lnr: %u - offset: %u\n", nref->nref_lnr, nref->nref_offset);
566 vc = chfs_nref_to_vc(nref);
567
568 dbg_gc("switch\n");
569 switch(vc->state) {
570 case VNO_STATE_CHECKEDABSENT:
571 if (CHFS_REF_FLAGS(nref) == CHFS_PRISTINE_NODE_MASK) {
572 vc->state = VNO_STATE_GC;
573 }
574 break;
575
576 case VNO_STATE_PRESENT:
577 break;
578
579 case VNO_STATE_UNCHECKED:
580 case VNO_STATE_CHECKING:
581 case VNO_STATE_GC:
582 mutex_exit(&chmp->chm_lock_vnocache);
583 panic("CHFS BUG - vc state unchecked,"
584 " checking or gc (vno #%llu, num #%d)\n",
585 (unsigned long long)vc->vno, vc->state);
586
587 case VNO_STATE_READING:
588 mutex_exit(&chmp->chm_lock_vnocache);
589 /* XXX why do we need the delay here?! */
590 kpause("chvncrea", true, mstohz(50), NULL);
591
592 // sleep_on_spinunlock(&chmp->chm_lock_vnocache);
593 // KASSERT(!mutex_owned(&chmp->chm_lock_vnocache));
594 return 0;
595 }
596
597 if (vc->state == VNO_STATE_GC) {
598 dbg_gc("vc->state == VNO_STATE_GC\n");
599 vc->state = VNO_STATE_CHECKEDABSENT;
600 mutex_exit(&chmp->chm_lock_vnocache);
601 ret = chfs_gcollect_pristine(chmp, eb, NULL, nref);
602
603 //TODO wake_up(&chmp->chm_vnocache_wq);
604 if (ret != EBADF)
605 goto test_gcnode;
606 mutex_enter(&chmp->chm_lock_vnocache);
607 }
608
609 vno = vc->vno;
610 pvno = vc->pvno;
611 nlink = vc->nlink;
612 mutex_exit(&chmp->chm_lock_vnocache);
613
614 ip = chfs_gc_fetch_inode(chmp, vno, !(pvno | nlink));
615
616 if (!ip) {
617 dbg_gc("!ip\n");
618 ret = 0;
619 goto lock_size;
620 }
621
622 chfs_gcollect_live(chmp, eb, nref, ip);
623
624 chfs_gc_release_inode(chmp, ip);
625
626 test_gcnode:
627 if (eb->dirty_size == gcblock_dirty &&
628 !CHFS_REF_OBSOLETE(eb->gc_node)) {
629 dbg_gc("ERROR collecting node at %u failed.\n",
630 CHFS_GET_OFS(eb->gc_node->nref_offset));
631
632 ret = ENOSPC;
633 }
634
635 lock_size:
636 KASSERT(mutex_owned(&chmp->chm_lock_mountfields));
637 mutex_enter(&chmp->chm_lock_sizes);
638 eraseit:
639 dbg_gc("eraseit\n");
640
641 if (chmp->chm_gcblock) {
642 dbg_gc("eb used size = %u\n", chmp->chm_gcblock->used_size);
643 dbg_gc("eb free size = %u\n", chmp->chm_gcblock->free_size);
644 dbg_gc("eb dirty size = %u\n", chmp->chm_gcblock->dirty_size);
645 dbg_gc("eb unchecked size = %u\n",
646 chmp->chm_gcblock->unchecked_size);
647 dbg_gc("eb wasted size = %u\n", chmp->chm_gcblock->wasted_size);
648
649 KASSERT(chmp->chm_gcblock->used_size + chmp->chm_gcblock->free_size +
650 chmp->chm_gcblock->dirty_size +
651 chmp->chm_gcblock->unchecked_size +
652 chmp->chm_gcblock->wasted_size == chmp->chm_ebh->eb_size);
653
654 }
655
656 if (chmp->chm_gcblock && chmp->chm_gcblock->dirty_size +
657 chmp->chm_gcblock->wasted_size == chmp->chm_ebh->eb_size) {
658 dbg_gc("Block at leb #%u completely obsoleted by GC, "
659 "Moving to erase_pending_queue\n", chmp->chm_gcblock->lnr);
660 TAILQ_INSERT_TAIL(&chmp->chm_erase_pending_queue,
661 chmp->chm_gcblock, queue);
662 chmp->chm_gcblock = NULL;
663 chmp->chm_nr_erasable_blocks++;
664 if (!TAILQ_EMPTY(&chmp->chm_erase_pending_queue)) {
665 ret = chfs_remap_leb(chmp);
666 }
667 }
668
669 mutex_exit(&chmp->chm_lock_sizes);
670 dbg_gc("return\n");
671 return ret;
672 }
673
674
675 int
676 chfs_gcollect_pristine(struct chfs_mount *chmp, struct chfs_eraseblock *cheb,
677 struct chfs_vnode_cache *chvc, struct chfs_node_ref *nref)
678 {
679 struct chfs_node_ref *newnref;
680 struct chfs_flash_node_hdr *nhdr;
681 struct chfs_flash_vnode *fvnode;
682 struct chfs_flash_dirent_node *fdirent;
683 struct chfs_flash_data_node *fdata;
684 int ret, retries = 0;
685 uint32_t ofs, crc;
686 size_t totlen = chfs_nref_len(chmp, cheb, nref);
687 char *data;
688 struct iovec vec;
689 size_t retlen;
690
691 dbg_gc("gcollect_pristine\n");
692
693 data = kmem_alloc(totlen, KM_SLEEP);
694 if (!data)
695 return ENOMEM;
696
697 ofs = CHFS_GET_OFS(nref->nref_offset);
698
699 ret = chfs_read_leb(chmp, nref->nref_lnr, data, ofs, totlen, &retlen);
700 if (ret) {
701 dbg_gc("reading error\n");
702 return ret;
703 }
704 if (retlen != totlen) {
705 dbg_gc("read size error\n");
706 return EIO;
707 }
708 nhdr = (struct chfs_flash_node_hdr *)data;
709 /* check the header */
710 if (le16toh(nhdr->magic) != CHFS_FS_MAGIC_BITMASK) {
711 dbg_gc("node header magic number error\n");
712 return EBADF;
713 }
714 crc = crc32(0, (uint8_t *)nhdr, CHFS_NODE_HDR_SIZE - 4);
715 if (crc != le32toh(nhdr->hdr_crc)) {
716 dbg_gc("node header crc error\n");
717 return EBADF;
718 }
719
720 switch(le16toh(nhdr->type)) {
721 case CHFS_NODETYPE_VNODE:
722 fvnode = (struct chfs_flash_vnode *)data;
723 crc = crc32(0, (uint8_t *)fvnode, sizeof(struct chfs_flash_vnode) - 4);
724 if (crc != le32toh(fvnode->node_crc)) {
725 dbg_gc("vnode crc error\n");
726 return EBADF;
727 }
728 break;
729 case CHFS_NODETYPE_DIRENT:
730 fdirent = (struct chfs_flash_dirent_node *)data;
731 crc = crc32(0, (uint8_t *)fdirent, sizeof(struct chfs_flash_dirent_node) - 4);
732 if (crc != le32toh(fdirent->node_crc)) {
733 dbg_gc("dirent crc error\n");
734 return EBADF;
735 }
736 crc = crc32(0, fdirent->name, fdirent->nsize);
737 if (crc != le32toh(fdirent->name_crc)) {
738 dbg_gc("dirent name crc error\n");
739 return EBADF;
740 }
741 break;
742 case CHFS_NODETYPE_DATA:
743 fdata = (struct chfs_flash_data_node *)data;
744 crc = crc32(0, (uint8_t *)fdata, sizeof(struct chfs_flash_data_node) - 4);
745 if (crc != le32toh(fdata->node_crc)) {
746 dbg_gc("data node crc error\n");
747 return EBADF;
748 }
749 break;
750 default:
751 if (chvc) {
752 dbg_gc("unknown node have vnode cache\n");
753 return EBADF;
754 }
755 }
756 /* CRC's OK, write node to its new place */
757 retry:
758 ret = chfs_reserve_space_gc(chmp, totlen);
759 if (ret)
760 return ret;
761
762 newnref = chfs_alloc_node_ref(chmp->chm_nextblock);
763 if (!newnref)
764 return ENOMEM;
765
766 ofs = chmp->chm_ebh->eb_size - chmp->chm_nextblock->free_size;
767 newnref->nref_offset = ofs;
768
769 vec.iov_base = (void *)data;
770 vec.iov_len = totlen;
771 mutex_enter(&chmp->chm_lock_sizes);
772 ret = chfs_write_wbuf(chmp, &vec, 1, ofs, &retlen);
773
774 if (ret || retlen != totlen) {
775 chfs_err("error while writing out to the media\n");
776 chfs_err("err: %d | size: %zu | retlen : %zu\n",
777 ret, totlen, retlen);
778
779 chfs_change_size_dirty(chmp, chmp->chm_nextblock, totlen);
780 if (retries) {
781 mutex_exit(&chmp->chm_lock_sizes);
782 return EIO;
783 }
784
785 retries++;
786 mutex_exit(&chmp->chm_lock_sizes);
787 goto retry;
788 }
789
790 mutex_exit(&chmp->chm_lock_sizes);
791 //TODO should we set free_size?
792 //chfs_mark_node_obsolete(chmp, nref);
793 mutex_enter(&chmp->chm_lock_vnocache);
794 chfs_add_vnode_ref_to_vc(chmp, chvc, newnref);
795 mutex_exit(&chmp->chm_lock_vnocache);
796 return 0;
797 }
798
799
800 int
801 chfs_gcollect_live(struct chfs_mount *chmp,
802 struct chfs_eraseblock *cheb, struct chfs_node_ref *nref,
803 struct chfs_inode *ip)
804 {
805 struct chfs_node_frag *frag;
806 struct chfs_full_dnode *fn = NULL;
807 int start = 0, end = 0, nrfrags = 0;
808 struct chfs_dirent *fd = NULL;
809 int ret = 0;
810 bool is_dirent;
811
812 dbg_gc("gcollect_live\n");
813
814 if (chmp->chm_gcblock != cheb) {
815 dbg_gc("GC block is no longer gcblock. Restart.\n");
816 goto upnout;
817 }
818
819 if (CHFS_REF_OBSOLETE(nref)) {
820 dbg_gc("node to be GC'd was obsoleted in the meantime.\n");
821 goto upnout;
822 }
823
824 /* It's a vnode? */
825 if (ip->chvc->v == nref) {
826 chfs_gcollect_vnode(chmp, ip);
827 goto upnout;
828 }
829
830 /* find fn */
831 dbg_gc("find full dnode\n");
832 for(frag = frag_first(&ip->fragtree);
833 frag; frag = frag_next(&ip->fragtree, frag)) {
834 if (frag->node && frag->node->nref == nref) {
835 fn = frag->node;
836 end = frag->ofs + frag->size;
837 if (!nrfrags++)
838 start = frag->ofs;
839 if (nrfrags == frag->node->frags)
840 break;
841 }
842 }
843
844 /* It's a pristine node, or dnode (or hole? XXX have we hole nodes?) */
845 if (fn) {
846 if (CHFS_REF_FLAGS(nref) == CHFS_PRISTINE_NODE_MASK) {
847 ret = chfs_gcollect_pristine(chmp,
848 cheb, ip->chvc, nref);
849 if (!ret) {
850 frag->node->nref = ip->chvc->v;
851 }
852 if (ret != EBADF)
853 goto upnout;
854 }
855 //ret = chfs_gcollect_hole(chmp, cheb, ip, fn, start, end);
856 ret = chfs_gcollect_dnode(chmp, cheb, ip, fn, start, end);
857 goto upnout;
858 }
859
860
861 /* Is it a dirent? */
862 dbg_gc("find full dirent\n");
863 is_dirent = false;
864 TAILQ_FOREACH(fd, &ip->dents, fds) {
865 if (fd->nref == nref) {
866 is_dirent = true;
867 break;
868 }
869 }
870
871 if (is_dirent && fd->vno) {
872 ret = chfs_gcollect_dirent(chmp, cheb, ip, fd);
873 } else if (is_dirent) {
874 ret = chfs_gcollect_deletion_dirent(chmp, cheb, ip, fd);
875 } else {
876 dbg_gc("Nref at leb #%u offset 0x%08x wasn't in node list"
877 " for ino #%llu\n",
878 nref->nref_lnr, CHFS_GET_OFS(nref->nref_offset),
879 (unsigned long long)ip->ino);
880 if (CHFS_REF_OBSOLETE(nref)) {
881 dbg_gc("But it's obsolete so we don't mind"
882 " too much.\n");
883 }
884 }
885
886 upnout:
887 return ret;
888 }
889
890 int
891 chfs_gcollect_vnode(struct chfs_mount *chmp, struct chfs_inode *ip)
892 {
893 int ret;
894 dbg_gc("gcollect_vnode\n");
895
896 ret = chfs_write_flash_vnode(chmp, ip, ALLOC_GC);
897
898 return ret;
899 }
900
901 int
902 chfs_gcollect_dirent(struct chfs_mount *chmp,
903 struct chfs_eraseblock *cheb, struct chfs_inode *parent,
904 struct chfs_dirent *fd)
905 {
906 struct vnode *vnode = NULL;
907 struct chfs_inode *ip;
908 dbg_gc("gcollect_dirent\n");
909
910 vnode = chfs_vnode_lookup(chmp, fd->vno);
911
912 /* XXX maybe KASSERT or panic on this? */
913 if (vnode == NULL) {
914 return ENOENT;
915 }
916
917 ip = VTOI(vnode);
918
919 mutex_enter(&chmp->chm_lock_vnocache);
920 chfs_remove_and_obsolete(chmp, parent->chvc, fd->nref,
921 &parent->chvc->dirents);
922 mutex_exit(&chmp->chm_lock_vnocache);
923
924 return chfs_write_flash_dirent(chmp,
925 parent, ip, fd, fd->vno, ALLOC_GC);
926 }
927
928 /* Check dirents what are marked as deleted. */
929 int
930 chfs_gcollect_deletion_dirent(struct chfs_mount *chmp,
931 struct chfs_eraseblock *cheb, struct chfs_inode *parent,
932 struct chfs_dirent *fd)
933 {
934 struct chfs_flash_dirent_node chfdn;
935 struct chfs_node_ref *nref;
936 size_t retlen, name_len, nref_len;
937 uint32_t name_crc;
938
939 int ret;
940
941 struct vnode *vnode = NULL;
942
943 dbg_gc("gcollect_deletion_dirent\n");
944
945 name_len = strlen(fd->name);
946 name_crc = crc32(0, fd->name, name_len);
947
948 nref_len = chfs_nref_len(chmp, cheb, fd->nref);
949
950 vnode = chfs_vnode_lookup(chmp, fd->vno);
951
952 //dbg_gc("ip from vnode\n");
953 //VFS_VGET(chmp->chm_fsmp, fd->vno, &vnode);
954 //ip = VTOI(vnode);
955 //vput(vnode);
956
957 //dbg_gc("mutex enter erase_completion_lock\n");
958
959 // dbg_gc("alloc chfdn\n");
960 // chfdn = kmem_alloc(nref_len, KM_SLEEP);
961 // if (!chfdn)
962 // return ENOMEM;
963
964 for (nref = parent->chvc->dirents;
965 nref != (void*)parent->chvc;
966 nref = nref->nref_next) {
967
968 if (!CHFS_REF_OBSOLETE(nref))
969 continue;
970
971 /* if node refs have different length, skip */
972 if (chfs_nref_len(chmp, NULL, nref) != nref_len)
973 continue;
974
975 if (CHFS_GET_OFS(nref->nref_offset) ==
976 CHFS_GET_OFS(fd->nref->nref_offset)) {
977 continue;
978 }
979
980 ret = chfs_read_leb(chmp,
981 nref->nref_lnr, (void*)&chfdn, CHFS_GET_OFS(nref->nref_offset),
982 nref_len, &retlen);
983
984 if (ret) {
985 dbg_gc("Read error: %d\n", ret);
986 continue;
987 }
988
989 if (retlen != nref_len) {
990 dbg_gc("Error reading node:"
991 " read: %zu insted of: %zu\n", retlen, nref_len);
992 continue;
993 }
994
995 /* if node type doesn't match, skip */
996 if (le16toh(chfdn.type) != CHFS_NODETYPE_DIRENT)
997 continue;
998
999 /* if crc doesn't match, skip */
1000 if (le32toh(chfdn.name_crc) != name_crc)
1001 continue;
1002
1003 /* if length of name different, or this is an another deletion
1004 * dirent, skip
1005 */
1006 if (chfdn.nsize != name_len || !le64toh(chfdn.vno))
1007 continue;
1008
1009 /* check actual name */
1010 if (memcmp(chfdn.name, fd->name, name_len))
1011 continue;
1012
1013 // kmem_free(chfdn, nref_len);
1014
1015 mutex_enter(&chmp->chm_lock_vnocache);
1016 chfs_remove_and_obsolete(chmp, parent->chvc, fd->nref,
1017 &parent->chvc->dirents);
1018 mutex_exit(&chmp->chm_lock_vnocache);
1019 //chfs_mark_node_obsolete(chmp, fd->nref);
1020 return chfs_write_flash_dirent(chmp,
1021 parent, NULL, fd, fd->vno, ALLOC_GC);
1022 }
1023
1024 // kmem_free(chfdn, nref_len);
1025
1026 TAILQ_REMOVE(&parent->dents, fd, fds);
1027 chfs_free_dirent(fd);
1028 return 0;
1029 }
1030
1031 int
1032 chfs_gcollect_dnode(struct chfs_mount *chmp,
1033 struct chfs_eraseblock *orig_cheb, struct chfs_inode *ip,
1034 struct chfs_full_dnode *fn, uint32_t orig_start, uint32_t orig_end)
1035 {
1036 struct chfs_node_ref *nref;
1037 //struct chfs_node_ref *prev;
1038 struct chfs_full_dnode *newfn;
1039 struct chfs_flash_data_node *fdnode;
1040 int ret = 0, retries = 0;
1041 uint32_t totlen;
1042 char *data = NULL;
1043 struct iovec vec;
1044 size_t retlen;
1045 dbg_gc("gcollect_dnode\n");
1046
1047 //uint32_t used_size;
1048
1049 /* TODO GC merging frags, should we use it?
1050
1051 uint32_t start, end;
1052
1053 start = orig_start;
1054 end = orig_end;
1055
1056 if (chmp->chm_nr_free_blocks + chmp->chm_nr_erasable_blocks > chmp->chm_resv_blocks_gcmerge) {
1057 struct chfs_node_frag *frag;
1058 uint32_t min, max;
1059
1060 min = start & (PAGE_CACHE_SIZE-1);
1061 max = min + PAGE_CACHE_SIZE;
1062
1063 frag = (struct chfs_node_frag *)rb_tree_find_node_leq(&ip->i_chfs_ext.fragtree, &start);
1064 KASSERT(frag->ofs == start);
1065
1066 while ((frag = frag_prev(&ip->i_chfs_ext.fragtree, frag)) && frag->ofs >= min) {
1067 if (frag->ofs > min) {
1068 start = frag->ofs;
1069 continue;
1070 }
1071
1072 if (!frag->node || !frag->node->nref) {
1073 break;
1074 } else {
1075 struct chfs_node_ref *nref = frag->node->nref;
1076 struct chfs_eraseblock *cheb;
1077
1078 cheb = &chmp->chm_blocks[nref->nref_lnr];
1079
1080 if (cheb == chmp->chm_gcblock)
1081 start = frag->ofs;
1082
1083 //TODO is this a clean block?
1084
1085 start = frag->ofs;
1086 break;
1087 }
1088 }
1089
1090 end--;
1091 frag = (struct chfs_node_frag *)rb_tree_find_node_leq(&ip->i_chfs_ext.fragtree, &(end));
1092
1093 while ((frag = frag_next(&ip->i_chfs_ext.fragtree, frag)) && (frag->ofs + frag->size <= max)) {
1094 if (frag->ofs + frag->size < max) {
1095 end = frag->ofs + frag->size;
1096 continue;
1097 }
1098
1099 if (!frag->node || !frag->node->nref) {
1100 break;
1101 } else {
1102 struct chfs_node_ref *nref = frag->node->nref;
1103 struct chfs_eraseblock *cheb;
1104
1105 cheb = &chmp->chm_blocks[nref->nref_lnr];
1106
1107 if (cheb == chmp->chm_gcblock)
1108 end = frag->ofs + frag->size;
1109
1110 //TODO is this a clean block?
1111
1112 end = frag->ofs + frag->size;
1113 break;
1114 }
1115 }
1116
1117 KASSERT(end <=
1118 frag_last(&ip->i_chfs_ext.fragtree)->ofs +
1119 frag_last(&ip->i_chfs_ext.fragtree)->size);
1120 KASSERT(end >= orig_end);
1121 KASSERT(start <= orig_start);
1122 }
1123 */
1124 KASSERT(orig_cheb->lnr == fn->nref->nref_lnr);
1125 totlen = chfs_nref_len(chmp, orig_cheb, fn->nref);
1126 data = kmem_alloc(totlen, KM_SLEEP);
1127
1128 ret = chfs_read_leb(chmp, fn->nref->nref_lnr, data, fn->nref->nref_offset,
1129 totlen, &retlen);
1130
1131 fdnode = (struct chfs_flash_data_node *)data;
1132 fdnode->version = htole64(++ip->chvc->highest_version);
1133 fdnode->node_crc = htole32(crc32(0, (uint8_t *)fdnode,
1134 sizeof(*fdnode) - 4));
1135
1136 vec.iov_base = (void *)data;
1137 vec.iov_len = totlen;
1138
1139 retry:
1140 ret = chfs_reserve_space_gc(chmp, totlen);
1141 if (ret)
1142 goto out;
1143
1144 nref = chfs_alloc_node_ref(chmp->chm_nextblock);
1145 if (!nref) {
1146 ret = ENOMEM;
1147 goto out;
1148 }
1149
1150 mutex_enter(&chmp->chm_lock_sizes);
1151
1152 nref->nref_offset = chmp->chm_ebh->eb_size - chmp->chm_nextblock->free_size;
1153 KASSERT(nref->nref_offset % 4 == 0);
1154 chfs_change_size_free(chmp, chmp->chm_nextblock, -totlen);
1155
1156 ret = chfs_write_wbuf(chmp, &vec, 1, nref->nref_offset, &retlen);
1157 if (ret || retlen != totlen) {
1158 chfs_err("error while writing out to the media\n");
1159 chfs_err("err: %d | size: %d | retlen : %zu\n",
1160 ret, totlen, retlen);
1161 chfs_change_size_dirty(chmp, chmp->chm_nextblock, totlen);
1162 if (retries) {
1163 ret = EIO;
1164 mutex_exit(&chmp->chm_lock_sizes);
1165 goto out;
1166 }
1167
1168 retries++;
1169 mutex_exit(&chmp->chm_lock_sizes);
1170 goto retry;
1171 }
1172
1173 dbg_gc("new nref lnr: %u - offset: %u\n", nref->nref_lnr, nref->nref_offset);
1174
1175 chfs_change_size_used(chmp, &chmp->chm_blocks[nref->nref_lnr], totlen);
1176 mutex_exit(&chmp->chm_lock_sizes);
1177 KASSERT(chmp->chm_blocks[nref->nref_lnr].used_size <= chmp->chm_ebh->eb_size);
1178
1179 newfn = chfs_alloc_full_dnode();
1180 newfn->nref = nref;
1181 newfn->ofs = fn->ofs;
1182 newfn->size = fn->size;
1183 newfn->frags = 0;
1184
1185 mutex_enter(&chmp->chm_lock_vnocache);
1186 chfs_remove_frags_of_node(chmp, &ip->fragtree, fn->nref);
1187 chfs_remove_and_obsolete(chmp, ip->chvc, fn->nref, &ip->chvc->dnode);
1188
1189 chfs_add_full_dnode_to_inode(chmp, ip, newfn);
1190 chfs_add_node_to_list(chmp,
1191 ip->chvc, newfn->nref, &ip->chvc->dnode);
1192 mutex_exit(&chmp->chm_lock_vnocache);
1193
1194 out:
1195 kmem_free(data, totlen);
1196 return ret;
1197 }
1198