1059819e3SMatthew Dillon /* 2059819e3SMatthew Dillon * Copyright (c) 2008 The DragonFly Project. All rights reserved. 3059819e3SMatthew Dillon * 4059819e3SMatthew Dillon * This code is derived from software contributed to The DragonFly Project 5059819e3SMatthew Dillon * by Matthew Dillon <dillon@backplane.com> 6059819e3SMatthew Dillon * 7059819e3SMatthew Dillon * Redistribution and use in source and binary forms, with or without 8059819e3SMatthew Dillon * modification, are permitted provided that the following conditions 9059819e3SMatthew Dillon * are met: 10059819e3SMatthew Dillon * 11059819e3SMatthew Dillon * 1. Redistributions of source code must retain the above copyright 12059819e3SMatthew Dillon * notice, this list of conditions and the following disclaimer. 13059819e3SMatthew Dillon * 2. Redistributions in binary form must reproduce the above copyright 14059819e3SMatthew Dillon * notice, this list of conditions and the following disclaimer in 15059819e3SMatthew Dillon * the documentation and/or other materials provided with the 16059819e3SMatthew Dillon * distribution. 17059819e3SMatthew Dillon * 3. Neither the name of The DragonFly Project nor the names of its 18059819e3SMatthew Dillon * contributors may be used to endorse or promote products derived 19059819e3SMatthew Dillon * from this software without specific, prior written permission. 20059819e3SMatthew Dillon * 21059819e3SMatthew Dillon * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22059819e3SMatthew Dillon * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23059819e3SMatthew Dillon * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24059819e3SMatthew Dillon * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25059819e3SMatthew Dillon * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26059819e3SMatthew Dillon * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 27059819e3SMatthew Dillon * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28059819e3SMatthew Dillon * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 29059819e3SMatthew Dillon * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30059819e3SMatthew Dillon * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 31059819e3SMatthew Dillon * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32059819e3SMatthew Dillon * SUCH DAMAGE. 33059819e3SMatthew Dillon * 34*1f07f686SMatthew Dillon * $DragonFly: src/sys/vfs/hammer/hammer_flusher.c,v 1.9 2008/05/02 01:00:42 dillon Exp $ 35059819e3SMatthew Dillon */ 36059819e3SMatthew Dillon /* 37059819e3SMatthew Dillon * HAMMER dependancy flusher thread 38059819e3SMatthew Dillon * 39059819e3SMatthew Dillon * Meta data updates create buffer dependancies which are arranged as a 40059819e3SMatthew Dillon * hierarchy of lists. 41059819e3SMatthew Dillon */ 42059819e3SMatthew Dillon 43059819e3SMatthew Dillon #include "hammer.h" 44059819e3SMatthew Dillon 45059819e3SMatthew Dillon static void hammer_flusher_thread(void *arg); 4610a5d1baSMatthew Dillon static void hammer_flusher_clean_loose_ios(hammer_mount_t hmp); 47059819e3SMatthew Dillon static void hammer_flusher_flush(hammer_mount_t hmp); 480729c8c8SMatthew Dillon static int hammer_must_finalize_undo(hammer_mount_t hmp); 4910a5d1baSMatthew Dillon static void hammer_flusher_finalize(hammer_mount_t hmp, 5010a5d1baSMatthew Dillon hammer_volume_t root_volume, hammer_off_t start_offset); 51059819e3SMatthew Dillon 52059819e3SMatthew Dillon void 53059819e3SMatthew Dillon hammer_flusher_sync(hammer_mount_t hmp) 54059819e3SMatthew Dillon { 55059819e3SMatthew Dillon int seq; 56059819e3SMatthew Dillon 57f90dde4cSMatthew Dillon if (hmp->flusher_td) { 58*1f07f686SMatthew Dillon seq = hmp->flusher_next; 59*1f07f686SMatthew Dillon if (hmp->flusher_signal == 0) { 60*1f07f686SMatthew Dillon hmp->flusher_signal = 1; 61*1f07f686SMatthew Dillon wakeup(&hmp->flusher_signal); 62*1f07f686SMatthew Dillon } 63*1f07f686SMatthew Dillon while ((int)(seq - hmp->flusher_done) > 0) 64*1f07f686SMatthew Dillon tsleep(&hmp->flusher_done, 0, "hmrfls", 0); 65059819e3SMatthew Dillon } 66f90dde4cSMatthew Dillon } 67059819e3SMatthew Dillon 68059819e3SMatthew Dillon void 69059819e3SMatthew Dillon hammer_flusher_async(hammer_mount_t hmp) 70059819e3SMatthew Dillon { 71f90dde4cSMatthew Dillon if (hmp->flusher_td) { 72*1f07f686SMatthew Dillon if (hmp->flusher_signal == 0) { 73*1f07f686SMatthew Dillon hmp->flusher_signal = 1; 74*1f07f686SMatthew Dillon wakeup(&hmp->flusher_signal); 75*1f07f686SMatthew Dillon } 76059819e3SMatthew Dillon } 77f90dde4cSMatthew Dillon } 78059819e3SMatthew Dillon 79059819e3SMatthew Dillon void 80059819e3SMatthew Dillon hammer_flusher_create(hammer_mount_t hmp) 81059819e3SMatthew Dillon { 82*1f07f686SMatthew Dillon hmp->flusher_signal = 0; 83*1f07f686SMatthew Dillon hmp->flusher_act = 0; 84*1f07f686SMatthew Dillon hmp->flusher_done = 0; 85*1f07f686SMatthew Dillon hmp->flusher_next = 1; 86059819e3SMatthew Dillon lwkt_create(hammer_flusher_thread, hmp, &hmp->flusher_td, NULL, 87059819e3SMatthew Dillon 0, -1, "hammer"); 88059819e3SMatthew Dillon } 89059819e3SMatthew Dillon 90059819e3SMatthew Dillon void 91059819e3SMatthew Dillon hammer_flusher_destroy(hammer_mount_t hmp) 92059819e3SMatthew Dillon { 93f90dde4cSMatthew Dillon if (hmp->flusher_td) { 94059819e3SMatthew Dillon hmp->flusher_exiting = 1; 95*1f07f686SMatthew Dillon while (hmp->flusher_td) { 96*1f07f686SMatthew Dillon hmp->flusher_signal = 1; 97*1f07f686SMatthew Dillon wakeup(&hmp->flusher_signal); 98059819e3SMatthew Dillon tsleep(&hmp->flusher_exiting, 0, "hmrwex", 0); 99059819e3SMatthew Dillon } 100f90dde4cSMatthew Dillon } 101*1f07f686SMatthew Dillon } 102059819e3SMatthew Dillon 103059819e3SMatthew Dillon static void 104059819e3SMatthew Dillon hammer_flusher_thread(void *arg) 105059819e3SMatthew Dillon { 106059819e3SMatthew Dillon hammer_mount_t hmp = arg; 1070729c8c8SMatthew Dillon 108059819e3SMatthew Dillon for (;;) { 109*1f07f686SMatthew Dillon hmp->flusher_act = hmp->flusher_next; 110*1f07f686SMatthew Dillon ++hmp->flusher_next; 111*1f07f686SMatthew Dillon kprintf("F"); 11210a5d1baSMatthew Dillon hammer_flusher_clean_loose_ios(hmp); 113059819e3SMatthew Dillon hammer_flusher_flush(hmp); 11410a5d1baSMatthew Dillon hammer_flusher_clean_loose_ios(hmp); 115*1f07f686SMatthew Dillon hmp->flusher_done = hmp->flusher_act; 116*1f07f686SMatthew Dillon 117*1f07f686SMatthew Dillon wakeup(&hmp->flusher_done); 118c32a6806SMatthew Dillon 119c32a6806SMatthew Dillon /* 120*1f07f686SMatthew Dillon * Wait for activity. 121c32a6806SMatthew Dillon */ 122*1f07f686SMatthew Dillon if (hmp->flusher_exiting && TAILQ_EMPTY(&hmp->flush_list)) 123059819e3SMatthew Dillon break; 124*1f07f686SMatthew Dillon kprintf("E"); 125*1f07f686SMatthew Dillon 126*1f07f686SMatthew Dillon while (hmp->flusher_signal == 0 && 127*1f07f686SMatthew Dillon TAILQ_EMPTY(&hmp->flush_list)) { 128*1f07f686SMatthew Dillon tsleep(&hmp->flusher_signal, 0, "hmrwwa", 0); 129059819e3SMatthew Dillon } 130*1f07f686SMatthew Dillon hmp->flusher_signal = 0; 131*1f07f686SMatthew Dillon } 132059819e3SMatthew Dillon hmp->flusher_td = NULL; 133059819e3SMatthew Dillon wakeup(&hmp->flusher_exiting); 134059819e3SMatthew Dillon lwkt_exit(); 135059819e3SMatthew Dillon } 136059819e3SMatthew Dillon 13710a5d1baSMatthew Dillon static void 13810a5d1baSMatthew Dillon hammer_flusher_clean_loose_ios(hammer_mount_t hmp) 13910a5d1baSMatthew Dillon { 14010a5d1baSMatthew Dillon hammer_buffer_t buffer; 14110a5d1baSMatthew Dillon hammer_io_t io; 14210a5d1baSMatthew Dillon 14310a5d1baSMatthew Dillon /* 14410a5d1baSMatthew Dillon * loose ends - buffers without bp's aren't tracked by the kernel 14510a5d1baSMatthew Dillon * and can build up, so clean them out. This can occur when an 14610a5d1baSMatthew Dillon * IO completes on a buffer with no references left. 14710a5d1baSMatthew Dillon */ 14810a5d1baSMatthew Dillon while ((io = TAILQ_FIRST(&hmp->lose_list)) != NULL) { 14910a5d1baSMatthew Dillon KKASSERT(io->mod_list == &hmp->lose_list); 15010a5d1baSMatthew Dillon TAILQ_REMOVE(io->mod_list, io, mod_entry); 15110a5d1baSMatthew Dillon io->mod_list = NULL; 15210a5d1baSMatthew Dillon hammer_ref(&io->lock); 15310a5d1baSMatthew Dillon buffer = (void *)io; 15410a5d1baSMatthew Dillon hammer_rel_buffer(buffer, 0); 15510a5d1baSMatthew Dillon } 15610a5d1baSMatthew Dillon } 15710a5d1baSMatthew Dillon 158059819e3SMatthew Dillon /* 159059819e3SMatthew Dillon * Flush stuff 160059819e3SMatthew Dillon */ 161059819e3SMatthew Dillon static void 162059819e3SMatthew Dillon hammer_flusher_flush(hammer_mount_t hmp) 163059819e3SMatthew Dillon { 16410a5d1baSMatthew Dillon hammer_volume_t root_volume; 16510a5d1baSMatthew Dillon hammer_blockmap_t rootmap; 166059819e3SMatthew Dillon hammer_inode_t ip; 16710a5d1baSMatthew Dillon hammer_off_t start_offset; 16810a5d1baSMatthew Dillon int error; 16910a5d1baSMatthew Dillon 17010a5d1baSMatthew Dillon root_volume = hammer_get_root_volume(hmp, &error); 1710729c8c8SMatthew Dillon rootmap = &hmp->blockmap[HAMMER_ZONE_UNDO_INDEX]; 17210a5d1baSMatthew Dillon start_offset = rootmap->next_offset; 173059819e3SMatthew Dillon 174*1f07f686SMatthew Dillon while ((ip = TAILQ_FIRST(&hmp->flush_list)) != NULL) { 175*1f07f686SMatthew Dillon /* 176*1f07f686SMatthew Dillon * Stop when we hit a different flush group 177*1f07f686SMatthew Dillon */ 178*1f07f686SMatthew Dillon if (ip->flush_group != hmp->flusher_act) 179*1f07f686SMatthew Dillon break; 180059819e3SMatthew Dillon 181059819e3SMatthew Dillon /* 182*1f07f686SMatthew Dillon * Remove the inode from the flush list and inherit 183*1f07f686SMatthew Dillon * its reference, sync, and clean-up. 184059819e3SMatthew Dillon */ 185*1f07f686SMatthew Dillon TAILQ_REMOVE(&hmp->flush_list, ip, flush_entry); 186*1f07f686SMatthew Dillon kprintf("s"); 187*1f07f686SMatthew Dillon ip->error = hammer_sync_inode(ip); 188b84de5afSMatthew Dillon hammer_flush_inode_done(ip); 189*1f07f686SMatthew Dillon 190*1f07f686SMatthew Dillon /* 191*1f07f686SMatthew Dillon * XXX this breaks atomicy 192*1f07f686SMatthew Dillon */ 193*1f07f686SMatthew Dillon if (hammer_must_finalize_undo(hmp)) { 194*1f07f686SMatthew Dillon Debugger("Too many undos!!"); 19510a5d1baSMatthew Dillon hammer_flusher_finalize(hmp, root_volume, start_offset); 19610a5d1baSMatthew Dillon start_offset = rootmap->next_offset; 197059819e3SMatthew Dillon } 198059819e3SMatthew Dillon } 19910a5d1baSMatthew Dillon hammer_flusher_finalize(hmp, root_volume, start_offset); 20010a5d1baSMatthew Dillon hammer_rel_volume(root_volume, 0); 20110a5d1baSMatthew Dillon } 202059819e3SMatthew Dillon 20310a5d1baSMatthew Dillon /* 204ec4e8497SMatthew Dillon * If the UNDO area gets over half full we have to flush it. We can't 205ec4e8497SMatthew Dillon * afford the UNDO area becoming completely full as that would break 206ec4e8497SMatthew Dillon * the crash recovery atomicy. 207ec4e8497SMatthew Dillon */ 208ec4e8497SMatthew Dillon static 209ec4e8497SMatthew Dillon int 2100729c8c8SMatthew Dillon hammer_must_finalize_undo(hammer_mount_t hmp) 211ec4e8497SMatthew Dillon { 212*1f07f686SMatthew Dillon if (hammer_undo_space(hmp) < hammer_undo_max(hmp) / 2) { 213ec4e8497SMatthew Dillon kprintf("*"); 214*1f07f686SMatthew Dillon return(1); 215*1f07f686SMatthew Dillon } else { 216*1f07f686SMatthew Dillon return(0); 217*1f07f686SMatthew Dillon } 218ec4e8497SMatthew Dillon } 219ec4e8497SMatthew Dillon 220ec4e8497SMatthew Dillon /* 22110a5d1baSMatthew Dillon * To finalize the flush we finish flushing all undo and data buffers 22210a5d1baSMatthew Dillon * still present, then we update the volume header and flush it, 22310a5d1baSMatthew Dillon * then we flush out the mata-data (that can now be undone). 22410a5d1baSMatthew Dillon * 22510a5d1baSMatthew Dillon * Note that as long as the undo fifo's start and end points do not 22610a5d1baSMatthew Dillon * match, we always must at least update the volume header. 2279480ff55SMatthew Dillon * 2289480ff55SMatthew Dillon * The sync_lock is used by other threads to issue modifying operations 2299480ff55SMatthew Dillon * to HAMMER media without crossing a synchronization boundary or messing 2309480ff55SMatthew Dillon * up the media synchronization operation. Specifically, the pruning 2319480ff55SMatthew Dillon * the reblocking ioctls, and allowing the frontend strategy code to 2329480ff55SMatthew Dillon * allocate media data space. 23310a5d1baSMatthew Dillon */ 23410a5d1baSMatthew Dillon static 23510a5d1baSMatthew Dillon void 23610a5d1baSMatthew Dillon hammer_flusher_finalize(hammer_mount_t hmp, hammer_volume_t root_volume, 23710a5d1baSMatthew Dillon hammer_off_t start_offset) 238059819e3SMatthew Dillon { 239059819e3SMatthew Dillon hammer_blockmap_t rootmap; 24010a5d1baSMatthew Dillon hammer_io_t io; 24110a5d1baSMatthew Dillon 2429480ff55SMatthew Dillon hammer_lock_ex(&hmp->sync_lock); 2439480ff55SMatthew Dillon 244059819e3SMatthew Dillon /* 24510a5d1baSMatthew Dillon * Flush undo bufs 246059819e3SMatthew Dillon */ 24710a5d1baSMatthew Dillon while ((io = TAILQ_FIRST(&hmp->undo_list)) != NULL) { 24810a5d1baSMatthew Dillon KKASSERT(io->modify_refs == 0); 24910a5d1baSMatthew Dillon hammer_ref(&io->lock); 25010a5d1baSMatthew Dillon KKASSERT(io->type != HAMMER_STRUCTURE_VOLUME); 25110a5d1baSMatthew Dillon hammer_io_flush(io); 25210a5d1baSMatthew Dillon hammer_rel_buffer((hammer_buffer_t)io, 1); 253059819e3SMatthew Dillon } 254059819e3SMatthew Dillon 255059819e3SMatthew Dillon /* 25610a5d1baSMatthew Dillon * Flush data bufs 257059819e3SMatthew Dillon */ 25810a5d1baSMatthew Dillon while ((io = TAILQ_FIRST(&hmp->data_list)) != NULL) { 25910a5d1baSMatthew Dillon KKASSERT(io->modify_refs == 0); 26010a5d1baSMatthew Dillon hammer_ref(&io->lock); 26110a5d1baSMatthew Dillon KKASSERT(io->type != HAMMER_STRUCTURE_VOLUME); 26210a5d1baSMatthew Dillon hammer_io_flush(io); 26310a5d1baSMatthew Dillon hammer_rel_buffer((hammer_buffer_t)io, 1); 264059819e3SMatthew Dillon } 265059819e3SMatthew Dillon 266059819e3SMatthew Dillon /* 267f90dde4cSMatthew Dillon * Wait for I/O to complete 268059819e3SMatthew Dillon */ 269f90dde4cSMatthew Dillon crit_enter(); 270f90dde4cSMatthew Dillon while (hmp->io_running_count) { 2719480ff55SMatthew Dillon kprintf("W[%d]", hmp->io_running_count); 272f90dde4cSMatthew Dillon tsleep(&hmp->io_running_count, 0, "hmrfl1", 0); 273f90dde4cSMatthew Dillon } 274f90dde4cSMatthew Dillon crit_exit(); 275059819e3SMatthew Dillon 276059819e3SMatthew Dillon /* 27710a5d1baSMatthew Dillon * Update the volume header 278059819e3SMatthew Dillon */ 2790729c8c8SMatthew Dillon rootmap = &hmp->blockmap[HAMMER_ZONE_UNDO_INDEX]; 28010a5d1baSMatthew Dillon if (rootmap->first_offset != start_offset) { 28110a5d1baSMatthew Dillon hammer_modify_volume(NULL, root_volume, NULL, 0); 28210a5d1baSMatthew Dillon rootmap->first_offset = start_offset; 28310a5d1baSMatthew Dillon hammer_modify_volume_done(root_volume); 2840729c8c8SMatthew Dillon } 2850729c8c8SMatthew Dillon if (root_volume->ondisk->vol0_next_tid != hmp->next_tid) { 2860729c8c8SMatthew Dillon hammer_modify_volume(NULL, root_volume, NULL, 0); 2870729c8c8SMatthew Dillon root_volume->ondisk->vol0_next_tid = hmp->next_tid; 2880729c8c8SMatthew Dillon hammer_modify_volume_done(root_volume); 2890729c8c8SMatthew Dillon } 2900729c8c8SMatthew Dillon 2910729c8c8SMatthew Dillon /* 2920729c8c8SMatthew Dillon * Sync our cached blockmap array with the one in the root 2930729c8c8SMatthew Dillon * volume header. 2940729c8c8SMatthew Dillon */ 2950729c8c8SMatthew Dillon if (root_volume->io.modified) { 2960729c8c8SMatthew Dillon bcopy(hmp->blockmap, root_volume->ondisk->vol0_blockmap, 2970729c8c8SMatthew Dillon sizeof(hmp->blockmap)); 29810a5d1baSMatthew Dillon hammer_io_flush(&root_volume->io); 299059819e3SMatthew Dillon } 300059819e3SMatthew Dillon 301059819e3SMatthew Dillon /* 302f90dde4cSMatthew Dillon * Wait for I/O to complete 303059819e3SMatthew Dillon */ 304f90dde4cSMatthew Dillon crit_enter(); 305f90dde4cSMatthew Dillon while (hmp->io_running_count) { 306f90dde4cSMatthew Dillon tsleep(&hmp->io_running_count, 0, "hmrfl2", 0); 307f90dde4cSMatthew Dillon } 308f90dde4cSMatthew Dillon crit_exit(); 309059819e3SMatthew Dillon 310059819e3SMatthew Dillon /* 31110a5d1baSMatthew Dillon * Flush meta-data 312059819e3SMatthew Dillon */ 31310a5d1baSMatthew Dillon while ((io = TAILQ_FIRST(&hmp->meta_list)) != NULL) { 31410a5d1baSMatthew Dillon KKASSERT(io->modify_refs == 0); 31510a5d1baSMatthew Dillon hammer_ref(&io->lock); 31610a5d1baSMatthew Dillon KKASSERT(io->type != HAMMER_STRUCTURE_VOLUME); 31710a5d1baSMatthew Dillon hammer_io_flush(io); 31810a5d1baSMatthew Dillon hammer_rel_buffer((hammer_buffer_t)io, 1); 319059819e3SMatthew Dillon } 3209480ff55SMatthew Dillon hammer_unlock(&hmp->sync_lock); 321059819e3SMatthew Dillon } 322059819e3SMatthew Dillon 323