2 * Copyright (c) 2008 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Matthew Dillon <dillon@backplane.com>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
17 * 3. Neither the name of The DragonFly Project nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific, prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT HOLDERS OR CONTRIBUTORS 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 OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * $DragonFly: src/sys/vfs/hammer/hammer_flusher.c,v 1.3 2008/04/25 21:49:49 dillon Exp $
37 * HAMMER dependancy flusher thread
39 * Meta data updates create buffer dependancies which are arranged as a
45 static void hammer_flusher_thread(void *arg);
46 static void hammer_flusher_clean_loose_ios(hammer_mount_t hmp);
47 static void hammer_flusher_flush(hammer_mount_t hmp);
48 static void hammer_flusher_finalize(hammer_mount_t hmp,
49 hammer_volume_t root_volume, hammer_off_t start_offset);
52 hammer_flusher_sync(hammer_mount_t hmp)
56 seq = ++hmp->flusher_seq;
57 wakeup(&hmp->flusher_seq);
58 while ((int)(seq - hmp->flusher_act) > 0)
59 tsleep(&hmp->flusher_act, 0, "hmrfls", 0);
63 hammer_flusher_async(hammer_mount_t hmp)
66 wakeup(&hmp->flusher_seq);
70 hammer_flusher_create(hammer_mount_t hmp)
72 lwkt_create(hammer_flusher_thread, hmp, &hmp->flusher_td, NULL,
77 hammer_flusher_destroy(hammer_mount_t hmp)
79 hmp->flusher_exiting = 1;
81 wakeup(&hmp->flusher_seq);
82 while (hmp->flusher_td)
83 tsleep(&hmp->flusher_exiting, 0, "hmrwex", 0);
87 hammer_flusher_thread(void *arg)
89 hammer_mount_t hmp = arg;
93 seq = hmp->flusher_seq;
94 hammer_flusher_clean_loose_ios(hmp);
95 hammer_flusher_flush(hmp);
96 hammer_flusher_clean_loose_ios(hmp);
97 hmp->flusher_act = seq;
98 wakeup(&hmp->flusher_act);
99 if (hmp->flusher_exiting)
101 while (hmp->flusher_seq == hmp->flusher_act)
102 tsleep(&hmp->flusher_seq, 0, "hmrflt", 0);
104 hmp->flusher_td = NULL;
105 wakeup(&hmp->flusher_exiting);
110 hammer_flusher_clean_loose_ios(hammer_mount_t hmp)
112 hammer_buffer_t buffer;
116 * loose ends - buffers without bp's aren't tracked by the kernel
117 * and can build up, so clean them out. This can occur when an
118 * IO completes on a buffer with no references left.
120 while ((io = TAILQ_FIRST(&hmp->lose_list)) != NULL) {
121 KKASSERT(io->mod_list == &hmp->lose_list);
122 TAILQ_REMOVE(io->mod_list, io, mod_entry);
124 hammer_ref(&io->lock);
125 kprintf("DELETE LOOSE %p\n", io);
127 hammer_rel_buffer(buffer, 0);
135 hammer_flusher_flush(hammer_mount_t hmp)
137 hammer_volume_t root_volume;
138 hammer_blockmap_t rootmap;
140 hammer_off_t start_offset;
143 root_volume = hammer_get_root_volume(hmp, &error);
144 rootmap = &root_volume->ondisk->vol0_blockmap[HAMMER_ZONE_UNDO_INDEX];
145 start_offset = rootmap->next_offset;
147 while ((ip = TAILQ_FIRST(&hmp->flush_list)) != NULL) {
148 TAILQ_REMOVE(&hmp->flush_list, ip, flush_entry);
151 * We inherit the inode ref from the flush list
153 ip->error = hammer_sync_inode(ip, (ip->vp ? 0 : 1));
154 hammer_flush_inode_done(ip);
155 if (hmp->locked_dirty_count > 64) {
156 hammer_flusher_finalize(hmp, root_volume, start_offset);
157 start_offset = rootmap->next_offset;
160 hammer_flusher_finalize(hmp, root_volume, start_offset);
161 hammer_rel_volume(root_volume, 0);
165 * To finalize the flush we finish flushing all undo and data buffers
166 * still present, then we update the volume header and flush it,
167 * then we flush out the mata-data (that can now be undone).
169 * Note that as long as the undo fifo's start and end points do not
170 * match, we always must at least update the volume header.
174 hammer_flusher_finalize(hammer_mount_t hmp, hammer_volume_t root_volume,
175 hammer_off_t start_offset)
177 hammer_blockmap_t rootmap;
180 kprintf("FINALIZE %d\n", hmp->locked_dirty_count);
185 while ((io = TAILQ_FIRST(&hmp->undo_list)) != NULL) {
186 KKASSERT(io->modify_refs == 0);
187 hammer_ref(&io->lock);
188 KKASSERT(io->type != HAMMER_STRUCTURE_VOLUME);
190 hammer_rel_buffer((hammer_buffer_t)io, 1);
196 while ((io = TAILQ_FIRST(&hmp->data_list)) != NULL) {
197 KKASSERT(io->modify_refs == 0);
198 hammer_ref(&io->lock);
199 KKASSERT(io->type != HAMMER_STRUCTURE_VOLUME);
201 hammer_rel_buffer((hammer_buffer_t)io, 1);
205 * XXX wait for I/O's to complete
209 * Update the volume header
211 rootmap = &root_volume->ondisk->vol0_blockmap[HAMMER_ZONE_UNDO_INDEX];
212 if (rootmap->first_offset != start_offset) {
213 kprintf("FINALIZE: ACTIVE VOLUME STAGE 1\n");
214 hammer_modify_volume(NULL, root_volume, NULL, 0);
215 rootmap->first_offset = start_offset;
216 hammer_modify_volume_done(root_volume);
217 hammer_io_flush(&root_volume->io);
219 kprintf("FINALIZE: ACTIVE VOLUME STAGE 2\n");
223 * XXX wait for I/O to complete
229 while ((io = TAILQ_FIRST(&hmp->meta_list)) != NULL) {
230 KKASSERT(io->modify_refs == 0);
231 hammer_ref(&io->lock);
232 KKASSERT(io->type != HAMMER_STRUCTURE_VOLUME);
234 hammer_rel_buffer((hammer_buffer_t)io, 1);