166325755SMatthew Dillon /* 266325755SMatthew Dillon * Copyright (c) 2007 The DragonFly Project. All rights reserved. 366325755SMatthew Dillon * 466325755SMatthew Dillon * This code is derived from software contributed to The DragonFly Project 566325755SMatthew Dillon * by Matthew Dillon <dillon@backplane.com> 666325755SMatthew Dillon * 766325755SMatthew Dillon * Redistribution and use in source and binary forms, with or without 866325755SMatthew Dillon * modification, are permitted provided that the following conditions 966325755SMatthew Dillon * are met: 1066325755SMatthew Dillon * 1166325755SMatthew Dillon * 1. Redistributions of source code must retain the above copyright 1266325755SMatthew Dillon * notice, this list of conditions and the following disclaimer. 1366325755SMatthew Dillon * 2. Redistributions in binary form must reproduce the above copyright 1466325755SMatthew Dillon * notice, this list of conditions and the following disclaimer in 1566325755SMatthew Dillon * the documentation and/or other materials provided with the 1666325755SMatthew Dillon * distribution. 1766325755SMatthew Dillon * 3. Neither the name of The DragonFly Project nor the names of its 1866325755SMatthew Dillon * contributors may be used to endorse or promote products derived 1966325755SMatthew Dillon * from this software without specific, prior written permission. 2066325755SMatthew Dillon * 2166325755SMatthew Dillon * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 2266325755SMatthew Dillon * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 2366325755SMatthew Dillon * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 2466325755SMatthew Dillon * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 2566325755SMatthew Dillon * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 2666325755SMatthew Dillon * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 2766325755SMatthew Dillon * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 2866325755SMatthew Dillon * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 2966325755SMatthew Dillon * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 3066325755SMatthew Dillon * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 3166325755SMatthew Dillon * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3266325755SMatthew Dillon * SUCH DAMAGE. 3366325755SMatthew Dillon * 34*d26d0ae9SMatthew Dillon * $DragonFly: src/sys/vfs/hammer/hammer_io.c,v 1.7 2007/12/29 09:01:27 dillon Exp $ 3566325755SMatthew Dillon */ 3666325755SMatthew Dillon /* 3766325755SMatthew Dillon * IO Primitives and buffer cache management 3866325755SMatthew Dillon * 3966325755SMatthew Dillon * All major data-tracking structures in HAMMER contain a struct hammer_io 4066325755SMatthew Dillon * which is used to manage their backing store. We use filesystem buffers 4166325755SMatthew Dillon * for backing store and we leave them passively associated with their 4266325755SMatthew Dillon * HAMMER structures. 4366325755SMatthew Dillon * 4466325755SMatthew Dillon * If the kernel tries to release a passively associated buf which we cannot 4566325755SMatthew Dillon * yet let go we set B_LOCKED in the buffer and then actively released it 4666325755SMatthew Dillon * later when we can. 4766325755SMatthew Dillon */ 4866325755SMatthew Dillon 4966325755SMatthew Dillon #include "hammer.h" 5066325755SMatthew Dillon #include <sys/fcntl.h> 5166325755SMatthew Dillon #include <sys/nlookup.h> 5266325755SMatthew Dillon #include <sys/buf.h> 5366325755SMatthew Dillon #include <sys/buf2.h> 5466325755SMatthew Dillon 5566325755SMatthew Dillon /* 56fbc6e32aSMatthew Dillon * Helper routine to disassociate a buffer cache buffer from an I/O 57fbc6e32aSMatthew Dillon * structure. 5866325755SMatthew Dillon */ 5966325755SMatthew Dillon static void 6066325755SMatthew Dillon hammer_io_disassociate(union hammer_io_structure *io) 6166325755SMatthew Dillon { 6266325755SMatthew Dillon struct buf *bp = io->io.bp; 6366325755SMatthew Dillon 6466325755SMatthew Dillon LIST_INIT(&bp->b_dep); /* clear the association */ 657f7c1f84SMatthew Dillon bp->b_ops = NULL; 6666325755SMatthew Dillon io->io.bp = NULL; 6766325755SMatthew Dillon 6866325755SMatthew Dillon switch(io->io.type) { 6966325755SMatthew Dillon case HAMMER_STRUCTURE_VOLUME: 7066325755SMatthew Dillon io->volume.ondisk = NULL; 7166325755SMatthew Dillon io->volume.alist.meta = NULL; 7266325755SMatthew Dillon break; 7366325755SMatthew Dillon case HAMMER_STRUCTURE_SUPERCL: 7466325755SMatthew Dillon io->supercl.ondisk = NULL; 7566325755SMatthew Dillon io->supercl.alist.meta = NULL; 7666325755SMatthew Dillon break; 7766325755SMatthew Dillon case HAMMER_STRUCTURE_CLUSTER: 7866325755SMatthew Dillon io->cluster.ondisk = NULL; 7966325755SMatthew Dillon io->cluster.alist_master.meta = NULL; 8066325755SMatthew Dillon io->cluster.alist_btree.meta = NULL; 8166325755SMatthew Dillon io->cluster.alist_record.meta = NULL; 8266325755SMatthew Dillon io->cluster.alist_mdata.meta = NULL; 8366325755SMatthew Dillon break; 8466325755SMatthew Dillon case HAMMER_STRUCTURE_BUFFER: 8566325755SMatthew Dillon io->buffer.ondisk = NULL; 8666325755SMatthew Dillon io->buffer.alist.meta = NULL; 8766325755SMatthew Dillon break; 8866325755SMatthew Dillon } 89fbc6e32aSMatthew Dillon io->io.modified = 0; 90c0ade690SMatthew Dillon io->io.released = 1; 9166325755SMatthew Dillon } 92fbc6e32aSMatthew Dillon 93fbc6e32aSMatthew Dillon /* 94fbc6e32aSMatthew Dillon * Mark a cluster as being closed. This is done as late as possible, 95fbc6e32aSMatthew Dillon * only when we are asked to flush the cluster 96fbc6e32aSMatthew Dillon */ 97fbc6e32aSMatthew Dillon static void 98fbc6e32aSMatthew Dillon hammer_close_cluster(hammer_cluster_t cluster) 99fbc6e32aSMatthew Dillon { 100fbc6e32aSMatthew Dillon while (cluster->state == HAMMER_CLUSTER_ASYNC) 101fbc6e32aSMatthew Dillon tsleep(cluster, 0, "hmrdep", 0); 102fbc6e32aSMatthew Dillon if (cluster->state == HAMMER_CLUSTER_OPEN) { 103fbc6e32aSMatthew Dillon cluster->state = HAMMER_CLUSTER_IDLE; 104fbc6e32aSMatthew Dillon cluster->ondisk->clu_flags &= ~HAMMER_CLUF_OPEN; 105fbc6e32aSMatthew Dillon kprintf("CLOSE CLUSTER\n"); 106fbc6e32aSMatthew Dillon hammer_modify_cluster(cluster); 10766325755SMatthew Dillon } 108fbc6e32aSMatthew Dillon } 109fbc6e32aSMatthew Dillon 11066325755SMatthew Dillon 11166325755SMatthew Dillon /* 11266325755SMatthew Dillon * Load bp for a HAMMER structure. 11366325755SMatthew Dillon */ 11466325755SMatthew Dillon int 11566325755SMatthew Dillon hammer_io_read(struct vnode *devvp, struct hammer_io *io) 11666325755SMatthew Dillon { 11766325755SMatthew Dillon struct buf *bp; 11866325755SMatthew Dillon int error; 11966325755SMatthew Dillon 12066325755SMatthew Dillon if ((bp = io->bp) == NULL) { 12166325755SMatthew Dillon error = bread(devvp, io->offset, HAMMER_BUFSIZE, &io->bp); 12266325755SMatthew Dillon if (error == 0) { 12366325755SMatthew Dillon bp = io->bp; 12466325755SMatthew Dillon bp->b_ops = &hammer_bioops; 12566325755SMatthew Dillon LIST_INSERT_HEAD(&bp->b_dep, &io->worklist, node); 12666325755SMatthew Dillon BUF_KERNPROC(bp); 12766325755SMatthew Dillon } 12866325755SMatthew Dillon io->modified = 0; /* no new modifications yet */ 12966325755SMatthew Dillon io->released = 0; /* we hold an active lock on bp */ 13066325755SMatthew Dillon } else { 13166325755SMatthew Dillon error = 0; 13266325755SMatthew Dillon } 13366325755SMatthew Dillon return(error); 13466325755SMatthew Dillon } 13566325755SMatthew Dillon 13666325755SMatthew Dillon /* 13766325755SMatthew Dillon * Similar to hammer_io_read() but returns a zero'd out buffer instead. 13866325755SMatthew Dillon * vfs_bio_clrbuf() is kinda nasty, enforce serialization against background 13966325755SMatthew Dillon * I/O so we can call it. 14066325755SMatthew Dillon */ 14166325755SMatthew Dillon int 14266325755SMatthew Dillon hammer_io_new(struct vnode *devvp, struct hammer_io *io) 14366325755SMatthew Dillon { 14466325755SMatthew Dillon struct buf *bp; 14566325755SMatthew Dillon 14666325755SMatthew Dillon if ((bp = io->bp) == NULL) { 14766325755SMatthew Dillon io->bp = getblk(devvp, io->offset, HAMMER_BUFSIZE, 0, 0); 14866325755SMatthew Dillon bp = io->bp; 14966325755SMatthew Dillon bp->b_ops = &hammer_bioops; 15066325755SMatthew Dillon LIST_INSERT_HEAD(&bp->b_dep, &io->worklist, node); 15166325755SMatthew Dillon io->released = 0; /* we hold an active lock on bp */ 15266325755SMatthew Dillon BUF_KERNPROC(bp); 15366325755SMatthew Dillon } else { 15466325755SMatthew Dillon if (io->released) { 15566325755SMatthew Dillon regetblk(bp); 15666325755SMatthew Dillon io->released = 0; 15766325755SMatthew Dillon BUF_KERNPROC(bp); 15866325755SMatthew Dillon } 15966325755SMatthew Dillon } 16066325755SMatthew Dillon io->modified = 1; 16166325755SMatthew Dillon vfs_bio_clrbuf(bp); 16266325755SMatthew Dillon return(0); 16366325755SMatthew Dillon } 16466325755SMatthew Dillon 16566325755SMatthew Dillon /* 166fbc6e32aSMatthew Dillon * This routine is called when a buffer within a cluster is modified. We 167fbc6e32aSMatthew Dillon * mark the cluster open and immediately initiate asynchronous I/O. Any 168fbc6e32aSMatthew Dillon * related hammer_buffer write I/O blocks until our async write completes. 169fbc6e32aSMatthew Dillon * This guarentees (inasmuch as the OS can) that the cluster recovery code 170fbc6e32aSMatthew Dillon * will see a cluster marked open if a crash occured while the filesystem 171fbc6e32aSMatthew Dillon * still had dirty buffers associated with that cluster. 172fbc6e32aSMatthew Dillon */ 173fbc6e32aSMatthew Dillon void 174fbc6e32aSMatthew Dillon hammer_io_notify_cluster(hammer_cluster_t cluster) 175fbc6e32aSMatthew Dillon { 176fbc6e32aSMatthew Dillon struct hammer_io *io = &cluster->io; 177fbc6e32aSMatthew Dillon 178fbc6e32aSMatthew Dillon if (cluster->state == HAMMER_CLUSTER_IDLE) { 179fbc6e32aSMatthew Dillon hammer_lock_ex(&cluster->io.lock); 180fbc6e32aSMatthew Dillon if (cluster->state == HAMMER_CLUSTER_IDLE) { 181fbc6e32aSMatthew Dillon if (io->released) 182fbc6e32aSMatthew Dillon regetblk(io->bp); 183fbc6e32aSMatthew Dillon kprintf("MARK CLUSTER OPEN\n"); 184fbc6e32aSMatthew Dillon cluster->ondisk->clu_flags |= HAMMER_CLUF_OPEN; 185fbc6e32aSMatthew Dillon cluster->state = HAMMER_CLUSTER_ASYNC; 186fbc6e32aSMatthew Dillon hammer_modify_cluster(cluster); 187fbc6e32aSMatthew Dillon bawrite(io->bp); 188fbc6e32aSMatthew Dillon io->released = 1; 189fbc6e32aSMatthew Dillon /* leave cluster marked as modified */ 190fbc6e32aSMatthew Dillon } 191fbc6e32aSMatthew Dillon hammer_unlock(&cluster->io.lock); 192fbc6e32aSMatthew Dillon } 193fbc6e32aSMatthew Dillon } 194fbc6e32aSMatthew Dillon 195fbc6e32aSMatthew Dillon /* 196fbc6e32aSMatthew Dillon * This routine is called on the last reference to a hammer structure. If 197fbc6e32aSMatthew Dillon * flush is non-zero we have to completely disassociate the bp from the 198fbc6e32aSMatthew Dillon * structure (which may involve blocking). Otherwise we can leave the bp 199fbc6e32aSMatthew Dillon * passively associated with the structure. 20066325755SMatthew Dillon * 201fbc6e32aSMatthew Dillon * The caller is holding io->lock exclusively. 20266325755SMatthew Dillon */ 20366325755SMatthew Dillon void 20466325755SMatthew Dillon hammer_io_release(struct hammer_io *io, int flush) 20566325755SMatthew Dillon { 20666325755SMatthew Dillon union hammer_io_structure *iou = (void *)io; 207fbc6e32aSMatthew Dillon hammer_cluster_t cluster; 20866325755SMatthew Dillon struct buf *bp; 20966325755SMatthew Dillon 21066325755SMatthew Dillon if ((bp = io->bp) != NULL) { 21166325755SMatthew Dillon /* 212fbc6e32aSMatthew Dillon * If neither we nor the kernel want to flush the bp, we can 213fbc6e32aSMatthew Dillon * stop here. Make sure the bp is passively released 214fbc6e32aSMatthew Dillon * before returning. Even though we are still holding it, 215fbc6e32aSMatthew Dillon * we want to be notified when the kernel wishes to flush 216fbc6e32aSMatthew Dillon * it out so make sure B_DELWRI is properly set if we had 217fbc6e32aSMatthew Dillon * made modifications. 21866325755SMatthew Dillon */ 219fbc6e32aSMatthew Dillon if (flush == 0 && (bp->b_flags & B_LOCKED) == 0) { 220fbc6e32aSMatthew Dillon if ((bp->b_flags & B_DELWRI) == 0 && io->modified) { 221fbc6e32aSMatthew Dillon if (io->released) 22266325755SMatthew Dillon regetblk(bp); 22366325755SMatthew Dillon bdwrite(bp); 224fbc6e32aSMatthew Dillon io->released = 1; 225fbc6e32aSMatthew Dillon } else if (io->released == 0) { 226fbc6e32aSMatthew Dillon bqrelse(bp); 227fbc6e32aSMatthew Dillon io->released = 1; 228fbc6e32aSMatthew Dillon } 229fbc6e32aSMatthew Dillon return; 230fbc6e32aSMatthew Dillon } 231fbc6e32aSMatthew Dillon 232fbc6e32aSMatthew Dillon /* 233fbc6e32aSMatthew Dillon * We've been asked to flush the buffer. 234fbc6e32aSMatthew Dillon * 235fbc6e32aSMatthew Dillon * If this is a hammer_buffer we may have to wait for the 236fbc6e32aSMatthew Dillon * cluster header write to complete. 237fbc6e32aSMatthew Dillon */ 238fbc6e32aSMatthew Dillon if (iou->io.type == HAMMER_STRUCTURE_BUFFER && 239fbc6e32aSMatthew Dillon (io->modified || (bp->b_flags & B_DELWRI))) { 240fbc6e32aSMatthew Dillon cluster = iou->buffer.cluster; 241fbc6e32aSMatthew Dillon while (cluster->state == HAMMER_CLUSTER_ASYNC) 242fbc6e32aSMatthew Dillon tsleep(iou->buffer.cluster, 0, "hmrdep", 0); 243fbc6e32aSMatthew Dillon } 244fbc6e32aSMatthew Dillon 245fbc6e32aSMatthew Dillon /* 246fbc6e32aSMatthew Dillon * If we have an open cluster header, close it 247fbc6e32aSMatthew Dillon */ 248fbc6e32aSMatthew Dillon if (iou->io.type == HAMMER_STRUCTURE_CLUSTER) { 249fbc6e32aSMatthew Dillon hammer_close_cluster(&iou->cluster); 250fbc6e32aSMatthew Dillon } 251fbc6e32aSMatthew Dillon 252fbc6e32aSMatthew Dillon 253fbc6e32aSMatthew Dillon /* 254fbc6e32aSMatthew Dillon * Ok the dependancies are all gone. Check for the simple 255fbc6e32aSMatthew Dillon * disassociation case. 256fbc6e32aSMatthew Dillon */ 257fbc6e32aSMatthew Dillon if (io->released && (bp->b_flags & B_LOCKED) == 0 && 258fbc6e32aSMatthew Dillon (io->modified == 0 || (bp->b_flags & B_DELWRI))) { 259fbc6e32aSMatthew Dillon hammer_io_disassociate(iou); 260fbc6e32aSMatthew Dillon return; 261fbc6e32aSMatthew Dillon } 262fbc6e32aSMatthew Dillon 263fbc6e32aSMatthew Dillon /* 264fbc6e32aSMatthew Dillon * Handle the more complex disassociation case. Acquire the 265fbc6e32aSMatthew Dillon * buffer, clean up B_LOCKED, and deal with the modified 266fbc6e32aSMatthew Dillon * flag. 267fbc6e32aSMatthew Dillon */ 268fbc6e32aSMatthew Dillon if (io->released) 269fbc6e32aSMatthew Dillon regetblk(bp); 270*d26d0ae9SMatthew Dillon io->released = 1; 271fbc6e32aSMatthew Dillon bp->b_flags &= ~B_LOCKED; 272fbc6e32aSMatthew Dillon if (io->modified || (bp->b_flags & B_DELWRI)) 273fbc6e32aSMatthew Dillon bawrite(bp); 27466325755SMatthew Dillon else 27566325755SMatthew Dillon bqrelse(bp); 27666325755SMatthew Dillon hammer_io_disassociate(iou); 277fbc6e32aSMatthew Dillon } 278fbc6e32aSMatthew Dillon } 279fbc6e32aSMatthew Dillon 280fbc6e32aSMatthew Dillon /* 281fbc6e32aSMatthew Dillon * Flush dirty data, if any. 282fbc6e32aSMatthew Dillon */ 283fbc6e32aSMatthew Dillon void 284fbc6e32aSMatthew Dillon hammer_io_flush(struct hammer_io *io, struct hammer_sync_info *info) 285fbc6e32aSMatthew Dillon { 286fbc6e32aSMatthew Dillon struct buf *bp; 287fbc6e32aSMatthew Dillon int error; 288fbc6e32aSMatthew Dillon 289fbc6e32aSMatthew Dillon if ((bp = io->bp) == NULL) 290fbc6e32aSMatthew Dillon return; 291fbc6e32aSMatthew Dillon if (bp->b_flags & B_DELWRI) 292fbc6e32aSMatthew Dillon io->modified = 1; 293fbc6e32aSMatthew Dillon if (io->modified == 0) 294fbc6e32aSMatthew Dillon return; 295fbc6e32aSMatthew Dillon kprintf("IO FLUSH BP %p TYPE %d REFS %d\n", bp, io->type, io->lock.refs); 296fbc6e32aSMatthew Dillon hammer_lock_ex(&io->lock); 297fbc6e32aSMatthew Dillon 298fbc6e32aSMatthew Dillon if ((bp = io->bp) != NULL && io->modified) { 299fbc6e32aSMatthew Dillon if (io->released) 300fbc6e32aSMatthew Dillon regetblk(bp); 301fbc6e32aSMatthew Dillon io->released = 1; 302fbc6e32aSMatthew Dillon 303fbc6e32aSMatthew Dillon /* 304fbc6e32aSMatthew Dillon * We own the bp now 305fbc6e32aSMatthew Dillon */ 306fbc6e32aSMatthew Dillon if (info->waitfor & MNT_WAIT) { 307fbc6e32aSMatthew Dillon io->modified = 0; 308fbc6e32aSMatthew Dillon error = bwrite(bp); 309fbc6e32aSMatthew Dillon if (error) 310fbc6e32aSMatthew Dillon info->error = error; 311fbc6e32aSMatthew Dillon } else if (io->lock.refs == 1) { 312fbc6e32aSMatthew Dillon io->modified = 0; 313fbc6e32aSMatthew Dillon bawrite(bp); 31466325755SMatthew Dillon } else { 315*d26d0ae9SMatthew Dillon /* 316*d26d0ae9SMatthew Dillon * structure is in-use, don't race the write, but 317*d26d0ae9SMatthew Dillon * also set B_LOCKED so we know something tried to 318*d26d0ae9SMatthew Dillon * flush it. 319*d26d0ae9SMatthew Dillon */ 320*d26d0ae9SMatthew Dillon kprintf("can't flush bp %p, %d refs - delaying\n", 321*d26d0ae9SMatthew Dillon bp, io->lock.refs); 322*d26d0ae9SMatthew Dillon bp->b_flags |= B_LOCKED; 323fbc6e32aSMatthew Dillon bqrelse(bp); 32466325755SMatthew Dillon } 32566325755SMatthew Dillon } 326fbc6e32aSMatthew Dillon hammer_unlock(&io->lock); 327fbc6e32aSMatthew Dillon } 328fbc6e32aSMatthew Dillon 32966325755SMatthew Dillon 33066325755SMatthew Dillon /* 33166325755SMatthew Dillon * HAMMER_BIOOPS 33266325755SMatthew Dillon */ 33366325755SMatthew Dillon 33466325755SMatthew Dillon /* 335fbc6e32aSMatthew Dillon * Pre and post I/O callbacks. 33666325755SMatthew Dillon */ 33766325755SMatthew Dillon static void hammer_io_deallocate(struct buf *bp); 33866325755SMatthew Dillon 33966325755SMatthew Dillon static void 34066325755SMatthew Dillon hammer_io_start(struct buf *bp) 34166325755SMatthew Dillon { 342fbc6e32aSMatthew Dillon #if 0 343fbc6e32aSMatthew Dillon union hammer_io_structure *io = (void *)LIST_FIRST(&bp->b_dep); 344fbc6e32aSMatthew Dillon 345fbc6e32aSMatthew Dillon if (io->io.type == HAMMER_STRUCTURE_BUFFER) { 346fbc6e32aSMatthew Dillon while (io->buffer.cluster->io_in_progress) { 347fbc6e32aSMatthew Dillon kprintf("hammer_io_start: wait for cluster\n"); 348fbc6e32aSMatthew Dillon tsleep(io->buffer.cluster, 0, "hmrdep", 0); 349fbc6e32aSMatthew Dillon kprintf("hammer_io_start: wait for cluster done\n"); 350fbc6e32aSMatthew Dillon } 351fbc6e32aSMatthew Dillon } 352fbc6e32aSMatthew Dillon #endif 35366325755SMatthew Dillon } 35466325755SMatthew Dillon 35566325755SMatthew Dillon static void 35666325755SMatthew Dillon hammer_io_complete(struct buf *bp) 35766325755SMatthew Dillon { 358fbc6e32aSMatthew Dillon union hammer_io_structure *io = (void *)LIST_FIRST(&bp->b_dep); 359fbc6e32aSMatthew Dillon 360fbc6e32aSMatthew Dillon if (io->io.type == HAMMER_STRUCTURE_CLUSTER) { 361fbc6e32aSMatthew Dillon if (io->cluster.state == HAMMER_CLUSTER_ASYNC) { 362fbc6e32aSMatthew Dillon kprintf("cluster write complete flags %08x\n", 363fbc6e32aSMatthew Dillon io->cluster.ondisk->clu_flags); 364fbc6e32aSMatthew Dillon io->cluster.state = HAMMER_CLUSTER_OPEN; 365fbc6e32aSMatthew Dillon wakeup(&io->cluster); 366fbc6e32aSMatthew Dillon } 367fbc6e32aSMatthew Dillon } 36866325755SMatthew Dillon } 36966325755SMatthew Dillon 37066325755SMatthew Dillon /* 37166325755SMatthew Dillon * Callback from kernel when it wishes to deallocate a passively 37266325755SMatthew Dillon * associated structure. This can only occur if the buffer is 3738cd0a023SMatthew Dillon * passively associated with the structure. The kernel has locked 3748cd0a023SMatthew Dillon * the buffer. 37566325755SMatthew Dillon * 37666325755SMatthew Dillon * If we cannot disassociate we set B_LOCKED to prevent the buffer 37766325755SMatthew Dillon * from getting reused. 37866325755SMatthew Dillon */ 37966325755SMatthew Dillon static void 38066325755SMatthew Dillon hammer_io_deallocate(struct buf *bp) 38166325755SMatthew Dillon { 38266325755SMatthew Dillon union hammer_io_structure *io = (void *)LIST_FIRST(&bp->b_dep); 38366325755SMatthew Dillon 38466325755SMatthew Dillon /* XXX memory interlock, spinlock to sync cpus */ 38566325755SMatthew Dillon 386fbc6e32aSMatthew Dillon /* 387fbc6e32aSMatthew Dillon * Since the kernel is passing us a locked buffer, the HAMMER 388fbc6e32aSMatthew Dillon * structure had better not believe it has a lock on the buffer. 389fbc6e32aSMatthew Dillon */ 39066325755SMatthew Dillon KKASSERT(io->io.released); 39166325755SMatthew Dillon crit_enter(); 3928cd0a023SMatthew Dillon 3938cd0a023SMatthew Dillon /* 3948cd0a023SMatthew Dillon * First, ref the structure to prevent either the buffer or the 395a89aec1bSMatthew Dillon * structure from going away or being unexpectedly flushed. 3968cd0a023SMatthew Dillon */ 3978cd0a023SMatthew Dillon hammer_ref(&io->io.lock); 3988cd0a023SMatthew Dillon 3998cd0a023SMatthew Dillon /* 4008cd0a023SMatthew Dillon * Buffers can have active references from cached hammer_node's, 4018cd0a023SMatthew Dillon * even if those nodes are themselves passively cached. Attempt 4028cd0a023SMatthew Dillon * to clean them out. This may not succeed. 4038cd0a023SMatthew Dillon */ 4048cd0a023SMatthew Dillon if (io->io.type == HAMMER_STRUCTURE_BUFFER && 4058cd0a023SMatthew Dillon hammer_lock_ex_try(&io->io.lock) == 0) { 4068cd0a023SMatthew Dillon hammer_flush_buffer_nodes(&io->buffer); 4078cd0a023SMatthew Dillon hammer_unlock(&io->io.lock); 4088cd0a023SMatthew Dillon } 4098cd0a023SMatthew Dillon 4108cd0a023SMatthew Dillon if (hammer_islastref(&io->io.lock)) { 4118cd0a023SMatthew Dillon /* 412fbc6e32aSMatthew Dillon * If we are the only ref left we can disassociate the I/O. 413fbc6e32aSMatthew Dillon * It had better still be in a released state because the 414fbc6e32aSMatthew Dillon * kernel is holding a lock on the buffer. Any passive 415fbc6e32aSMatthew Dillon * modifications should have already been synchronized with 416fbc6e32aSMatthew Dillon * the buffer. 4178cd0a023SMatthew Dillon */ 4188cd0a023SMatthew Dillon KKASSERT(io->io.released); 4198cd0a023SMatthew Dillon hammer_io_disassociate(io); 4208cd0a023SMatthew Dillon bp->b_flags &= ~B_LOCKED; 421fbc6e32aSMatthew Dillon KKASSERT (io->io.modified == 0 || (bp->b_flags & B_DELWRI)); 4228cd0a023SMatthew Dillon 423a89aec1bSMatthew Dillon /* 424a89aec1bSMatthew Dillon * Perform final rights on the structure. This can cause 425a89aec1bSMatthew Dillon * a chain reaction - e.g. last buffer -> last cluster -> 426a89aec1bSMatthew Dillon * last supercluster -> last volume. 427a89aec1bSMatthew Dillon */ 42866325755SMatthew Dillon switch(io->io.type) { 42966325755SMatthew Dillon case HAMMER_STRUCTURE_VOLUME: 4308cd0a023SMatthew Dillon hammer_rel_volume(&io->volume, 1); 43166325755SMatthew Dillon break; 43266325755SMatthew Dillon case HAMMER_STRUCTURE_SUPERCL: 4338cd0a023SMatthew Dillon hammer_rel_supercl(&io->supercl, 1); 43466325755SMatthew Dillon break; 43566325755SMatthew Dillon case HAMMER_STRUCTURE_CLUSTER: 4368cd0a023SMatthew Dillon hammer_rel_cluster(&io->cluster, 1); 43766325755SMatthew Dillon break; 43866325755SMatthew Dillon case HAMMER_STRUCTURE_BUFFER: 4398cd0a023SMatthew Dillon hammer_rel_buffer(&io->buffer, 1); 44066325755SMatthew Dillon break; 44166325755SMatthew Dillon } 4428cd0a023SMatthew Dillon } else { 4438cd0a023SMatthew Dillon /* 444a89aec1bSMatthew Dillon * Otherwise tell the kernel not to destroy the buffer. 445a89aec1bSMatthew Dillon * 446a89aec1bSMatthew Dillon * We have to unref the structure without performing any 447a89aec1bSMatthew Dillon * final rights to it to avoid a deadlock. 4488cd0a023SMatthew Dillon */ 4498cd0a023SMatthew Dillon bp->b_flags |= B_LOCKED; 450a89aec1bSMatthew Dillon hammer_unref(&io->io.lock); 45166325755SMatthew Dillon } 452a89aec1bSMatthew Dillon 45366325755SMatthew Dillon crit_exit(); 45466325755SMatthew Dillon } 45566325755SMatthew Dillon 45666325755SMatthew Dillon static int 45766325755SMatthew Dillon hammer_io_fsync(struct vnode *vp) 45866325755SMatthew Dillon { 45966325755SMatthew Dillon return(0); 46066325755SMatthew Dillon } 46166325755SMatthew Dillon 46266325755SMatthew Dillon /* 46366325755SMatthew Dillon * NOTE: will not be called unless we tell the kernel about the 46466325755SMatthew Dillon * bioops. Unused... we use the mount's VFS_SYNC instead. 46566325755SMatthew Dillon */ 46666325755SMatthew Dillon static int 46766325755SMatthew Dillon hammer_io_sync(struct mount *mp) 46866325755SMatthew Dillon { 46966325755SMatthew Dillon return(0); 47066325755SMatthew Dillon } 47166325755SMatthew Dillon 47266325755SMatthew Dillon static void 47366325755SMatthew Dillon hammer_io_movedeps(struct buf *bp1, struct buf *bp2) 47466325755SMatthew Dillon { 47566325755SMatthew Dillon } 47666325755SMatthew Dillon 47766325755SMatthew Dillon /* 47866325755SMatthew Dillon * I/O pre-check for reading and writing. HAMMER only uses this for 47966325755SMatthew Dillon * B_CACHE buffers so checkread just shouldn't happen, but if it does 48066325755SMatthew Dillon * allow it. 48166325755SMatthew Dillon * 482fbc6e32aSMatthew Dillon * Writing is a different case. We don't want the kernel to try to write 483fbc6e32aSMatthew Dillon * out a buffer that HAMMER may be modifying passively or which has a 484fbc6e32aSMatthew Dillon * dependancy. 485fbc6e32aSMatthew Dillon * 486fbc6e32aSMatthew Dillon * This code enforces the following write ordering: buffers, then cluster 487fbc6e32aSMatthew Dillon * headers, then volume headers. 48866325755SMatthew Dillon */ 48966325755SMatthew Dillon static int 49066325755SMatthew Dillon hammer_io_checkread(struct buf *bp) 49166325755SMatthew Dillon { 49266325755SMatthew Dillon return(0); 49366325755SMatthew Dillon } 49466325755SMatthew Dillon 49566325755SMatthew Dillon static int 49666325755SMatthew Dillon hammer_io_checkwrite(struct buf *bp) 49766325755SMatthew Dillon { 498fbc6e32aSMatthew Dillon union hammer_io_structure *iou = (void *)LIST_FIRST(&bp->b_dep); 49966325755SMatthew Dillon 500fbc6e32aSMatthew Dillon if (iou->io.type == HAMMER_STRUCTURE_BUFFER && 501fbc6e32aSMatthew Dillon iou->buffer.cluster->state == HAMMER_CLUSTER_ASYNC) { 502fbc6e32aSMatthew Dillon /* 503fbc6e32aSMatthew Dillon * Cannot write out a cluster buffer if the cluster header 504fbc6e32aSMatthew Dillon * I/O opening the cluster has not completed. 505fbc6e32aSMatthew Dillon */ 506fbc6e32aSMatthew Dillon kprintf("hammer_io_checkwrite: w/ depend - delayed\n"); 507fbc6e32aSMatthew Dillon bp->b_flags |= B_LOCKED; 508fbc6e32aSMatthew Dillon return(-1); 509fbc6e32aSMatthew Dillon } else if (iou->io.lock.refs) { 510fbc6e32aSMatthew Dillon /* 511fbc6e32aSMatthew Dillon * Cannot write out a bp if its associated buffer has active 512fbc6e32aSMatthew Dillon * references. 513fbc6e32aSMatthew Dillon */ 514fbc6e32aSMatthew Dillon kprintf("hammer_io_checkwrite: w/ refs - delayed\n"); 51566325755SMatthew Dillon bp->b_flags |= B_LOCKED; 51666325755SMatthew Dillon return(-1); 51766325755SMatthew Dillon } else { 518fbc6e32aSMatthew Dillon /* 519fbc6e32aSMatthew Dillon * We're good, but before we can let the kernel proceed we 520fbc6e32aSMatthew Dillon * may have to make some adjustments. 521fbc6e32aSMatthew Dillon */ 522fbc6e32aSMatthew Dillon if (iou->io.type == HAMMER_STRUCTURE_CLUSTER) 523fbc6e32aSMatthew Dillon hammer_close_cluster(&iou->cluster); 524fbc6e32aSMatthew Dillon kprintf("hammer_io_checkwrite: ok\n"); 525fbc6e32aSMatthew Dillon KKASSERT(iou->io.released); 526fbc6e32aSMatthew Dillon hammer_io_disassociate(iou); 52766325755SMatthew Dillon return(0); 52866325755SMatthew Dillon } 52966325755SMatthew Dillon } 53066325755SMatthew Dillon 5318cd0a023SMatthew Dillon /* 5328cd0a023SMatthew Dillon * Return non-zero if the caller should flush the structure associated 5338cd0a023SMatthew Dillon * with this io sub-structure. 5348cd0a023SMatthew Dillon */ 5358cd0a023SMatthew Dillon int 5368cd0a023SMatthew Dillon hammer_io_checkflush(struct hammer_io *io) 5378cd0a023SMatthew Dillon { 5388cd0a023SMatthew Dillon if (io->bp == NULL || (io->bp->b_flags & B_LOCKED)) 5398cd0a023SMatthew Dillon return(1); 5408cd0a023SMatthew Dillon return(0); 5418cd0a023SMatthew Dillon } 54266325755SMatthew Dillon 54366325755SMatthew Dillon /* 54466325755SMatthew Dillon * Return non-zero if we wish to delay the kernel's attempt to flush 54566325755SMatthew Dillon * this buffer to disk. 54666325755SMatthew Dillon */ 54766325755SMatthew Dillon static int 54866325755SMatthew Dillon hammer_io_countdeps(struct buf *bp, int n) 54966325755SMatthew Dillon { 55066325755SMatthew Dillon return(0); 55166325755SMatthew Dillon } 55266325755SMatthew Dillon 55366325755SMatthew Dillon struct bio_ops hammer_bioops = { 55466325755SMatthew Dillon .io_start = hammer_io_start, 55566325755SMatthew Dillon .io_complete = hammer_io_complete, 55666325755SMatthew Dillon .io_deallocate = hammer_io_deallocate, 55766325755SMatthew Dillon .io_fsync = hammer_io_fsync, 55866325755SMatthew Dillon .io_sync = hammer_io_sync, 55966325755SMatthew Dillon .io_movedeps = hammer_io_movedeps, 56066325755SMatthew Dillon .io_countdeps = hammer_io_countdeps, 56166325755SMatthew Dillon .io_checkread = hammer_io_checkread, 56266325755SMatthew Dillon .io_checkwrite = hammer_io_checkwrite, 56366325755SMatthew Dillon }; 56466325755SMatthew Dillon 565