1 /* 2 * Copyright (c) 2007-2008 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.33 2008/05/18 21:47:06 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 static void hammer_io_modify(hammer_io_t io, int count); 56 static void hammer_io_deallocate(struct buf *bp); 57 58 /* 59 * Initialize a new, already-zero'd hammer_io structure, or reinitialize 60 * an existing hammer_io structure which may have switched to another type. 61 */ 62 void 63 hammer_io_init(hammer_io_t io, hammer_mount_t hmp, enum hammer_io_type type) 64 { 65 io->hmp = hmp; 66 io->type = type; 67 } 68 69 void 70 hammer_io_reinit(hammer_io_t io, enum hammer_io_type type) 71 { 72 hammer_mount_t hmp = io->hmp; 73 74 if (io->modified) { 75 KKASSERT(io->mod_list != NULL); 76 if (io->mod_list == &hmp->volu_list || 77 io->mod_list == &hmp->meta_list) { 78 --hmp->locked_dirty_count; 79 --hammer_count_dirtybufs; 80 } 81 TAILQ_REMOVE(io->mod_list, io, mod_entry); 82 io->mod_list = NULL; 83 } 84 io->type = type; 85 if (io->modified) { 86 switch(io->type) { 87 case HAMMER_STRUCTURE_VOLUME: 88 io->mod_list = &hmp->volu_list; 89 ++hmp->locked_dirty_count; 90 ++hammer_count_dirtybufs; 91 break; 92 case HAMMER_STRUCTURE_META_BUFFER: 93 io->mod_list = &hmp->meta_list; 94 ++hmp->locked_dirty_count; 95 ++hammer_count_dirtybufs; 96 break; 97 case HAMMER_STRUCTURE_UNDO_BUFFER: 98 io->mod_list = &hmp->undo_list; 99 break; 100 case HAMMER_STRUCTURE_DATA_BUFFER: 101 io->mod_list = &hmp->data_list; 102 break; 103 } 104 TAILQ_INSERT_TAIL(io->mod_list, io, mod_entry); 105 } 106 } 107 108 /* 109 * Helper routine to disassociate a buffer cache buffer from an I/O 110 * structure. Called with the io structure exclusively locked. 111 * 112 * The io may have 0 or 1 references depending on who called us. The 113 * caller is responsible for dealing with the refs. 114 * 115 * This call can only be made when no action is required on the buffer. 116 * HAMMER must own the buffer (released == 0) since we mess around with it. 117 */ 118 static void 119 hammer_io_disassociate(hammer_io_structure_t iou, int elseit) 120 { 121 struct buf *bp = iou->io.bp; 122 123 KKASSERT(iou->io.modified == 0); 124 buf_dep_init(bp); 125 iou->io.bp = NULL; 126 bp->b_flags &= ~B_LOCKED; 127 if (elseit) { 128 KKASSERT(iou->io.released == 0); 129 iou->io.released = 1; 130 bqrelse(bp); 131 } else { 132 KKASSERT(iou->io.released); 133 } 134 135 switch(iou->io.type) { 136 case HAMMER_STRUCTURE_VOLUME: 137 iou->volume.ondisk = NULL; 138 break; 139 case HAMMER_STRUCTURE_DATA_BUFFER: 140 case HAMMER_STRUCTURE_META_BUFFER: 141 case HAMMER_STRUCTURE_UNDO_BUFFER: 142 iou->buffer.ondisk = NULL; 143 break; 144 } 145 } 146 147 /* 148 * Wait for any physical IO to complete 149 */ 150 static void 151 hammer_io_wait(hammer_io_t io) 152 { 153 if (io->running) { 154 crit_enter(); 155 tsleep_interlock(io); 156 io->waiting = 1; 157 for (;;) { 158 tsleep(io, 0, "hmrflw", 0); 159 if (io->running == 0) 160 break; 161 tsleep_interlock(io); 162 io->waiting = 1; 163 if (io->running == 0) 164 break; 165 } 166 crit_exit(); 167 } 168 } 169 170 #define HAMMER_MAXRA 4 171 172 /* 173 * Load bp for a HAMMER structure. The io must be exclusively locked by 174 * the caller. 175 * 176 * Generally speaking HAMMER assumes either an optimized layout or that 177 * typical access patterns will be close to the original layout when the 178 * information was written. For this reason we try to cluster all reads. 179 */ 180 int 181 hammer_io_read(struct vnode *devvp, struct hammer_io *io, hammer_off_t limit) 182 { 183 struct buf *bp; 184 int error; 185 186 if ((bp = io->bp) == NULL) { 187 #if 1 188 error = cluster_read(devvp, limit, io->offset, 189 HAMMER_BUFSIZE, MAXBSIZE, 16, &io->bp); 190 #else 191 error = bread(devvp, io->offset, HAMMER_BUFSIZE, &io->bp); 192 #endif 193 194 if (error == 0) { 195 bp = io->bp; 196 bp->b_ops = &hammer_bioops; 197 LIST_INSERT_HEAD(&bp->b_dep, &io->worklist, node); 198 BUF_KERNPROC(bp); 199 } 200 KKASSERT(io->modified == 0); 201 KKASSERT(io->running == 0); 202 KKASSERT(io->waiting == 0); 203 io->released = 0; /* we hold an active lock on bp */ 204 } else { 205 error = 0; 206 } 207 return(error); 208 } 209 210 /* 211 * Similar to hammer_io_read() but returns a zero'd out buffer instead. 212 * Must be called with the IO exclusively locked. 213 * 214 * vfs_bio_clrbuf() is kinda nasty, enforce serialization against background 215 * I/O by forcing the buffer to not be in a released state before calling 216 * it. 217 * 218 * This function will also mark the IO as modified but it will not 219 * increment the modify_refs count. 220 */ 221 int 222 hammer_io_new(struct vnode *devvp, struct hammer_io *io) 223 { 224 struct buf *bp; 225 226 if ((bp = io->bp) == NULL) { 227 io->bp = getblk(devvp, io->offset, HAMMER_BUFSIZE, 0, 0); 228 bp = io->bp; 229 bp->b_ops = &hammer_bioops; 230 LIST_INSERT_HEAD(&bp->b_dep, &io->worklist, node); 231 io->released = 0; 232 KKASSERT(io->running == 0); 233 io->waiting = 0; 234 BUF_KERNPROC(bp); 235 } else { 236 if (io->released) { 237 regetblk(bp); 238 BUF_KERNPROC(bp); 239 io->released = 0; 240 } 241 } 242 hammer_io_modify(io, 0); 243 vfs_bio_clrbuf(bp); 244 return(0); 245 } 246 247 /* 248 * This routine is called on the last reference to a hammer structure. 249 * The io is usually locked exclusively (but may not be during unmount). 250 * 251 * This routine is responsible for the disposition of the buffer cache 252 * buffer backing the IO. Only pure-data and undo buffers can be handed 253 * back to the kernel. Volume and meta-data buffers must be retained 254 * by HAMMER until explicitly flushed by the backend. 255 */ 256 void 257 hammer_io_release(struct hammer_io *io, int flush) 258 { 259 struct buf *bp; 260 261 if ((bp = io->bp) == NULL) 262 return; 263 264 /* 265 * Try to flush a dirty IO to disk if asked to by the 266 * caller or if the kernel tried to flush the buffer in the past. 267 * 268 * Kernel-initiated flushes are only allowed for pure-data buffers. 269 * meta-data and volume buffers can only be flushed explicitly 270 * by HAMMER. 271 */ 272 if (io->modified) { 273 if (flush) { 274 hammer_io_flush(io); 275 } else if (bp->b_flags & B_LOCKED) { 276 switch(io->type) { 277 case HAMMER_STRUCTURE_DATA_BUFFER: 278 case HAMMER_STRUCTURE_UNDO_BUFFER: 279 hammer_io_flush(io); 280 break; 281 default: 282 break; 283 } 284 } /* else no explicit request to flush the buffer */ 285 } 286 287 /* 288 * Wait for the IO to complete if asked to. 289 */ 290 if (io->waitdep && io->running) { 291 hammer_io_wait(io); 292 } 293 294 /* 295 * Return control of the buffer to the kernel (with the provisio 296 * that our bioops can override kernel decisions with regards to 297 * the buffer). 298 */ 299 if (flush && io->modified == 0 && io->running == 0) { 300 /* 301 * Always disassociate the bp if an explicit flush 302 * was requested and the IO completed with no error 303 * (so unmount can really clean up the structure). 304 */ 305 if (io->released) { 306 regetblk(bp); 307 BUF_KERNPROC(bp); 308 io->released = 0; 309 } 310 hammer_io_disassociate((hammer_io_structure_t)io, 1); 311 } else if (io->modified) { 312 /* 313 * Only certain IO types can be released to the kernel. 314 * volume and meta-data IO types must be explicitly flushed 315 * by HAMMER. 316 */ 317 switch(io->type) { 318 case HAMMER_STRUCTURE_DATA_BUFFER: 319 case HAMMER_STRUCTURE_UNDO_BUFFER: 320 if (io->released == 0) { 321 io->released = 1; 322 bdwrite(bp); 323 } 324 break; 325 default: 326 break; 327 } 328 } else if (io->released == 0) { 329 /* 330 * Clean buffers can be generally released to the kernel. 331 * We leave the bp passively associated with the HAMMER 332 * structure and use bioops to disconnect it later on 333 * if the kernel wants to discard the buffer. 334 */ 335 bp->b_flags &= ~B_LOCKED; 336 io->released = 1; 337 bqrelse(bp); 338 } else { 339 /* 340 * A released buffer may have been locked when the kernel 341 * tried to deallocate it while HAMMER still had references 342 * on the hammer_buffer. We must unlock the buffer or 343 * it will just rot. 344 */ 345 crit_enter(); 346 if (io->running == 0 && (bp->b_flags & B_LOCKED)) { 347 regetblk(bp); 348 bp->b_flags &= ~B_LOCKED; 349 bqrelse(bp); 350 } 351 crit_exit(); 352 } 353 } 354 355 /* 356 * This routine is called with a locked IO when a flush is desired and 357 * no other references to the structure exists other then ours. This 358 * routine is ONLY called when HAMMER believes it is safe to flush a 359 * potentially modified buffer out. 360 */ 361 void 362 hammer_io_flush(struct hammer_io *io) 363 { 364 struct buf *bp; 365 366 /* 367 * Degenerate case - nothing to flush if nothing is dirty. 368 */ 369 if (io->modified == 0) { 370 return; 371 } 372 373 KKASSERT(io->bp); 374 KKASSERT(io->modify_refs == 0); 375 376 /* 377 * Acquire ownership of the bp, particularly before we clear our 378 * modified flag. 379 * 380 * We are going to bawrite() this bp. Don't leave a window where 381 * io->released is set, we actually own the bp rather then our 382 * buffer. 383 */ 384 bp = io->bp; 385 if (io->released) { 386 regetblk(bp); 387 /* BUF_KERNPROC(io->bp); */ 388 /* io->released = 0; */ 389 KKASSERT(io->released); 390 KKASSERT(io->bp == bp); 391 } 392 io->released = 1; 393 394 /* 395 * Acquire exclusive access to the bp and then clear the modified 396 * state of the buffer prior to issuing I/O to interlock any 397 * modifications made while the I/O is in progress. This shouldn't 398 * happen anyway but losing data would be worse. The modified bit 399 * will be rechecked after the IO completes. 400 * 401 * This is only legal when lock.refs == 1 (otherwise we might clear 402 * the modified bit while there are still users of the cluster 403 * modifying the data). 404 * 405 * Do this before potentially blocking so any attempt to modify the 406 * ondisk while we are blocked blocks waiting for us. 407 */ 408 KKASSERT(io->mod_list != NULL); 409 if (io->mod_list == &io->hmp->volu_list || 410 io->mod_list == &io->hmp->meta_list) { 411 --io->hmp->locked_dirty_count; 412 --hammer_count_dirtybufs; 413 } 414 TAILQ_REMOVE(io->mod_list, io, mod_entry); 415 io->mod_list = NULL; 416 io->modified = 0; 417 418 /* 419 * Transfer ownership to the kernel and initiate I/O. 420 */ 421 io->running = 1; 422 ++io->hmp->io_running_count; 423 bawrite(bp); 424 } 425 426 /************************************************************************ 427 * BUFFER DIRTYING * 428 ************************************************************************ 429 * 430 * These routines deal with dependancies created when IO buffers get 431 * modified. The caller must call hammer_modify_*() on a referenced 432 * HAMMER structure prior to modifying its on-disk data. 433 * 434 * Any intent to modify an IO buffer acquires the related bp and imposes 435 * various write ordering dependancies. 436 */ 437 438 /* 439 * Mark a HAMMER structure as undergoing modification. Meta-data buffers 440 * are locked until the flusher can deal with them, pure data buffers 441 * can be written out. 442 */ 443 static 444 void 445 hammer_io_modify(hammer_io_t io, int count) 446 { 447 struct hammer_mount *hmp = io->hmp; 448 449 /* 450 * Shortcut if nothing to do. 451 */ 452 KKASSERT(io->lock.refs != 0 && io->bp != NULL); 453 io->modify_refs += count; 454 if (io->modified && io->released == 0) 455 return; 456 457 hammer_lock_ex(&io->lock); 458 if (io->modified == 0) { 459 KKASSERT(io->mod_list == NULL); 460 switch(io->type) { 461 case HAMMER_STRUCTURE_VOLUME: 462 io->mod_list = &hmp->volu_list; 463 ++hmp->locked_dirty_count; 464 ++hammer_count_dirtybufs; 465 break; 466 case HAMMER_STRUCTURE_META_BUFFER: 467 io->mod_list = &hmp->meta_list; 468 ++hmp->locked_dirty_count; 469 ++hammer_count_dirtybufs; 470 break; 471 case HAMMER_STRUCTURE_UNDO_BUFFER: 472 io->mod_list = &hmp->undo_list; 473 break; 474 case HAMMER_STRUCTURE_DATA_BUFFER: 475 io->mod_list = &hmp->data_list; 476 break; 477 } 478 TAILQ_INSERT_TAIL(io->mod_list, io, mod_entry); 479 io->modified = 1; 480 } 481 if (io->released) { 482 regetblk(io->bp); 483 BUF_KERNPROC(io->bp); 484 io->released = 0; 485 KKASSERT(io->modified != 0); 486 } 487 hammer_unlock(&io->lock); 488 } 489 490 static __inline 491 void 492 hammer_io_modify_done(hammer_io_t io) 493 { 494 KKASSERT(io->modify_refs > 0); 495 --io->modify_refs; 496 } 497 498 /* 499 * Caller intends to modify a volume's ondisk structure. 500 * 501 * This is only allowed if we are the flusher or we have a ref on the 502 * sync_lock. 503 */ 504 void 505 hammer_modify_volume(hammer_transaction_t trans, hammer_volume_t volume, 506 void *base, int len) 507 { 508 KKASSERT (trans == NULL || trans->sync_lock_refs > 0); 509 510 hammer_io_modify(&volume->io, 1); 511 if (len) { 512 intptr_t rel_offset = (intptr_t)base - (intptr_t)volume->ondisk; 513 KKASSERT((rel_offset & ~(intptr_t)HAMMER_BUFMASK) == 0); 514 hammer_generate_undo(trans, &volume->io, 515 HAMMER_ENCODE_RAW_VOLUME(volume->vol_no, rel_offset), 516 base, len); 517 } 518 } 519 520 /* 521 * Caller intends to modify a buffer's ondisk structure. 522 * 523 * This is only allowed if we are the flusher or we have a ref on the 524 * sync_lock. 525 */ 526 void 527 hammer_modify_buffer(hammer_transaction_t trans, hammer_buffer_t buffer, 528 void *base, int len) 529 { 530 KKASSERT (trans == NULL || trans->sync_lock_refs > 0); 531 532 hammer_io_modify(&buffer->io, 1); 533 if (len) { 534 intptr_t rel_offset = (intptr_t)base - (intptr_t)buffer->ondisk; 535 KKASSERT((rel_offset & ~(intptr_t)HAMMER_BUFMASK) == 0); 536 hammer_generate_undo(trans, &buffer->io, 537 buffer->zone2_offset + rel_offset, 538 base, len); 539 } 540 } 541 542 void 543 hammer_modify_volume_done(hammer_volume_t volume) 544 { 545 hammer_io_modify_done(&volume->io); 546 } 547 548 void 549 hammer_modify_buffer_done(hammer_buffer_t buffer) 550 { 551 hammer_io_modify_done(&buffer->io); 552 } 553 554 /* 555 * Mark an entity as not being dirty any more -- this usually occurs when 556 * the governing a-list has freed the entire entity. 557 * 558 * XXX 559 */ 560 void 561 hammer_io_clear_modify(struct hammer_io *io) 562 { 563 #if 0 564 struct buf *bp; 565 566 io->modified = 0; 567 XXX mod_list/entry 568 if ((bp = io->bp) != NULL) { 569 if (io->released) { 570 regetblk(bp); 571 /* BUF_KERNPROC(io->bp); */ 572 } else { 573 io->released = 1; 574 } 575 if (io->modified == 0) { 576 hkprintf("hammer_io_clear_modify: cleared %p\n", io); 577 bundirty(bp); 578 bqrelse(bp); 579 } else { 580 bdwrite(bp); 581 } 582 } 583 #endif 584 } 585 586 /************************************************************************ 587 * HAMMER_BIOOPS * 588 ************************************************************************ 589 * 590 */ 591 592 /* 593 * Pre-IO initiation kernel callback - cluster build only 594 */ 595 static void 596 hammer_io_start(struct buf *bp) 597 { 598 } 599 600 /* 601 * Post-IO completion kernel callback 602 * 603 * NOTE: HAMMER may modify a buffer after initiating I/O. The modified bit 604 * may also be set if we were marking a cluster header open. Only remove 605 * our dependancy if the modified bit is clear. 606 */ 607 static void 608 hammer_io_complete(struct buf *bp) 609 { 610 union hammer_io_structure *iou = (void *)LIST_FIRST(&bp->b_dep); 611 612 KKASSERT(iou->io.released == 1); 613 614 if (iou->io.running) { 615 if (--iou->io.hmp->io_running_count == 0) 616 wakeup(&iou->io.hmp->io_running_count); 617 KKASSERT(iou->io.hmp->io_running_count >= 0); 618 iou->io.running = 0; 619 } 620 621 /* 622 * If no lock references remain and we can acquire the IO lock and 623 * someone at some point wanted us to flush (B_LOCKED test), then 624 * try to dispose of the IO. 625 */ 626 if (iou->io.waiting) { 627 iou->io.waiting = 0; 628 wakeup(iou); 629 } 630 631 /* 632 * Someone wanted us to flush, try to clean out the buffer. 633 */ 634 if ((bp->b_flags & B_LOCKED) && iou->io.lock.refs == 0) { 635 KKASSERT(iou->io.modified == 0); 636 bp->b_flags &= ~B_LOCKED; 637 hammer_io_deallocate(bp); 638 /* structure may be dead now */ 639 } 640 } 641 642 /* 643 * Callback from kernel when it wishes to deallocate a passively 644 * associated structure. This mostly occurs with clean buffers 645 * but it may be possible for a holding structure to be marked dirty 646 * while its buffer is passively associated. 647 * 648 * If we cannot disassociate we set B_LOCKED to prevent the buffer 649 * from getting reused. 650 * 651 * WARNING: Because this can be called directly by getnewbuf we cannot 652 * recurse into the tree. If a bp cannot be immediately disassociated 653 * our only recourse is to set B_LOCKED. 654 */ 655 static void 656 hammer_io_deallocate(struct buf *bp) 657 { 658 hammer_io_structure_t iou = (void *)LIST_FIRST(&bp->b_dep); 659 660 KKASSERT((bp->b_flags & B_LOCKED) == 0 && iou->io.running == 0); 661 if (iou->io.lock.refs > 0 || iou->io.modified) { 662 /* 663 * It is not legal to disassociate a modified buffer. This 664 * case really shouldn't ever occur. 665 */ 666 bp->b_flags |= B_LOCKED; 667 } else { 668 /* 669 * Disassociate the BP. If the io has no refs left we 670 * have to add it to the loose list. 671 */ 672 hammer_io_disassociate(iou, 0); 673 if (iou->io.bp == NULL && 674 iou->io.type != HAMMER_STRUCTURE_VOLUME) { 675 KKASSERT(iou->io.mod_list == NULL); 676 iou->io.mod_list = &iou->io.hmp->lose_list; 677 TAILQ_INSERT_TAIL(iou->io.mod_list, &iou->io, mod_entry); 678 } 679 } 680 } 681 682 static int 683 hammer_io_fsync(struct vnode *vp) 684 { 685 return(0); 686 } 687 688 /* 689 * NOTE: will not be called unless we tell the kernel about the 690 * bioops. Unused... we use the mount's VFS_SYNC instead. 691 */ 692 static int 693 hammer_io_sync(struct mount *mp) 694 { 695 return(0); 696 } 697 698 static void 699 hammer_io_movedeps(struct buf *bp1, struct buf *bp2) 700 { 701 } 702 703 /* 704 * I/O pre-check for reading and writing. HAMMER only uses this for 705 * B_CACHE buffers so checkread just shouldn't happen, but if it does 706 * allow it. 707 * 708 * Writing is a different case. We don't want the kernel to try to write 709 * out a buffer that HAMMER may be modifying passively or which has a 710 * dependancy. In addition, kernel-demanded writes can only proceed for 711 * certain types of buffers (i.e. UNDO and DATA types). Other dirty 712 * buffer types can only be explicitly written by the flusher. 713 * 714 * checkwrite will only be called for bdwrite()n buffers. If we return 715 * success the kernel is guaranteed to initiate the buffer write. 716 */ 717 static int 718 hammer_io_checkread(struct buf *bp) 719 { 720 return(0); 721 } 722 723 static int 724 hammer_io_checkwrite(struct buf *bp) 725 { 726 hammer_io_t io = (void *)LIST_FIRST(&bp->b_dep); 727 728 /* 729 * This shouldn't happen under normal operation. 730 */ 731 if (io->type == HAMMER_STRUCTURE_VOLUME || 732 io->type == HAMMER_STRUCTURE_META_BUFFER) { 733 if (!panicstr) 734 panic("hammer_io_checkwrite: illegal buffer"); 735 hkprintf("x"); 736 bp->b_flags |= B_LOCKED; 737 return(1); 738 } 739 740 /* 741 * We can only clear the modified bit if the IO is not currently 742 * undergoing modification. Otherwise we may miss changes. 743 */ 744 if (io->modify_refs == 0 && io->modified) { 745 KKASSERT(io->mod_list != NULL); 746 if (io->mod_list == &io->hmp->volu_list || 747 io->mod_list == &io->hmp->meta_list) { 748 --io->hmp->locked_dirty_count; 749 --hammer_count_dirtybufs; 750 } 751 TAILQ_REMOVE(io->mod_list, io, mod_entry); 752 io->mod_list = NULL; 753 io->modified = 0; 754 } 755 756 /* 757 * The kernel is going to start the IO, set io->running. 758 */ 759 KKASSERT(io->running == 0); 760 io->running = 1; 761 ++io->hmp->io_running_count; 762 return(0); 763 } 764 765 /* 766 * Return non-zero if we wish to delay the kernel's attempt to flush 767 * this buffer to disk. 768 */ 769 static int 770 hammer_io_countdeps(struct buf *bp, int n) 771 { 772 return(0); 773 } 774 775 struct bio_ops hammer_bioops = { 776 .io_start = hammer_io_start, 777 .io_complete = hammer_io_complete, 778 .io_deallocate = hammer_io_deallocate, 779 .io_fsync = hammer_io_fsync, 780 .io_sync = hammer_io_sync, 781 .io_movedeps = hammer_io_movedeps, 782 .io_countdeps = hammer_io_countdeps, 783 .io_checkread = hammer_io_checkread, 784 .io_checkwrite = hammer_io_checkwrite, 785 }; 786 787