1 /* 2 * Copyright (c) 2007 The DragonFly Project. All rights reserved. 3 * 4 * This code is derived from software contributed to The DragonFly Project 5 * by Matthew Dillon <dillon@backplane.com> 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 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 16 * distribution. 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. 20 * 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 32 * SUCH DAMAGE. 33 * 34 * $DragonFly: src/sys/vfs/hammer/hammer_io.c,v 1.2 2007/11/19 00:53:40 dillon Exp $ 35 */ 36 /* 37 * IO Primitives and buffer cache management 38 * 39 * All major data-tracking structures in HAMMER contain a struct hammer_io 40 * which is used to manage their backing store. We use filesystem buffers 41 * for backing store and we leave them passively associated with their 42 * HAMMER structures. 43 * 44 * If the kernel tries to release a passively associated buf which we cannot 45 * yet let go we set B_LOCKED in the buffer and then actively released it 46 * later when we can. 47 */ 48 49 #include "hammer.h" 50 #include <sys/fcntl.h> 51 #include <sys/nlookup.h> 52 #include <sys/buf.h> 53 #include <sys/buf2.h> 54 55 /* 56 * Helper routine which disassociates a buffer cache buf from a 57 * hammer structure. 58 * 59 * If the io structures indicates that the buffer is not in a released 60 * state we must dispose of it. 61 */ 62 static void 63 hammer_io_disassociate(union hammer_io_structure *io) 64 { 65 struct buf *bp = io->io.bp; 66 int modified; 67 int released; 68 69 LIST_INIT(&bp->b_dep); /* clear the association */ 70 io->io.bp = NULL; 71 modified = io->io.modified; 72 released = io->io.released; 73 74 switch(io->io.type) { 75 case HAMMER_STRUCTURE_VOLUME: 76 io->volume.ondisk = NULL; 77 io->volume.alist.meta = NULL; 78 io->io.modified = 0; 79 break; 80 case HAMMER_STRUCTURE_SUPERCL: 81 io->supercl.ondisk = NULL; 82 io->supercl.alist.meta = NULL; 83 io->io.modified = 0; 84 break; 85 case HAMMER_STRUCTURE_CLUSTER: 86 io->cluster.ondisk = NULL; 87 io->cluster.alist_master.meta = NULL; 88 io->cluster.alist_btree.meta = NULL; 89 io->cluster.alist_record.meta = NULL; 90 io->cluster.alist_mdata.meta = NULL; 91 io->io.modified = 0; 92 break; 93 case HAMMER_STRUCTURE_BUFFER: 94 io->buffer.ondisk = NULL; 95 io->buffer.alist.meta = NULL; 96 io->io.modified = 0; 97 break; 98 } 99 /* 100 * 'io' now invalid. If the buffer was not released we have to 101 * dispose of it. 102 * 103 * disassociate can be called via hammer_io_checkwrite() with 104 * the buffer in a released state (possibly with no lock held 105 * at all, in fact). Don't mess with it if we are in a released 106 * state. 107 */ 108 if (released == 0) { 109 if (modified) 110 bdwrite(bp); 111 else 112 bqrelse(bp); 113 } 114 } 115 116 /* 117 * Load bp for a HAMMER structure. 118 */ 119 int 120 hammer_io_read(struct vnode *devvp, struct hammer_io *io) 121 { 122 struct buf *bp; 123 int error; 124 125 if ((bp = io->bp) == NULL) { 126 error = bread(devvp, io->offset, HAMMER_BUFSIZE, &io->bp); 127 if (error == 0) { 128 bp = io->bp; 129 bp->b_ops = &hammer_bioops; 130 LIST_INSERT_HEAD(&bp->b_dep, &io->worklist, node); 131 BUF_KERNPROC(bp); 132 } 133 io->modified = 0; /* no new modifications yet */ 134 io->released = 0; /* we hold an active lock on bp */ 135 } else { 136 error = 0; 137 } 138 return(error); 139 } 140 141 /* 142 * Similar to hammer_io_read() but returns a zero'd out buffer instead. 143 * vfs_bio_clrbuf() is kinda nasty, enforce serialization against background 144 * I/O so we can call it. 145 */ 146 int 147 hammer_io_new(struct vnode *devvp, struct hammer_io *io) 148 { 149 struct buf *bp; 150 151 if ((bp = io->bp) == NULL) { 152 io->bp = getblk(devvp, io->offset, HAMMER_BUFSIZE, 0, 0); 153 bp = io->bp; 154 bp->b_ops = &hammer_bioops; 155 LIST_INSERT_HEAD(&bp->b_dep, &io->worklist, node); 156 io->released = 0; /* we hold an active lock on bp */ 157 BUF_KERNPROC(bp); 158 } else { 159 if (io->released) { 160 regetblk(bp); 161 io->released = 0; 162 BUF_KERNPROC(bp); 163 } 164 } 165 io->modified = 1; 166 vfs_bio_clrbuf(bp); 167 return(0); 168 } 169 170 /* 171 * Release the IO buffer on the last reference to a hammer structure. At 172 * this time the lock still has a reference. 173 * 174 * We flush and disassociate the bp if flush is non-zero or if the kernel 175 * tried to free/reuse the buffer. 176 */ 177 void 178 hammer_io_release(struct hammer_io *io, int flush) 179 { 180 union hammer_io_structure *iou = (void *)io; 181 struct buf *bp; 182 183 if ((bp = io->bp) != NULL) { 184 if (bp->b_flags & B_LOCKED) { 185 /* 186 * The kernel wanted the buffer but couldn't get it, 187 * give it up now. 188 */ 189 KKASSERT(io->released); 190 regetblk(bp); 191 io->released = 0; 192 BUF_KERNPROC(bp); 193 bp->b_flags &= ~B_LOCKED; 194 hammer_io_disassociate(iou); 195 } else if (io->released == 0) { 196 /* 197 * We are holding a real lock on the buffer, release 198 * it passively (hammer_io_deallocate is called 199 * when the kernel really wants to reuse the buffer). 200 */ 201 if (flush) { 202 hammer_io_disassociate(iou); 203 } else { 204 if (io->modified) 205 bdwrite(bp); 206 else 207 bqrelse(bp); 208 io->modified = 0; 209 io->released = 1; 210 } 211 } else if (io->modified && (bp->b_flags & B_DELWRI) == 0) { 212 /* 213 * We are holding the buffer passively but made 214 * modifications to it. The kernel has not initiated 215 * I/O (else B_LOCKED would have been set), so just 216 * check whether B_DELWRI is set. Since we still 217 * have lock references on the HAMMER structure the 218 * kernel cannot throw the buffer away. 219 * 220 * We have to do this to avoid the situation where 221 * the buffer is not marked B_DELWRI when modified 222 * and in a released state, otherwise the kernel 223 * will never try to flush the modified buffer! 224 */ 225 regetblk(bp); 226 BUF_KERNPROC(bp); 227 io->released = 0; 228 if (flush) { 229 hammer_io_disassociate(iou); 230 } else { 231 bdwrite(bp); 232 io->modified = 0; 233 } 234 } else if (flush) { 235 /* 236 * We are holding the buffer passively but were 237 * asked to disassociate and flush it. 238 */ 239 regetblk(bp); 240 BUF_KERNPROC(bp); 241 io->released = 0; 242 hammer_io_disassociate(iou); 243 /* io->released ignored */ 244 } /* else just leave it associated in a released state */ 245 } 246 } 247 248 /* 249 * HAMMER_BIOOPS 250 */ 251 252 /* 253 * Pre and post I/O callbacks. No buffer munging is done so there is 254 * nothing to do here. 255 */ 256 static void hammer_io_deallocate(struct buf *bp); 257 258 static void 259 hammer_io_start(struct buf *bp) 260 { 261 } 262 263 static void 264 hammer_io_complete(struct buf *bp) 265 { 266 } 267 268 /* 269 * Callback from kernel when it wishes to deallocate a passively 270 * associated structure. This can only occur if the buffer is 271 * passively associated with the structure. The kernel has locked 272 * the buffer. 273 * 274 * If we cannot disassociate we set B_LOCKED to prevent the buffer 275 * from getting reused. 276 */ 277 static void 278 hammer_io_deallocate(struct buf *bp) 279 { 280 union hammer_io_structure *io = (void *)LIST_FIRST(&bp->b_dep); 281 282 /* XXX memory interlock, spinlock to sync cpus */ 283 284 KKASSERT(io->io.released); 285 crit_enter(); 286 287 /* 288 * First, ref the structure to prevent either the buffer or the 289 * structure from going away. 290 */ 291 hammer_ref(&io->io.lock); 292 293 /* 294 * Buffers can have active references from cached hammer_node's, 295 * even if those nodes are themselves passively cached. Attempt 296 * to clean them out. This may not succeed. 297 */ 298 if (io->io.type == HAMMER_STRUCTURE_BUFFER && 299 hammer_lock_ex_try(&io->io.lock) == 0) { 300 hammer_flush_buffer_nodes(&io->buffer); 301 hammer_unlock(&io->io.lock); 302 } 303 304 if (hammer_islastref(&io->io.lock)) { 305 /* 306 * If we are the only ref left we can disassociate the 307 * I/O. It had better still be in a released state because 308 * the kernel is holding a lock on the buffer. 309 */ 310 KKASSERT(io->io.released); 311 hammer_io_disassociate(io); 312 bp->b_flags &= ~B_LOCKED; 313 314 switch(io->io.type) { 315 case HAMMER_STRUCTURE_VOLUME: 316 hammer_rel_volume(&io->volume, 1); 317 break; 318 case HAMMER_STRUCTURE_SUPERCL: 319 hammer_rel_supercl(&io->supercl, 1); 320 break; 321 case HAMMER_STRUCTURE_CLUSTER: 322 hammer_rel_cluster(&io->cluster, 1); 323 break; 324 case HAMMER_STRUCTURE_BUFFER: 325 hammer_rel_buffer(&io->buffer, 1); 326 break; 327 } 328 /* NOTE: io may be invalid (kfree'd) here */ 329 } else { 330 /* 331 * Otherwise tell the kernel not to destroy the buffer 332 */ 333 bp->b_flags |= B_LOCKED; 334 hammer_unlock(&io->io.lock); 335 } 336 crit_exit(); 337 } 338 339 static int 340 hammer_io_fsync(struct vnode *vp) 341 { 342 return(0); 343 } 344 345 /* 346 * NOTE: will not be called unless we tell the kernel about the 347 * bioops. Unused... we use the mount's VFS_SYNC instead. 348 */ 349 static int 350 hammer_io_sync(struct mount *mp) 351 { 352 return(0); 353 } 354 355 static void 356 hammer_io_movedeps(struct buf *bp1, struct buf *bp2) 357 { 358 } 359 360 /* 361 * I/O pre-check for reading and writing. HAMMER only uses this for 362 * B_CACHE buffers so checkread just shouldn't happen, but if it does 363 * allow it. 364 * 365 * Writing is a different case. We don't want to write out a buffer 366 * that HAMMER may be modifying passively. 367 */ 368 static int 369 hammer_io_checkread(struct buf *bp) 370 { 371 return(0); 372 } 373 374 static int 375 hammer_io_checkwrite(struct buf *bp) 376 { 377 union hammer_io_structure *io = (void *)LIST_FIRST(&bp->b_dep); 378 379 if (io->io.lock.refs) { 380 bp->b_flags |= B_LOCKED; 381 return(-1); 382 } else { 383 KKASSERT(bp->b_flags & B_DELWRI); 384 hammer_io_disassociate(io); 385 return(0); 386 } 387 } 388 389 /* 390 * Return non-zero if the caller should flush the structure associated 391 * with this io sub-structure. 392 */ 393 int 394 hammer_io_checkflush(struct hammer_io *io) 395 { 396 if (io->bp == NULL || (io->bp->b_flags & B_LOCKED)) 397 return(1); 398 return(0); 399 } 400 401 /* 402 * Return non-zero if we wish to delay the kernel's attempt to flush 403 * this buffer to disk. 404 */ 405 static int 406 hammer_io_countdeps(struct buf *bp, int n) 407 { 408 return(0); 409 } 410 411 struct bio_ops hammer_bioops = { 412 .io_start = hammer_io_start, 413 .io_complete = hammer_io_complete, 414 .io_deallocate = hammer_io_deallocate, 415 .io_fsync = hammer_io_fsync, 416 .io_sync = hammer_io_sync, 417 .io_movedeps = hammer_io_movedeps, 418 .io_countdeps = hammer_io_countdeps, 419 .io_checkread = hammer_io_checkread, 420 .io_checkwrite = hammer_io_checkwrite, 421 }; 422 423