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*d8971d2bSMatthew Dillon * $DragonFly: src/sys/vfs/hammer/hammer_io.c,v 1.16 2008/01/11 05:45:19 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 55055f5ff8SMatthew Dillon static void hammer_io_deallocate(struct buf *bp); 56055f5ff8SMatthew Dillon static int hammer_io_checkwrite(struct buf *bp); 57055f5ff8SMatthew Dillon 58055f5ff8SMatthew Dillon /* 59055f5ff8SMatthew Dillon * Initialize an already-zero'd hammer_io structure 60055f5ff8SMatthew Dillon */ 61055f5ff8SMatthew Dillon void 62055f5ff8SMatthew Dillon hammer_io_init(hammer_io_t io, enum hammer_io_type type) 63055f5ff8SMatthew Dillon { 64055f5ff8SMatthew Dillon io->type = type; 65055f5ff8SMatthew Dillon TAILQ_INIT(&io->deplist); 66055f5ff8SMatthew Dillon } 67055f5ff8SMatthew Dillon 6866325755SMatthew Dillon /* 69fbc6e32aSMatthew Dillon * Helper routine to disassociate a buffer cache buffer from an I/O 70055f5ff8SMatthew Dillon * structure. Called with the io structure exclusively locked. 71055f5ff8SMatthew Dillon * 72055f5ff8SMatthew Dillon * The io may have 0 or 1 references depending on who called us. The 73055f5ff8SMatthew Dillon * caller is responsible for dealing with the refs. 74055f5ff8SMatthew Dillon * 75055f5ff8SMatthew Dillon * This call can only be made when no action is required on the buffer. 76*d8971d2bSMatthew Dillon * HAMMER must own the buffer (released == 0) since we mess around with it. 7766325755SMatthew Dillon */ 7866325755SMatthew Dillon static void 79055f5ff8SMatthew Dillon hammer_io_disassociate(hammer_io_structure_t iou, int elseit) 8066325755SMatthew Dillon { 81055f5ff8SMatthew Dillon struct buf *bp = iou->io.bp; 8266325755SMatthew Dillon 83055f5ff8SMatthew Dillon KKASSERT(TAILQ_EMPTY(&iou->io.deplist) && iou->io.modified == 0); 844d75d829SMatthew Dillon buf_dep_init(bp); 85055f5ff8SMatthew Dillon iou->io.bp = NULL; 86*d8971d2bSMatthew Dillon bp->b_flags &= ~B_LOCKED; 87055f5ff8SMatthew Dillon if (elseit) { 88055f5ff8SMatthew Dillon KKASSERT(iou->io.released == 0); 89055f5ff8SMatthew Dillon iou->io.released = 1; 90055f5ff8SMatthew Dillon bqrelse(bp); 91055f5ff8SMatthew Dillon } else { 92055f5ff8SMatthew Dillon KKASSERT(iou->io.released); 93055f5ff8SMatthew Dillon } 9466325755SMatthew Dillon 95055f5ff8SMatthew Dillon switch(iou->io.type) { 9666325755SMatthew Dillon case HAMMER_STRUCTURE_VOLUME: 97055f5ff8SMatthew Dillon iou->volume.ondisk = NULL; 98055f5ff8SMatthew Dillon iou->volume.alist.meta = NULL; 9966325755SMatthew Dillon break; 10066325755SMatthew Dillon case HAMMER_STRUCTURE_SUPERCL: 101055f5ff8SMatthew Dillon iou->supercl.ondisk = NULL; 102055f5ff8SMatthew Dillon iou->supercl.alist.meta = NULL; 10366325755SMatthew Dillon break; 10466325755SMatthew Dillon case HAMMER_STRUCTURE_CLUSTER: 105055f5ff8SMatthew Dillon iou->cluster.ondisk = NULL; 106055f5ff8SMatthew Dillon iou->cluster.alist_master.meta = NULL; 107055f5ff8SMatthew Dillon iou->cluster.alist_btree.meta = NULL; 108055f5ff8SMatthew Dillon iou->cluster.alist_record.meta = NULL; 109055f5ff8SMatthew Dillon iou->cluster.alist_mdata.meta = NULL; 11066325755SMatthew Dillon break; 11166325755SMatthew Dillon case HAMMER_STRUCTURE_BUFFER: 112055f5ff8SMatthew Dillon iou->buffer.ondisk = NULL; 113055f5ff8SMatthew Dillon iou->buffer.alist.meta = NULL; 11466325755SMatthew Dillon break; 11566325755SMatthew Dillon } 11666325755SMatthew Dillon } 117fbc6e32aSMatthew Dillon 118fbc6e32aSMatthew Dillon /* 119055f5ff8SMatthew Dillon * Wait for any physical IO to complete 120fbc6e32aSMatthew Dillon */ 121fbc6e32aSMatthew Dillon static void 122055f5ff8SMatthew Dillon hammer_io_wait(hammer_io_t io) 123fbc6e32aSMatthew Dillon { 124055f5ff8SMatthew Dillon if (io->running) { 125055f5ff8SMatthew Dillon crit_enter(); 126055f5ff8SMatthew Dillon tsleep_interlock(io); 127055f5ff8SMatthew Dillon io->waiting = 1; 128055f5ff8SMatthew Dillon for (;;) { 129055f5ff8SMatthew Dillon tsleep(io, 0, "hmrflw", 0); 130055f5ff8SMatthew Dillon if (io->running == 0) 131055f5ff8SMatthew Dillon break; 132055f5ff8SMatthew Dillon tsleep_interlock(io); 133055f5ff8SMatthew Dillon io->waiting = 1; 134055f5ff8SMatthew Dillon if (io->running == 0) 135055f5ff8SMatthew Dillon break; 136055f5ff8SMatthew Dillon } 137055f5ff8SMatthew Dillon crit_exit(); 138055f5ff8SMatthew Dillon } 139055f5ff8SMatthew Dillon } 140055f5ff8SMatthew Dillon 141055f5ff8SMatthew Dillon void 142055f5ff8SMatthew Dillon hammer_io_waitdep(hammer_io_t io) 143055f5ff8SMatthew Dillon { 144055f5ff8SMatthew Dillon while (TAILQ_FIRST(&io->deplist)) { 145055f5ff8SMatthew Dillon kprintf("waitdep %p\n", io); 146055f5ff8SMatthew Dillon tsleep(io, 0, "hmrdep", hz); 14766325755SMatthew Dillon } 148fbc6e32aSMatthew Dillon } 149fbc6e32aSMatthew Dillon 15061aeeb33SMatthew Dillon /* 151055f5ff8SMatthew Dillon * Load bp for a HAMMER structure. The io is exclusively locked by the 152055f5ff8SMatthew Dillon * caller. 15366325755SMatthew Dillon */ 15466325755SMatthew Dillon int 15566325755SMatthew Dillon hammer_io_read(struct vnode *devvp, struct hammer_io *io) 15666325755SMatthew Dillon { 15766325755SMatthew Dillon struct buf *bp; 15866325755SMatthew Dillon int error; 15966325755SMatthew Dillon 16066325755SMatthew Dillon if ((bp = io->bp) == NULL) { 16166325755SMatthew Dillon error = bread(devvp, io->offset, HAMMER_BUFSIZE, &io->bp); 16266325755SMatthew Dillon if (error == 0) { 16366325755SMatthew Dillon bp = io->bp; 16466325755SMatthew Dillon bp->b_ops = &hammer_bioops; 16566325755SMatthew Dillon LIST_INSERT_HEAD(&bp->b_dep, &io->worklist, node); 16666325755SMatthew Dillon BUF_KERNPROC(bp); 16766325755SMatthew Dillon } 16866325755SMatthew Dillon io->modified = 0; /* no new modifications yet */ 16966325755SMatthew Dillon io->released = 0; /* we hold an active lock on bp */ 170055f5ff8SMatthew Dillon io->running = 0; 171055f5ff8SMatthew Dillon io->waiting = 0; 17266325755SMatthew Dillon } else { 17366325755SMatthew Dillon error = 0; 17466325755SMatthew Dillon } 17566325755SMatthew Dillon return(error); 17666325755SMatthew Dillon } 17766325755SMatthew Dillon 17866325755SMatthew Dillon /* 17966325755SMatthew Dillon * Similar to hammer_io_read() but returns a zero'd out buffer instead. 18066325755SMatthew Dillon * vfs_bio_clrbuf() is kinda nasty, enforce serialization against background 18166325755SMatthew Dillon * I/O so we can call it. 182055f5ff8SMatthew Dillon * 183055f5ff8SMatthew Dillon * The caller is responsible for calling hammer_modify_*() on the appropriate 184055f5ff8SMatthew Dillon * HAMMER structure. 18566325755SMatthew Dillon */ 18666325755SMatthew Dillon int 18766325755SMatthew Dillon hammer_io_new(struct vnode *devvp, struct hammer_io *io) 18866325755SMatthew Dillon { 18966325755SMatthew Dillon struct buf *bp; 19066325755SMatthew Dillon 19166325755SMatthew Dillon if ((bp = io->bp) == NULL) { 19266325755SMatthew Dillon io->bp = getblk(devvp, io->offset, HAMMER_BUFSIZE, 0, 0); 19366325755SMatthew Dillon bp = io->bp; 19466325755SMatthew Dillon bp->b_ops = &hammer_bioops; 19566325755SMatthew Dillon LIST_INSERT_HEAD(&bp->b_dep, &io->worklist, node); 196055f5ff8SMatthew Dillon io->modified = 0; 197055f5ff8SMatthew Dillon io->released = 0; 198055f5ff8SMatthew Dillon io->running = 0; 199055f5ff8SMatthew Dillon io->waiting = 0; 20066325755SMatthew Dillon BUF_KERNPROC(bp); 20166325755SMatthew Dillon } else { 20266325755SMatthew Dillon if (io->released) { 20366325755SMatthew Dillon regetblk(bp); 20466325755SMatthew Dillon BUF_KERNPROC(bp); 205d113fda1SMatthew Dillon io->released = 0; 20666325755SMatthew Dillon } 20766325755SMatthew Dillon } 20866325755SMatthew Dillon vfs_bio_clrbuf(bp); 20966325755SMatthew Dillon return(0); 21066325755SMatthew Dillon } 21166325755SMatthew Dillon 21266325755SMatthew Dillon /* 213b3deaf57SMatthew Dillon * This routine is called on the last reference to a hammer structure. 214055f5ff8SMatthew Dillon * The io is usually locked exclusively (but may not be during unmount). 215b3deaf57SMatthew Dillon * 216055f5ff8SMatthew Dillon * If flush is 1, or B_LOCKED was set indicating that the kernel 217055f5ff8SMatthew Dillon * wanted to recycle the buffer, and there are no dependancies, this 218055f5ff8SMatthew Dillon * function will issue an asynchronous write. 21966325755SMatthew Dillon * 220055f5ff8SMatthew Dillon * If flush is 2 this function waits until all I/O has completed and 221055f5ff8SMatthew Dillon * disassociates the bp from the IO before returning, unless there 222055f5ff8SMatthew Dillon * are still other references. 22366325755SMatthew Dillon */ 22466325755SMatthew Dillon void 22566325755SMatthew Dillon hammer_io_release(struct hammer_io *io, int flush) 22666325755SMatthew Dillon { 22766325755SMatthew Dillon struct buf *bp; 22866325755SMatthew Dillon 229fbc6e32aSMatthew Dillon if ((bp = io->bp) == NULL) 230fbc6e32aSMatthew Dillon return; 231fbc6e32aSMatthew Dillon 232055f5ff8SMatthew Dillon #if 0 2330b075555SMatthew Dillon /* 234055f5ff8SMatthew Dillon * If flush is 2 wait for dependancies 2350b075555SMatthew Dillon */ 236055f5ff8SMatthew Dillon while (flush == 2 && TAILQ_FIRST(&io->deplist)) { 237055f5ff8SMatthew Dillon hammer_io_wait(TAILQ_FIRST(&io->deplist)); 2380b075555SMatthew Dillon } 239055f5ff8SMatthew Dillon #endif 2400b075555SMatthew Dillon 2410b075555SMatthew Dillon /* 242055f5ff8SMatthew Dillon * Try to flush a dirty IO to disk if asked to by the caller 243055f5ff8SMatthew Dillon * or if the kernel tried to flush the buffer in the past. 2440b075555SMatthew Dillon * 245055f5ff8SMatthew Dillon * The flush will fail if any dependancies are present. 246055f5ff8SMatthew Dillon */ 247055f5ff8SMatthew Dillon if (io->modified && (flush || bp->b_flags & B_LOCKED)) 248055f5ff8SMatthew Dillon hammer_io_flush(io); 249055f5ff8SMatthew Dillon 250055f5ff8SMatthew Dillon /* 251055f5ff8SMatthew Dillon * If flush is 2 we wait for the IO to complete. 252055f5ff8SMatthew Dillon */ 253055f5ff8SMatthew Dillon if (flush == 2 && io->running) { 254055f5ff8SMatthew Dillon hammer_io_wait(io); 255055f5ff8SMatthew Dillon } 256055f5ff8SMatthew Dillon 257055f5ff8SMatthew Dillon /* 258055f5ff8SMatthew Dillon * Actively or passively release the buffer. Modified IOs with 259055f5ff8SMatthew Dillon * dependancies cannot be released. 260055f5ff8SMatthew Dillon */ 261055f5ff8SMatthew Dillon if (flush && io->modified == 0 && io->running == 0) { 262055f5ff8SMatthew Dillon KKASSERT(TAILQ_EMPTY(&io->deplist)); 263055f5ff8SMatthew Dillon if (io->released) { 264055f5ff8SMatthew Dillon regetblk(bp); 265055f5ff8SMatthew Dillon io->released = 0; 266055f5ff8SMatthew Dillon } 267055f5ff8SMatthew Dillon hammer_io_disassociate((hammer_io_structure_t)io, 1); 268055f5ff8SMatthew Dillon } else if (io->modified) { 269055f5ff8SMatthew Dillon if (io->released == 0 && TAILQ_EMPTY(&io->deplist)) { 270055f5ff8SMatthew Dillon io->released = 1; 271055f5ff8SMatthew Dillon bdwrite(bp); 272055f5ff8SMatthew Dillon } 273055f5ff8SMatthew Dillon } else if (io->released == 0) { 274055f5ff8SMatthew Dillon io->released = 1; 275055f5ff8SMatthew Dillon bqrelse(bp); 276055f5ff8SMatthew Dillon } 277055f5ff8SMatthew Dillon } 278055f5ff8SMatthew Dillon 279055f5ff8SMatthew Dillon /* 280055f5ff8SMatthew Dillon * This routine is called with a locked IO when a flush is desired. 2810b075555SMatthew Dillon */ 2820b075555SMatthew Dillon void 283055f5ff8SMatthew Dillon hammer_io_flush(struct hammer_io *io) 2840b075555SMatthew Dillon { 285055f5ff8SMatthew Dillon struct buf *bp; 286055f5ff8SMatthew Dillon 287055f5ff8SMatthew Dillon /* 288055f5ff8SMatthew Dillon * Can't flush if the IO isn't modified or if it has dependancies. 289055f5ff8SMatthew Dillon */ 290055f5ff8SMatthew Dillon if (io->modified == 0) 291055f5ff8SMatthew Dillon return; 292055f5ff8SMatthew Dillon if (TAILQ_FIRST(&io->deplist)) 293055f5ff8SMatthew Dillon return; 294055f5ff8SMatthew Dillon 295055f5ff8SMatthew Dillon KKASSERT(io->bp); 296055f5ff8SMatthew Dillon 297055f5ff8SMatthew Dillon bp = io->bp; 298055f5ff8SMatthew Dillon 299055f5ff8SMatthew Dillon /* 300055f5ff8SMatthew Dillon * If we are trying to flush a buffer we have to wait until the 301055f5ff8SMatthew Dillon * cluster header for the mark-OPEN has completed its I/O. 302055f5ff8SMatthew Dillon */ 303055f5ff8SMatthew Dillon if (io->type == HAMMER_STRUCTURE_BUFFER) { 304055f5ff8SMatthew Dillon hammer_io_structure_t iou = (void *)io; 305055f5ff8SMatthew Dillon hammer_cluster_t cluster = iou->buffer.cluster; 306055f5ff8SMatthew Dillon 307055f5ff8SMatthew Dillon if (cluster->io.running) { 308055f5ff8SMatthew Dillon kprintf("WAIT CLUSTER OPEN %d\n", cluster->clu_no); 309055f5ff8SMatthew Dillon hammer_io_wait(&cluster->io); 310055f5ff8SMatthew Dillon kprintf("WAIT CLUSTER OPEN OK\n"); 311055f5ff8SMatthew Dillon } 312055f5ff8SMatthew Dillon } 313055f5ff8SMatthew Dillon if (io->type == HAMMER_STRUCTURE_CLUSTER) { 314055f5ff8SMatthew Dillon /* 315055f5ff8SMatthew Dillon * Mark the cluster closed if we can 316055f5ff8SMatthew Dillon */ 317055f5ff8SMatthew Dillon hammer_io_checkwrite(io->bp); 318055f5ff8SMatthew Dillon } 3190b075555SMatthew Dillon if (io->released) { 320055f5ff8SMatthew Dillon regetblk(bp); 321055f5ff8SMatthew Dillon /* BUF_KERNPROC(io->bp); */ 322055f5ff8SMatthew Dillon io->released = 0; 323055f5ff8SMatthew Dillon } 324055f5ff8SMatthew Dillon io->released = 1; 325055f5ff8SMatthew Dillon io->running = 1; 326055f5ff8SMatthew Dillon bawrite(bp); 327055f5ff8SMatthew Dillon } 328055f5ff8SMatthew Dillon 329055f5ff8SMatthew Dillon /************************************************************************ 330055f5ff8SMatthew Dillon * BUFFER DIRTYING * 331055f5ff8SMatthew Dillon ************************************************************************ 332055f5ff8SMatthew Dillon * 333055f5ff8SMatthew Dillon * These routines deal with dependancies created when IO buffers get 334055f5ff8SMatthew Dillon * modified. The caller must call hammer_modify_*() on a referenced 335055f5ff8SMatthew Dillon * HAMMER structure prior to modifying its on-disk data. 336055f5ff8SMatthew Dillon * 337055f5ff8SMatthew Dillon * Any intent to modify an IO buffer acquires the related bp and imposes 338055f5ff8SMatthew Dillon * various write ordering dependancies. 339055f5ff8SMatthew Dillon */ 340055f5ff8SMatthew Dillon 341055f5ff8SMatthew Dillon /* 342055f5ff8SMatthew Dillon * Ensure that the bp is acquired and return non-zero on a 0->1 transition 343055f5ff8SMatthew Dillon * of the modified bit. 344055f5ff8SMatthew Dillon */ 345055f5ff8SMatthew Dillon static __inline 346055f5ff8SMatthew Dillon int 347055f5ff8SMatthew Dillon hammer_io_modify(hammer_io_t io, struct hammer_io_list *list) 348055f5ff8SMatthew Dillon { 349055f5ff8SMatthew Dillon int r = 0; 350055f5ff8SMatthew Dillon 351055f5ff8SMatthew Dillon KKASSERT(io->lock.refs != 0 && io->bp != NULL); 352055f5ff8SMatthew Dillon if (io->modified == 0) { 353055f5ff8SMatthew Dillon hammer_lock_ex(&io->lock); 354055f5ff8SMatthew Dillon if (io->modified == 0) { 355055f5ff8SMatthew Dillon if (io->released) { 356055f5ff8SMatthew Dillon regetblk(io->bp); 357055f5ff8SMatthew Dillon BUF_KERNPROC(io->bp); 358055f5ff8SMatthew Dillon io->released = 0; 359055f5ff8SMatthew Dillon } 360055f5ff8SMatthew Dillon io->modified = 1; 361055f5ff8SMatthew Dillon io->entry_list = list; 362055f5ff8SMatthew Dillon if (list) 363055f5ff8SMatthew Dillon TAILQ_INSERT_TAIL(list, io, entry); 364055f5ff8SMatthew Dillon r = 1; 365055f5ff8SMatthew Dillon } 366055f5ff8SMatthew Dillon hammer_unlock(&io->lock); 367055f5ff8SMatthew Dillon } else if (io->released) { 368055f5ff8SMatthew Dillon /* 369055f5ff8SMatthew Dillon * Make sure no IO is occuring while we modify the contents 370055f5ff8SMatthew Dillon * of the buffer. XXX should be able to avoid doing this. 371055f5ff8SMatthew Dillon */ 3720b075555SMatthew Dillon hammer_lock_ex(&io->lock); 3730b075555SMatthew Dillon if (io->released) { 3740b075555SMatthew Dillon regetblk(io->bp); 3750b075555SMatthew Dillon BUF_KERNPROC(io->bp); 376d113fda1SMatthew Dillon io->released = 0; 3770b075555SMatthew Dillon } 3780b075555SMatthew Dillon hammer_unlock(&io->lock); 3790b075555SMatthew Dillon } 380055f5ff8SMatthew Dillon return(r); 3810b075555SMatthew Dillon } 3820b075555SMatthew Dillon 3830b075555SMatthew Dillon void 384055f5ff8SMatthew Dillon hammer_modify_volume(hammer_volume_t volume) 3850b075555SMatthew Dillon { 386055f5ff8SMatthew Dillon hammer_io_modify(&volume->io, NULL); 387055f5ff8SMatthew Dillon } 388055f5ff8SMatthew Dillon 389055f5ff8SMatthew Dillon void 390055f5ff8SMatthew Dillon hammer_modify_supercl(hammer_supercl_t supercl) 391055f5ff8SMatthew Dillon { 392055f5ff8SMatthew Dillon hammer_io_modify(&supercl->io, &supercl->volume->io.deplist); 393055f5ff8SMatthew Dillon } 394055f5ff8SMatthew Dillon 395055f5ff8SMatthew Dillon /* 396055f5ff8SMatthew Dillon * Caller intends to modify a cluster's ondisk structure. 397055f5ff8SMatthew Dillon */ 398055f5ff8SMatthew Dillon void 399055f5ff8SMatthew Dillon hammer_modify_cluster(hammer_cluster_t cluster) 400055f5ff8SMatthew Dillon { 401055f5ff8SMatthew Dillon hammer_io_modify(&cluster->io, &cluster->volume->io.deplist); 402055f5ff8SMatthew Dillon } 403055f5ff8SMatthew Dillon 404055f5ff8SMatthew Dillon /* 405055f5ff8SMatthew Dillon * Caller intends to modify a buffer's ondisk structure. The related 406055f5ff8SMatthew Dillon * cluster must be marked open prior to being able to flush the modified 407055f5ff8SMatthew Dillon * buffer so get that I/O going now. 408055f5ff8SMatthew Dillon */ 409055f5ff8SMatthew Dillon void 410055f5ff8SMatthew Dillon hammer_modify_buffer(hammer_buffer_t buffer) 411055f5ff8SMatthew Dillon { 412055f5ff8SMatthew Dillon hammer_cluster_t cluster = buffer->cluster; 413055f5ff8SMatthew Dillon 414055f5ff8SMatthew Dillon if (hammer_io_modify(&buffer->io, &cluster->io.deplist)) { 415055f5ff8SMatthew Dillon hammer_modify_cluster(cluster); 416055f5ff8SMatthew Dillon if ((cluster->ondisk->clu_flags & HAMMER_CLUF_OPEN) == 0) { 417055f5ff8SMatthew Dillon hammer_lock_ex(&cluster->io.lock); 418055f5ff8SMatthew Dillon if ((cluster->ondisk->clu_flags & HAMMER_CLUF_OPEN) == 0) { 419055f5ff8SMatthew Dillon KKASSERT(cluster->io.released == 0); 420055f5ff8SMatthew Dillon cluster->ondisk->clu_flags |= HAMMER_CLUF_OPEN; 421055f5ff8SMatthew Dillon cluster->io.released = 1; 422055f5ff8SMatthew Dillon cluster->io.running = 1; 423055f5ff8SMatthew Dillon bawrite(cluster->io.bp); 424f3b0f382SMatthew Dillon kprintf("OPEN CLUSTER %d:%d\n", 425f3b0f382SMatthew Dillon cluster->volume->vol_no, 426f3b0f382SMatthew Dillon cluster->clu_no); 427055f5ff8SMatthew Dillon } 428055f5ff8SMatthew Dillon hammer_unlock(&cluster->io.lock); 429055f5ff8SMatthew Dillon } 4300b075555SMatthew Dillon } 4310b075555SMatthew Dillon } 43266325755SMatthew Dillon 43366325755SMatthew Dillon /* 434055f5ff8SMatthew Dillon * Mark an entity as not being dirty any more -- this usually occurs when 43561aeeb33SMatthew Dillon * the governing a-list has freed the entire entity. 436055f5ff8SMatthew Dillon * 437055f5ff8SMatthew Dillon * XXX 43861aeeb33SMatthew Dillon */ 43961aeeb33SMatthew Dillon void 44061aeeb33SMatthew Dillon hammer_io_clear_modify(struct hammer_io *io) 44161aeeb33SMatthew Dillon { 442055f5ff8SMatthew Dillon #if 0 44361aeeb33SMatthew Dillon struct buf *bp; 44461aeeb33SMatthew Dillon 44561aeeb33SMatthew Dillon io->modified = 0; 44661aeeb33SMatthew Dillon if ((bp = io->bp) != NULL) { 447055f5ff8SMatthew Dillon if (io->released) { 44861aeeb33SMatthew Dillon regetblk(bp); 449055f5ff8SMatthew Dillon /* BUF_KERNPROC(io->bp); */ 450055f5ff8SMatthew Dillon } else { 45161aeeb33SMatthew Dillon io->released = 1; 452055f5ff8SMatthew Dillon } 45361aeeb33SMatthew Dillon if (io->modified == 0) { 45461aeeb33SMatthew Dillon kprintf("hammer_io_clear_modify: cleared %p\n", io); 45561aeeb33SMatthew Dillon bundirty(bp); 45661aeeb33SMatthew Dillon bqrelse(bp); 45761aeeb33SMatthew Dillon } else { 45861aeeb33SMatthew Dillon bdwrite(bp); 45961aeeb33SMatthew Dillon } 46061aeeb33SMatthew Dillon } 461fbc6e32aSMatthew Dillon #endif 46266325755SMatthew Dillon } 46366325755SMatthew Dillon 464055f5ff8SMatthew Dillon /************************************************************************ 465055f5ff8SMatthew Dillon * HAMMER_BIOOPS * 466055f5ff8SMatthew Dillon ************************************************************************ 467055f5ff8SMatthew Dillon * 468055f5ff8SMatthew Dillon */ 469055f5ff8SMatthew Dillon 470055f5ff8SMatthew Dillon /* 471055f5ff8SMatthew Dillon * Pre-IO initiation kernel callback - cluster build only 472055f5ff8SMatthew Dillon */ 473055f5ff8SMatthew Dillon static void 474055f5ff8SMatthew Dillon hammer_io_start(struct buf *bp) 475055f5ff8SMatthew Dillon { 476055f5ff8SMatthew Dillon } 477055f5ff8SMatthew Dillon 478055f5ff8SMatthew Dillon /* 479055f5ff8SMatthew Dillon * Post-IO completion kernel callback 480055f5ff8SMatthew Dillon */ 48166325755SMatthew Dillon static void 48266325755SMatthew Dillon hammer_io_complete(struct buf *bp) 48366325755SMatthew Dillon { 484055f5ff8SMatthew Dillon union hammer_io_structure *iou = (void *)LIST_FIRST(&bp->b_dep); 485fbc6e32aSMatthew Dillon 486055f5ff8SMatthew Dillon KKASSERT(iou->io.released == 1); 487055f5ff8SMatthew Dillon 488055f5ff8SMatthew Dillon if (iou->io.modified == 0) 489055f5ff8SMatthew Dillon return; 490055f5ff8SMatthew Dillon 491055f5ff8SMatthew Dillon /* 492055f5ff8SMatthew Dillon * If we were writing the cluster header out and CLUF_OPEN is set, 493055f5ff8SMatthew Dillon * do NOT clear the modify bit. Just clear the IO running bit 494055f5ff8SMatthew Dillon * and do a wakeup. 495055f5ff8SMatthew Dillon */ 496055f5ff8SMatthew Dillon if (iou->io.type == HAMMER_STRUCTURE_CLUSTER) { 497055f5ff8SMatthew Dillon if (iou->cluster.ondisk->clu_flags & HAMMER_CLUF_OPEN) { 498055f5ff8SMatthew Dillon iou->io.running = 0; 499055f5ff8SMatthew Dillon if (iou->io.waiting) { 500055f5ff8SMatthew Dillon iou->io.waiting = 0; 501055f5ff8SMatthew Dillon wakeup(iou); 502fbc6e32aSMatthew Dillon } 503055f5ff8SMatthew Dillon return; 504055f5ff8SMatthew Dillon } 505055f5ff8SMatthew Dillon } 506055f5ff8SMatthew Dillon 507055f5ff8SMatthew Dillon 508055f5ff8SMatthew Dillon /* 509055f5ff8SMatthew Dillon * If this was a write then clear the modified status and remove us 510055f5ff8SMatthew Dillon * from the dependancy list. 511055f5ff8SMatthew Dillon * 512055f5ff8SMatthew Dillon * If no lock references remain and we can acquire the IO lock and 513055f5ff8SMatthew Dillon * someone at some point wanted us to flush (B_LOCKED test), then 514055f5ff8SMatthew Dillon * try to dispose of the IO. 515055f5ff8SMatthew Dillon */ 516055f5ff8SMatthew Dillon iou->io.modified = 0; 517055f5ff8SMatthew Dillon if (iou->io.entry_list) { 518055f5ff8SMatthew Dillon TAILQ_REMOVE(iou->io.entry_list, &iou->io, entry); 519055f5ff8SMatthew Dillon iou->io.entry_list = NULL; 520055f5ff8SMatthew Dillon } 521055f5ff8SMatthew Dillon iou->io.running = 0; 522055f5ff8SMatthew Dillon if (iou->io.waiting) { 523055f5ff8SMatthew Dillon iou->io.waiting = 0; 524055f5ff8SMatthew Dillon wakeup(iou); 525055f5ff8SMatthew Dillon } 526055f5ff8SMatthew Dillon 527055f5ff8SMatthew Dillon /* 528055f5ff8SMatthew Dillon * Someone wanted us to flush, try to clean out the buffer. 529055f5ff8SMatthew Dillon */ 530055f5ff8SMatthew Dillon if ((bp->b_flags & B_LOCKED) && iou->io.lock.refs == 0) { 531055f5ff8SMatthew Dillon hammer_io_deallocate(bp); 532055f5ff8SMatthew Dillon /* structure may be dead now */ 533fbc6e32aSMatthew Dillon } 53466325755SMatthew Dillon } 53566325755SMatthew Dillon 53666325755SMatthew Dillon /* 53766325755SMatthew Dillon * Callback from kernel when it wishes to deallocate a passively 538055f5ff8SMatthew Dillon * associated structure. This case can only occur with read-only 539055f5ff8SMatthew Dillon * bp's. 54066325755SMatthew Dillon * 54166325755SMatthew Dillon * If we cannot disassociate we set B_LOCKED to prevent the buffer 54266325755SMatthew Dillon * from getting reused. 54366325755SMatthew Dillon */ 54466325755SMatthew Dillon static void 54566325755SMatthew Dillon hammer_io_deallocate(struct buf *bp) 54666325755SMatthew Dillon { 547055f5ff8SMatthew Dillon hammer_io_structure_t iou = (void *)LIST_FIRST(&bp->b_dep); 54866325755SMatthew Dillon 549055f5ff8SMatthew Dillon KKASSERT((bp->b_flags & B_LOCKED) == 0 && iou->io.running == 0); 550055f5ff8SMatthew Dillon if (iou->io.modified) { 551055f5ff8SMatthew Dillon bp->b_flags |= B_LOCKED; 552055f5ff8SMatthew Dillon return; 5538cd0a023SMatthew Dillon } 554055f5ff8SMatthew Dillon hammer_ref(&iou->io.lock); 555055f5ff8SMatthew Dillon if (iou->io.lock.refs > 1 || iou->io.modified) { 556055f5ff8SMatthew Dillon hammer_unref(&iou->io.lock); 557055f5ff8SMatthew Dillon bp->b_flags |= B_LOCKED; 558055f5ff8SMatthew Dillon } else { 559055f5ff8SMatthew Dillon hammer_io_disassociate(iou, 0); 5608cd0a023SMatthew Dillon 561055f5ff8SMatthew Dillon switch(iou->io.type) { 56266325755SMatthew Dillon case HAMMER_STRUCTURE_VOLUME: 563055f5ff8SMatthew Dillon hammer_rel_volume(&iou->volume, 1); 56466325755SMatthew Dillon break; 56566325755SMatthew Dillon case HAMMER_STRUCTURE_SUPERCL: 566055f5ff8SMatthew Dillon hammer_rel_supercl(&iou->supercl, 1); 56766325755SMatthew Dillon break; 56866325755SMatthew Dillon case HAMMER_STRUCTURE_CLUSTER: 569055f5ff8SMatthew Dillon hammer_rel_cluster(&iou->cluster, 1); 57066325755SMatthew Dillon break; 57166325755SMatthew Dillon case HAMMER_STRUCTURE_BUFFER: 572055f5ff8SMatthew Dillon hammer_rel_buffer(&iou->buffer, 1); 57366325755SMatthew Dillon break; 57466325755SMatthew Dillon } 57566325755SMatthew Dillon } 57666325755SMatthew Dillon } 57766325755SMatthew Dillon 57866325755SMatthew Dillon static int 57966325755SMatthew Dillon hammer_io_fsync(struct vnode *vp) 58066325755SMatthew Dillon { 58166325755SMatthew Dillon return(0); 58266325755SMatthew Dillon } 58366325755SMatthew Dillon 58466325755SMatthew Dillon /* 58566325755SMatthew Dillon * NOTE: will not be called unless we tell the kernel about the 58666325755SMatthew Dillon * bioops. Unused... we use the mount's VFS_SYNC instead. 58766325755SMatthew Dillon */ 58866325755SMatthew Dillon static int 58966325755SMatthew Dillon hammer_io_sync(struct mount *mp) 59066325755SMatthew Dillon { 59166325755SMatthew Dillon return(0); 59266325755SMatthew Dillon } 59366325755SMatthew Dillon 59466325755SMatthew Dillon static void 59566325755SMatthew Dillon hammer_io_movedeps(struct buf *bp1, struct buf *bp2) 59666325755SMatthew Dillon { 59766325755SMatthew Dillon } 59866325755SMatthew Dillon 59966325755SMatthew Dillon /* 60066325755SMatthew Dillon * I/O pre-check for reading and writing. HAMMER only uses this for 60166325755SMatthew Dillon * B_CACHE buffers so checkread just shouldn't happen, but if it does 60266325755SMatthew Dillon * allow it. 60366325755SMatthew Dillon * 604fbc6e32aSMatthew Dillon * Writing is a different case. We don't want the kernel to try to write 605fbc6e32aSMatthew Dillon * out a buffer that HAMMER may be modifying passively or which has a 606fbc6e32aSMatthew Dillon * dependancy. 607fbc6e32aSMatthew Dillon * 608fbc6e32aSMatthew Dillon * This code enforces the following write ordering: buffers, then cluster 609fbc6e32aSMatthew Dillon * headers, then volume headers. 61066325755SMatthew Dillon */ 61166325755SMatthew Dillon static int 61266325755SMatthew Dillon hammer_io_checkread(struct buf *bp) 61366325755SMatthew Dillon { 61466325755SMatthew Dillon return(0); 61566325755SMatthew Dillon } 61666325755SMatthew Dillon 61766325755SMatthew Dillon static int 61866325755SMatthew Dillon hammer_io_checkwrite(struct buf *bp) 61966325755SMatthew Dillon { 620fbc6e32aSMatthew Dillon union hammer_io_structure *iou = (void *)LIST_FIRST(&bp->b_dep); 62166325755SMatthew Dillon 622fbc6e32aSMatthew Dillon /* 623055f5ff8SMatthew Dillon * A modified cluster with no dependancies can be closed. 624fbc6e32aSMatthew Dillon */ 625055f5ff8SMatthew Dillon if (iou->io.type == HAMMER_STRUCTURE_CLUSTER && iou->io.modified) { 626055f5ff8SMatthew Dillon hammer_cluster_t cluster = &iou->cluster; 627055f5ff8SMatthew Dillon 628055f5ff8SMatthew Dillon if (TAILQ_EMPTY(&cluster->io.deplist)) { 629055f5ff8SMatthew Dillon cluster->ondisk->clu_flags &= ~HAMMER_CLUF_OPEN; 630f3b0f382SMatthew Dillon kprintf("CLOSE CLUSTER %d:%d\n", 631f3b0f382SMatthew Dillon cluster->volume->vol_no, 632f3b0f382SMatthew Dillon cluster->clu_no); 63366325755SMatthew Dillon } 63466325755SMatthew Dillon } 635055f5ff8SMatthew Dillon return(0); 636055f5ff8SMatthew Dillon } 63766325755SMatthew Dillon 6388cd0a023SMatthew Dillon /* 6398cd0a023SMatthew Dillon * Return non-zero if the caller should flush the structure associated 6408cd0a023SMatthew Dillon * with this io sub-structure. 6418cd0a023SMatthew Dillon */ 6428cd0a023SMatthew Dillon int 6438cd0a023SMatthew Dillon hammer_io_checkflush(struct hammer_io *io) 6448cd0a023SMatthew Dillon { 645055f5ff8SMatthew Dillon if (io->bp == NULL || (io->bp->b_flags & B_LOCKED)) { 6468cd0a023SMatthew Dillon return(1); 647055f5ff8SMatthew Dillon } 6488cd0a023SMatthew Dillon return(0); 6498cd0a023SMatthew Dillon } 65066325755SMatthew Dillon 65166325755SMatthew Dillon /* 65266325755SMatthew Dillon * Return non-zero if we wish to delay the kernel's attempt to flush 65366325755SMatthew Dillon * this buffer to disk. 65466325755SMatthew Dillon */ 65566325755SMatthew Dillon static int 65666325755SMatthew Dillon hammer_io_countdeps(struct buf *bp, int n) 65766325755SMatthew Dillon { 65866325755SMatthew Dillon return(0); 65966325755SMatthew Dillon } 66066325755SMatthew Dillon 66166325755SMatthew Dillon struct bio_ops hammer_bioops = { 66266325755SMatthew Dillon .io_start = hammer_io_start, 66366325755SMatthew Dillon .io_complete = hammer_io_complete, 66466325755SMatthew Dillon .io_deallocate = hammer_io_deallocate, 66566325755SMatthew Dillon .io_fsync = hammer_io_fsync, 66666325755SMatthew Dillon .io_sync = hammer_io_sync, 66766325755SMatthew Dillon .io_movedeps = hammer_io_movedeps, 66866325755SMatthew Dillon .io_countdeps = hammer_io_countdeps, 66966325755SMatthew Dillon .io_checkread = hammer_io_checkread, 67066325755SMatthew Dillon .io_checkwrite = hammer_io_checkwrite, 67166325755SMatthew Dillon }; 67266325755SMatthew Dillon 673