1/*	$NetBSD: chfs_erase.c,v 1.1 2011/11/24 15:51:31 ahoka Exp $	*/
2
3/*-
4 * Copyright (c) 2010 Department of Software Engineering,
5 *		      University of Szeged, Hungary
6 * Copyright (c) 2010 David Tengeri <dtengeri@inf.u-szeged.hu>
7 * All rights reserved.
8 *
9 * This code is derived from software contributed to The NetBSD Foundation
10 * by the Department of Software Engineering, University of Szeged, Hungary
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 *    notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 *    notice, this list of conditions and the following disclaimer in the
19 *    documentation and/or other materials provided with the distribution.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#include "chfs.h"
35
36
37/*
38 * chfs_remap_leb - unmap and then map a leb
39 *
40 * Gets an eraseblock from the erasable queue, unmaps it through
41 * EBH and maps another eraseblock to the same LNR.
42 * EBH will find a free eraseblock if any or will erase one if there isn't any
43 * free, just dirty block.
44 *
45 * Needs more brainstorming here.
46 */
47int
48chfs_remap_leb(struct chfs_mount *chmp)
49{
50	int err;
51	struct chfs_eraseblock *cheb;
52	dbg("chfs_remap_leb\n");
53	uint32_t dirty, unchecked, used, free, wasted;
54
55	KASSERT(!rw_write_held(&chmp->chm_lock_wbuf));
56	KASSERT(mutex_owned(&chmp->chm_lock_mountfields));
57	KASSERT(mutex_owned(&chmp->chm_lock_sizes));
58
59	if (!chmp->chm_nr_erasable_blocks) {
60		//TODO
61		/* We don't have any erasable blocks, need to check if there are
62		 * blocks on erasable_pending_wbuf_queue, flush the data and then
63		 * we can remap it.
64		 * If there aren't any blocks on that list too, we need to GC?
65		 */
66		if (!TAILQ_EMPTY(&chmp->chm_erasable_pending_wbuf_queue)) {
67			cheb = TAILQ_FIRST(&chmp->chm_erasable_pending_wbuf_queue);
68			TAILQ_REMOVE(&chmp->chm_erasable_pending_wbuf_queue, cheb, queue);
69			if (chmp->chm_wbuf_len) {
70				mutex_exit(&chmp->chm_lock_sizes);
71				chfs_flush_pending_wbuf(chmp);
72				mutex_enter(&chmp->chm_lock_sizes);
73			}
74			TAILQ_INSERT_TAIL(&chmp->chm_erase_pending_queue, cheb, queue);
75			chmp->chm_nr_erasable_blocks++;
76		} else {
77			/* We can't delete any block. */
78			//FIXME should we return ENOSPC?
79			return ENOSPC;
80		}
81	}
82	cheb = TAILQ_FIRST(&chmp->chm_erase_pending_queue);
83	TAILQ_REMOVE(&chmp->chm_erase_pending_queue, cheb, queue);
84	chmp->chm_nr_erasable_blocks--;
85
86	dirty = cheb->dirty_size;
87	unchecked = cheb->unchecked_size;
88	used = cheb->used_size;
89	free = cheb->free_size;
90	wasted = cheb->wasted_size;
91
92	/* Free allocated node references for this eraseblock */
93	chfs_free_node_refs(cheb);
94
95	err = chfs_unmap_leb(chmp, cheb->lnr);
96	if (err)
97		return err;
98
99	err = chfs_map_leb(chmp, cheb->lnr);
100	if (err)
101		return err;
102	/* Reset state to default and change chmp sizes too */
103	chfs_change_size_dirty(chmp, cheb, -dirty);
104	chfs_change_size_unchecked(chmp, cheb, -unchecked);
105	chfs_change_size_used(chmp, cheb, -used);
106	chfs_change_size_free(chmp, cheb, chmp->chm_ebh->eb_size - free);
107	chfs_change_size_wasted(chmp, cheb, -wasted);
108
109	KASSERT(cheb->dirty_size == 0);
110	KASSERT(cheb->unchecked_size == 0);
111	KASSERT(cheb->used_size == 0);
112	KASSERT(cheb->free_size == chmp->chm_ebh->eb_size);
113	KASSERT(cheb->wasted_size == 0);
114
115	cheb->first_node = NULL;
116	cheb->last_node  = NULL;
117	/* put it to free_queue */
118	TAILQ_INSERT_TAIL(&chmp->chm_free_queue, cheb, queue);
119	chmp->chm_nr_free_blocks++;
120	dbg("remaped (free: %d, erasable: %d)\n", chmp->chm_nr_free_blocks, chmp->chm_nr_erasable_blocks);
121	KASSERT(!TAILQ_EMPTY(&chmp->chm_free_queue));
122
123	return 0;
124}
125