1 /* 2 * Copyright (c) 2013-2014 The DragonFly Project. All rights reserved. 3 * 4 * This code is derived from software contributed to The DragonFly Project 5 * by Matthew Dillon <dillon@dragonflybsd.org> 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 35 #include "hammer2.h" 36 37 /* 38 * Implements an abstraction layer for synchronous and asynchronous 39 * buffered device I/O. Can be used for OS-abstraction but the main 40 * purpose is to allow larger buffers to be used against hammer2_chain's 41 * using smaller allocations, without causing deadlocks. 42 * 43 */ 44 static int hammer2_io_cleanup_callback(hammer2_io_t *dio, void *arg); 45 46 static int 47 hammer2_io_cmp(hammer2_io_t *io1, hammer2_io_t *io2) 48 { 49 if (io2->pbase < io1->pbase) 50 return(-1); 51 if (io2->pbase > io1->pbase) 52 return(1); 53 return(0); 54 } 55 56 RB_PROTOTYPE2(hammer2_io_tree, hammer2_io, rbnode, hammer2_io_cmp, off_t); 57 RB_GENERATE2(hammer2_io_tree, hammer2_io, rbnode, hammer2_io_cmp, 58 off_t, pbase); 59 60 struct hammer2_cleanupcb_info { 61 struct hammer2_io_tree tmptree; 62 int count; 63 }; 64 65 #define HAMMER2_GETBLK_GOOD 0 66 #define HAMMER2_GETBLK_QUEUED 1 67 #define HAMMER2_GETBLK_OWNED 2 68 69 /* 70 * Allocate/Locate the requested dio, reference it, issue or queue iocb. 71 */ 72 void 73 hammer2_io_getblk(hammer2_mount_t *hmp, off_t lbase, int lsize, 74 hammer2_iocb_t *iocb) 75 { 76 hammer2_io_t *dio; 77 hammer2_io_t *xio; 78 off_t pbase; 79 off_t pmask; 80 int psize = hammer2_devblksize(lsize); 81 int refs; 82 83 pmask = ~(hammer2_off_t)(psize - 1); 84 85 KKASSERT((1 << (int)(lbase & HAMMER2_OFF_MASK_RADIX)) == lsize); 86 lbase &= ~HAMMER2_OFF_MASK_RADIX; 87 pbase = lbase & pmask; 88 KKASSERT(pbase != 0 && ((lbase + lsize - 1) & pmask) == pbase); 89 90 /* 91 * Access/Allocate the DIO, bump dio->refs to prevent destruction. 92 */ 93 spin_lock_shared(&hmp->io_spin); 94 dio = RB_LOOKUP(hammer2_io_tree, &hmp->iotree, pbase); 95 if (dio) { 96 if ((atomic_fetchadd_int(&dio->refs, 1) & 97 HAMMER2_DIO_MASK) == 0) { 98 atomic_add_int(&dio->hmp->iofree_count, -1); 99 } 100 spin_unlock_shared(&hmp->io_spin); 101 } else { 102 spin_unlock_shared(&hmp->io_spin); 103 dio = kmalloc(sizeof(*dio), M_HAMMER2, M_INTWAIT | M_ZERO); 104 dio->hmp = hmp; 105 dio->pbase = pbase; 106 dio->psize = psize; 107 dio->refs = 1; 108 spin_init(&dio->spin, "h2dio"); 109 TAILQ_INIT(&dio->iocbq); 110 spin_lock(&hmp->io_spin); 111 xio = RB_INSERT(hammer2_io_tree, &hmp->iotree, dio); 112 if (xio == NULL) { 113 atomic_add_int(&hammer2_dio_count, 1); 114 spin_unlock(&hmp->io_spin); 115 } else { 116 if ((atomic_fetchadd_int(&xio->refs, 1) & 117 HAMMER2_DIO_MASK) == 0) { 118 atomic_add_int(&xio->hmp->iofree_count, -1); 119 } 120 spin_unlock(&hmp->io_spin); 121 kfree(dio, M_HAMMER2); 122 dio = xio; 123 } 124 } 125 126 /* 127 * Obtain/Validate the buffer. 128 */ 129 iocb->dio = dio; 130 131 for (;;) { 132 refs = dio->refs; 133 cpu_ccfence(); 134 135 /* 136 * Issue the iocb immediately if the buffer is already good. 137 * Once set GOOD cannot be cleared until refs drops to 0. 138 */ 139 if (refs & HAMMER2_DIO_GOOD) { 140 iocb->callback(iocb); 141 break; 142 } 143 144 /* 145 * Try to own the DIO by setting INPROG so we can issue 146 * I/O on it. 147 */ 148 if (refs & HAMMER2_DIO_INPROG) { 149 /* 150 * If DIO_INPROG is already set then set WAITING and 151 * queue the iocb. 152 */ 153 spin_lock(&dio->spin); 154 if (atomic_cmpset_int(&dio->refs, refs, 155 refs | HAMMER2_DIO_WAITING)) { 156 iocb->flags |= HAMMER2_IOCB_ONQ | 157 HAMMER2_IOCB_INPROG; 158 TAILQ_INSERT_TAIL(&dio->iocbq, iocb, entry); 159 spin_unlock(&dio->spin); 160 break; 161 } 162 spin_unlock(&dio->spin); 163 /* retry */ 164 } else { 165 /* 166 * If DIO_INPROG is not set then set it and issue the 167 * callback immediately to start I/O. 168 */ 169 if (atomic_cmpset_int(&dio->refs, refs, 170 refs | HAMMER2_DIO_INPROG)) { 171 iocb->flags |= HAMMER2_IOCB_INPROG; 172 iocb->callback(iocb); 173 break; 174 } 175 /* retry */ 176 } 177 /* retry */ 178 } 179 if (dio->act < 5) 180 ++dio->act; 181 } 182 183 /* 184 * The originator of the iocb is finished with it. 185 */ 186 void 187 hammer2_io_complete(hammer2_iocb_t *iocb) 188 { 189 hammer2_io_t *dio = iocb->dio; 190 uint32_t orefs; 191 uint32_t nrefs; 192 uint32_t oflags; 193 uint32_t nflags; 194 195 /* 196 * If IOCB_INPROG was not set completion is synchronous due to the 197 * buffer already being good. We can simply set IOCB_DONE and return. 198 * In this situation DIO_INPROG is not set and we have no visibility 199 * on dio->bp. 200 */ 201 if ((iocb->flags & HAMMER2_IOCB_INPROG) == 0) { 202 iocb->flags |= HAMMER2_IOCB_DONE; 203 return; 204 } 205 206 /* 207 * The iocb was queued, obtained DIO_INPROG, and its callback was 208 * made. The callback is now complete. We still own DIO_INPROG. 209 * 210 * We can set DIO_GOOD if no error occurred, which gives certain 211 * stability guarantees to dio->bp and allows other accessors to 212 * short-cut access. DIO_GOOD cannot be cleared until the last 213 * ref is dropped. 214 */ 215 KKASSERT(dio->refs & HAMMER2_DIO_INPROG); 216 if (dio->bp) { 217 BUF_KERNPROC(dio->bp); 218 if ((dio->bp->b_flags & B_ERROR) == 0) { 219 KKASSERT(dio->bp->b_flags & B_CACHE); 220 atomic_set_int(&dio->refs, HAMMER2_DIO_GOOD); 221 } 222 } 223 224 for (;;) { 225 oflags = iocb->flags; 226 cpu_ccfence(); 227 nflags = oflags; 228 nflags &= ~(HAMMER2_IOCB_WAKEUP | HAMMER2_IOCB_INPROG); 229 nflags |= HAMMER2_IOCB_DONE; 230 231 if (atomic_cmpset_int(&iocb->flags, oflags, nflags)) { 232 if (oflags & HAMMER2_IOCB_WAKEUP) 233 wakeup(iocb); 234 /* SMP: iocb is now stale */ 235 break; 236 } 237 /* retry */ 238 } 239 iocb = NULL; 240 241 /* 242 * Now finish up the dio. If another iocb is pending chain to it 243 * leaving DIO_INPROG set. Otherwise clear DIO_INPROG 244 * (and DIO_WAITING). 245 */ 246 for (;;) { 247 orefs = dio->refs; 248 nrefs = orefs & ~(HAMMER2_DIO_WAITING | HAMMER2_DIO_INPROG); 249 250 if ((orefs & HAMMER2_DIO_WAITING) && TAILQ_FIRST(&dio->iocbq)) { 251 spin_lock(&dio->spin); 252 iocb = TAILQ_FIRST(&dio->iocbq); 253 if (iocb) { 254 TAILQ_REMOVE(&dio->iocbq, iocb, entry); 255 spin_unlock(&dio->spin); 256 iocb->callback(iocb); /* chained */ 257 break; 258 } 259 spin_unlock(&dio->spin); 260 /* retry */ 261 } else if (atomic_cmpset_int(&dio->refs, orefs, nrefs)) { 262 break; 263 } /* else retry */ 264 /* retry */ 265 } 266 /* SMP: dio is stale now */ 267 } 268 269 /* 270 * Wait for an iocb's I/O to finish. 271 */ 272 void 273 hammer2_iocb_wait(hammer2_iocb_t *iocb) 274 { 275 uint32_t oflags; 276 uint32_t nflags; 277 278 for (;;) { 279 oflags = iocb->flags; 280 cpu_ccfence(); 281 nflags = oflags | HAMMER2_IOCB_WAKEUP; 282 if (oflags & HAMMER2_IOCB_DONE) 283 break; 284 tsleep_interlock(iocb, 0); 285 if (atomic_cmpset_int(&iocb->flags, oflags, nflags)) { 286 tsleep(iocb, PINTERLOCKED, "h2iocb", hz); 287 } 288 } 289 290 } 291 292 /* 293 * Release our ref on *diop. 294 * 295 * On the last ref we must atomically clear DIO_GOOD and set DIO_INPROG, 296 * then dispose of the underlying buffer. 297 */ 298 void 299 hammer2_io_putblk(hammer2_io_t **diop) 300 { 301 hammer2_mount_t *hmp; 302 hammer2_io_t *dio; 303 hammer2_iocb_t iocb; 304 struct buf *bp; 305 off_t peof; 306 off_t pbase; 307 int psize; 308 int refs; 309 310 dio = *diop; 311 *diop = NULL; 312 313 /* 314 * Drop refs, on 1->0 transition clear flags, set INPROG. 315 */ 316 for (;;) { 317 refs = dio->refs; 318 319 if ((refs & HAMMER2_DIO_MASK) == 1) { 320 KKASSERT((refs & HAMMER2_DIO_INPROG) == 0); 321 if (atomic_cmpset_int(&dio->refs, refs, 322 ((refs - 1) & 323 ~(HAMMER2_DIO_GOOD | 324 HAMMER2_DIO_DIRTY)) | 325 HAMMER2_DIO_INPROG)) { 326 break; 327 } 328 /* retry */ 329 } else { 330 if (atomic_cmpset_int(&dio->refs, refs, refs - 1)) 331 return; 332 /* retry */ 333 } 334 /* retry */ 335 } 336 337 /* 338 * We have set DIO_INPROG to gain control of the buffer and we have 339 * cleared DIO_GOOD to prevent other accessors from thinking it is 340 * still good. 341 * 342 * We can now dispose of the buffer, and should do it before calling 343 * io_complete() in case there's a race against a new reference 344 * which causes io_complete() to chain and instantiate the bp again. 345 */ 346 pbase = dio->pbase; 347 psize = dio->psize; 348 bp = dio->bp; 349 dio->bp = NULL; 350 351 if (refs & HAMMER2_DIO_GOOD) { 352 KKASSERT(bp != NULL); 353 if (refs & HAMMER2_DIO_DIRTY) { 354 if (hammer2_cluster_enable) { 355 peof = (pbase + HAMMER2_SEGMASK64) & 356 ~HAMMER2_SEGMASK64; 357 cluster_write(bp, peof, psize, 4); 358 } else { 359 bp->b_flags |= B_CLUSTEROK; 360 bdwrite(bp); 361 } 362 } else if (bp->b_flags & (B_ERROR | B_INVAL | B_RELBUF)) { 363 brelse(bp); 364 } else { 365 bqrelse(bp); 366 } 367 } else if (bp) { 368 if (refs & HAMMER2_DIO_DIRTY) { 369 bdwrite(bp); 370 } else { 371 brelse(bp); 372 } 373 } 374 375 /* 376 * The instant we call io_complete dio is a free agent again and 377 * can be ripped out from under us. 378 * 379 * we can cleanup our final DIO_INPROG by simulating an iocb 380 * completion. 381 */ 382 hmp = dio->hmp; /* extract fields */ 383 atomic_add_int(&hmp->iofree_count, 1); 384 cpu_ccfence(); 385 386 iocb.dio = dio; 387 iocb.flags = HAMMER2_IOCB_INPROG; 388 hammer2_io_complete(&iocb); 389 dio = NULL; /* dio stale */ 390 391 /* 392 * We cache free buffers so re-use cases can use a shared lock, but 393 * if too many build up we have to clean them out. 394 */ 395 if (hmp->iofree_count > 1000) { 396 struct hammer2_cleanupcb_info info; 397 398 RB_INIT(&info.tmptree); 399 spin_lock(&hmp->io_spin); 400 if (hmp->iofree_count > 1000) { 401 info.count = hmp->iofree_count / 2; 402 RB_SCAN(hammer2_io_tree, &hmp->iotree, NULL, 403 hammer2_io_cleanup_callback, &info); 404 } 405 spin_unlock(&hmp->io_spin); 406 hammer2_io_cleanup(hmp, &info.tmptree); 407 } 408 } 409 410 /* 411 * Cleanup any dio's with (INPROG | refs) == 0. 412 * 413 * Called to clean up cached DIOs on umount after all activity has been 414 * flushed. 415 */ 416 static 417 int 418 hammer2_io_cleanup_callback(hammer2_io_t *dio, void *arg) 419 { 420 struct hammer2_cleanupcb_info *info = arg; 421 hammer2_io_t *xio; 422 423 if ((dio->refs & (HAMMER2_DIO_MASK | HAMMER2_DIO_INPROG)) == 0) { 424 if (dio->act > 0) { 425 --dio->act; 426 return 0; 427 } 428 KKASSERT(dio->bp == NULL); 429 RB_REMOVE(hammer2_io_tree, &dio->hmp->iotree, dio); 430 xio = RB_INSERT(hammer2_io_tree, &info->tmptree, dio); 431 KKASSERT(xio == NULL); 432 if (--info->count <= 0) /* limit scan */ 433 return(-1); 434 } 435 return 0; 436 } 437 438 void 439 hammer2_io_cleanup(hammer2_mount_t *hmp, struct hammer2_io_tree *tree) 440 { 441 hammer2_io_t *dio; 442 443 while ((dio = RB_ROOT(tree)) != NULL) { 444 RB_REMOVE(hammer2_io_tree, tree, dio); 445 KKASSERT(dio->bp == NULL && 446 (dio->refs & (HAMMER2_DIO_MASK | HAMMER2_DIO_INPROG)) == 0); 447 kfree(dio, M_HAMMER2); 448 atomic_add_int(&hammer2_dio_count, -1); 449 atomic_add_int(&hmp->iofree_count, -1); 450 } 451 } 452 453 /* 454 * Returns a pointer to the requested data. 455 */ 456 char * 457 hammer2_io_data(hammer2_io_t *dio, off_t lbase) 458 { 459 struct buf *bp; 460 int off; 461 462 bp = dio->bp; 463 KKASSERT(bp != NULL); 464 off = (lbase & ~HAMMER2_OFF_MASK_RADIX) - bp->b_loffset; 465 KKASSERT(off >= 0 && off < bp->b_bufsize); 466 return(bp->b_data + off); 467 } 468 469 /* 470 * Helpers for hammer2_io_new*() functions 471 */ 472 static 473 void 474 hammer2_iocb_new_callback(hammer2_iocb_t *iocb) 475 { 476 hammer2_io_t *dio = iocb->dio; 477 int gbctl = (iocb->flags & HAMMER2_IOCB_QUICK) ? GETBLK_NOWAIT : 0; 478 479 /* 480 * If IOCB_INPROG is not set the dio already has a good buffer and we 481 * can't mess with it other than zero the requested range. 482 * 483 * If IOCB_INPROG is set we also own DIO_INPROG at this time and can 484 * do what needs to be done with dio->bp. 485 */ 486 if (iocb->flags & HAMMER2_IOCB_INPROG) { 487 if ((iocb->flags & HAMMER2_IOCB_READ) == 0) { 488 if (iocb->lsize == dio->psize) { 489 /* 490 * Fully covered buffer, try to optimize to 491 * avoid any I/O. We might already have the 492 * buffer due to iocb chaining. 493 */ 494 if (dio->bp == NULL) { 495 dio->bp = getblk(dio->hmp->devvp, 496 dio->pbase, dio->psize, 497 gbctl, 0); 498 } 499 if (dio->bp) { 500 vfs_bio_clrbuf(dio->bp); 501 dio->bp->b_flags |= B_CACHE; 502 } 503 } else if (iocb->flags & HAMMER2_IOCB_QUICK) { 504 /* 505 * Partial buffer, quick mode. Do nothing. 506 * Do not instantiate the buffer or try to 507 * mark it B_CACHE because other portions of 508 * the buffer might have to be read by other 509 * accessors. 510 */ 511 } else if (dio->bp == NULL || 512 (dio->bp->b_flags & B_CACHE) == 0) { 513 /* 514 * Partial buffer, normal mode, requires 515 * read-before-write. Chain the read. 516 * 517 * We might already have the buffer due to 518 * iocb chaining. XXX unclear if we really 519 * need to write/release it and reacquire 520 * in that case. 521 * 522 * QUEUE ASYNC I/O, IOCB IS NOT YET COMPLETE. 523 */ 524 if (dio->bp) { 525 if (dio->refs & HAMMER2_DIO_DIRTY) 526 bdwrite(dio->bp); 527 else 528 bqrelse(dio->bp); 529 dio->bp = NULL; 530 } 531 iocb->flags |= HAMMER2_IOCB_READ; 532 breadcb(dio->hmp->devvp, 533 dio->pbase, dio->psize, 534 hammer2_io_callback, iocb); 535 return; 536 } /* else buffer is good */ 537 } /* else callback from breadcb is complete */ 538 } 539 if (dio->bp) { 540 if (iocb->flags & HAMMER2_IOCB_ZERO) 541 bzero(hammer2_io_data(dio, iocb->lbase), iocb->lsize); 542 atomic_set_int(&dio->refs, HAMMER2_DIO_DIRTY); 543 } 544 hammer2_io_complete(iocb); 545 } 546 547 static 548 int 549 _hammer2_io_new(hammer2_mount_t *hmp, off_t lbase, int lsize, 550 hammer2_io_t **diop, int flags) 551 { 552 hammer2_iocb_t iocb; 553 hammer2_io_t *dio; 554 555 iocb.callback = hammer2_iocb_new_callback; 556 iocb.cluster = NULL; 557 iocb.chain = NULL; 558 iocb.ptr = NULL; 559 iocb.lbase = lbase; 560 iocb.lsize = lsize; 561 iocb.flags = flags; 562 iocb.error = 0; 563 hammer2_io_getblk(hmp, lbase, lsize, &iocb); 564 if ((iocb.flags & HAMMER2_IOCB_DONE) == 0) 565 hammer2_iocb_wait(&iocb); 566 dio = *diop = iocb.dio; 567 568 return (iocb.error); 569 } 570 571 int 572 hammer2_io_new(hammer2_mount_t *hmp, off_t lbase, int lsize, 573 hammer2_io_t **diop) 574 { 575 return(_hammer2_io_new(hmp, lbase, lsize, diop, HAMMER2_IOCB_ZERO)); 576 } 577 578 int 579 hammer2_io_newnz(hammer2_mount_t *hmp, off_t lbase, int lsize, 580 hammer2_io_t **diop) 581 { 582 return(_hammer2_io_new(hmp, lbase, lsize, diop, 0)); 583 } 584 585 int 586 hammer2_io_newq(hammer2_mount_t *hmp, off_t lbase, int lsize, 587 hammer2_io_t **diop) 588 { 589 return(_hammer2_io_new(hmp, lbase, lsize, diop, HAMMER2_IOCB_QUICK)); 590 } 591 592 static 593 void 594 hammer2_iocb_bread_callback(hammer2_iocb_t *iocb) 595 { 596 hammer2_io_t *dio = iocb->dio; 597 off_t peof; 598 int error; 599 600 /* 601 * If IOCB_INPROG is not set the dio already has a good buffer and we 602 * can't mess with it other than zero the requested range. 603 * 604 * If IOCB_INPROG is set we also own DIO_INPROG at this time and can 605 * do what needs to be done with dio->bp. 606 */ 607 if (iocb->flags & HAMMER2_IOCB_INPROG) { 608 if (dio->bp && (dio->bp->b_flags & B_CACHE)) { 609 /* 610 * Already good, likely due to being chained from 611 * another iocb. 612 */ 613 error = 0; 614 } else if (hammer2_cluster_enable) { 615 /* 616 * Synchronous cluster I/O for now. 617 */ 618 if (dio->bp) { 619 bqrelse(dio->bp); 620 dio->bp = NULL; 621 } 622 peof = (dio->pbase + HAMMER2_SEGMASK64) & 623 ~HAMMER2_SEGMASK64; 624 error = cluster_read(dio->hmp->devvp, peof, dio->pbase, 625 dio->psize, 626 dio->psize, HAMMER2_PBUFSIZE*4, 627 &dio->bp); 628 } else { 629 /* 630 * Synchronous I/O for now. 631 */ 632 if (dio->bp) { 633 bqrelse(dio->bp); 634 dio->bp = NULL; 635 } 636 error = bread(dio->hmp->devvp, dio->pbase, 637 dio->psize, &dio->bp); 638 } 639 if (error) { 640 brelse(dio->bp); 641 dio->bp = NULL; 642 } 643 } 644 hammer2_io_complete(iocb); 645 } 646 647 int 648 hammer2_io_bread(hammer2_mount_t *hmp, off_t lbase, int lsize, 649 hammer2_io_t **diop) 650 { 651 hammer2_iocb_t iocb; 652 hammer2_io_t *dio; 653 654 iocb.callback = hammer2_iocb_bread_callback; 655 iocb.cluster = NULL; 656 iocb.chain = NULL; 657 iocb.ptr = NULL; 658 iocb.lbase = lbase; 659 iocb.lsize = lsize; 660 iocb.flags = 0; 661 iocb.error = 0; 662 hammer2_io_getblk(hmp, lbase, lsize, &iocb); 663 if ((iocb.flags & HAMMER2_IOCB_DONE) == 0) 664 hammer2_iocb_wait(&iocb); 665 dio = *diop = iocb.dio; 666 667 return (iocb.error); 668 } 669 670 /* 671 * System buf/bio async callback extracts the iocb and chains 672 * to the iocb callback. 673 */ 674 void 675 hammer2_io_callback(struct bio *bio) 676 { 677 struct buf *dbp = bio->bio_buf; 678 hammer2_iocb_t *iocb = bio->bio_caller_info1.ptr; 679 hammer2_io_t *dio; 680 681 dio = iocb->dio; 682 if ((bio->bio_flags & BIO_DONE) == 0) 683 bpdone(dbp, 0); 684 bio->bio_flags &= ~(BIO_DONE | BIO_SYNC); 685 dio->bp = bio->bio_buf; 686 iocb->callback(iocb); 687 } 688 689 void 690 hammer2_io_bawrite(hammer2_io_t **diop) 691 { 692 atomic_set_int(&(*diop)->refs, HAMMER2_DIO_DIRTY); 693 hammer2_io_putblk(diop); 694 } 695 696 void 697 hammer2_io_bdwrite(hammer2_io_t **diop) 698 { 699 atomic_set_int(&(*diop)->refs, HAMMER2_DIO_DIRTY); 700 hammer2_io_putblk(diop); 701 } 702 703 int 704 hammer2_io_bwrite(hammer2_io_t **diop) 705 { 706 atomic_set_int(&(*diop)->refs, HAMMER2_DIO_DIRTY); 707 hammer2_io_putblk(diop); 708 return (0); /* XXX */ 709 } 710 711 void 712 hammer2_io_setdirty(hammer2_io_t *dio) 713 { 714 atomic_set_int(&dio->refs, HAMMER2_DIO_DIRTY); 715 } 716 717 void 718 hammer2_io_setinval(hammer2_io_t *dio, u_int bytes) 719 { 720 if ((u_int)dio->psize == bytes) 721 dio->bp->b_flags |= B_INVAL | B_RELBUF; 722 } 723 724 void 725 hammer2_io_brelse(hammer2_io_t **diop) 726 { 727 hammer2_io_putblk(diop); 728 } 729 730 void 731 hammer2_io_bqrelse(hammer2_io_t **diop) 732 { 733 hammer2_io_putblk(diop); 734 } 735 736 int 737 hammer2_io_isdirty(hammer2_io_t *dio) 738 { 739 return((dio->refs & HAMMER2_DIO_DIRTY) != 0); 740 } 741