1 /* 2 * COPYRIGHT: See COPYRIGHT.TXT 3 * PROJECT: Ext2 File System Driver for WinNT/2K/XP 4 * FILE: linux.c 5 * PROGRAMMER: Matt Wu <mattwu@163.com> 6 * HOMEPAGE: http://www.ext2fsd.com 7 * UPDATE HISTORY: 8 */ 9 10 /* INCLUDES *****************************************************************/ 11 12 #include <ext2fs.h> 13 #include <linux/jbd.h> 14 #include <linux/errno.h> 15 16 /* GLOBALS ***************************************************************/ 17 18 extern PEXT2_GLOBAL Ext2Global; 19 20 /* DEFINITIONS *************************************************************/ 21 22 #ifdef ALLOC_PRAGMA 23 #pragma alloc_text(PAGE, kzalloc) 24 #endif 25 26 struct task_struct current_task = { 27 /* pid */ 0, 28 /* tid */ 1, 29 /* comm */ "current\0", 30 /* journal_info */ NULL 31 }; 32 struct task_struct *current = ¤t_task; 33 34 void *kzalloc(int size, int flags) 35 { 36 void *buffer = kmalloc(size, flags); 37 if (buffer) { 38 memset(buffer, 0, size); 39 } 40 return buffer; 41 } 42 43 // 44 // slab routines 45 // 46 47 kmem_cache_t * 48 kmem_cache_create( 49 const char * name, 50 size_t size, 51 size_t offset, 52 unsigned long flags, 53 kmem_cache_cb_t ctor 54 ) 55 { 56 kmem_cache_t *kc = NULL; 57 58 kc = kmalloc(sizeof(kmem_cache_t), GFP_KERNEL); 59 if (kc == NULL) { 60 goto errorout; 61 } 62 63 memset(kc, 0, sizeof(kmem_cache_t)); 64 ExInitializeNPagedLookasideList( 65 &kc->la, 66 NULL, 67 NULL, 68 0, 69 size, 70 'JBKC', 71 0); 72 73 kc->size = size; 74 strncpy(kc->name, name, 31); 75 kc->constructor = ctor; 76 77 errorout: 78 79 return kc; 80 } 81 82 int kmem_cache_destroy(kmem_cache_t * kc) 83 { 84 ASSERT(kc != NULL); 85 86 ExDeleteNPagedLookasideList(&(kc->la)); 87 kfree(kc); 88 89 return 0; 90 } 91 92 void* kmem_cache_alloc(kmem_cache_t *kc, int flags) 93 { 94 PVOID ptr = NULL; 95 ptr = ExAllocateFromNPagedLookasideList(&(kc->la)); 96 if (ptr) { 97 atomic_inc(&kc->count); 98 atomic_inc(&kc->acount); 99 } 100 return ptr; 101 } 102 103 void kmem_cache_free(kmem_cache_t *kc, void *p) 104 { 105 if (p) { 106 atomic_dec(&kc->count); 107 ExFreeToNPagedLookasideList(&(kc->la), p); 108 } 109 } 110 111 // 112 // wait queue routines 113 // 114 115 void init_waitqueue_head(wait_queue_head_t *q) 116 { 117 spin_lock_init(&q->lock); 118 INIT_LIST_HEAD(&q->task_list); 119 } 120 121 struct __wait_queue * 122 wait_queue_create() 123 { 124 struct __wait_queue * wait = NULL; 125 wait = kmalloc(sizeof(struct __wait_queue), GFP_KERNEL); 126 if (!wait) { 127 return NULL; 128 } 129 130 memset(wait, 0, sizeof(struct __wait_queue)); 131 wait->flags = WQ_FLAG_AUTO_REMOVAL; 132 wait->private = (void *)KeGetCurrentThread(); 133 INIT_LIST_HEAD(&wait->task_list); 134 KeInitializeEvent(&(wait->event), 135 SynchronizationEvent, 136 FALSE); 137 138 return wait; 139 } 140 141 void 142 wait_queue_destroy(struct __wait_queue * wait) 143 { 144 kfree(wait); 145 } 146 147 static inline void __add_wait_queue(wait_queue_head_t *head, struct __wait_queue *new) 148 { 149 list_add(&new->task_list, &head->task_list); 150 } 151 152 /* 153 * Used for wake-one threads: 154 */ 155 static inline void __add_wait_queue_tail(wait_queue_head_t *head, 156 struct __wait_queue *new) 157 { 158 list_add_tail(&new->task_list, &head->task_list); 159 } 160 161 static inline void __remove_wait_queue(wait_queue_head_t *head, 162 struct __wait_queue *old) 163 { 164 list_del(&old->task_list); 165 } 166 167 void add_wait_queue(wait_queue_head_t *q, wait_queue_t *waiti) 168 { 169 unsigned long flags; 170 struct __wait_queue *wait = *waiti; 171 172 wait->flags &= ~WQ_FLAG_EXCLUSIVE; 173 spin_lock_irqsave(&q->lock, flags); 174 __add_wait_queue(q, wait); 175 spin_unlock_irqrestore(&q->lock, flags); 176 } 177 178 void add_wait_queue_exclusive(wait_queue_head_t *q, wait_queue_t *waiti) 179 { 180 unsigned long flags; 181 struct __wait_queue *wait = *waiti; 182 183 wait->flags |= WQ_FLAG_EXCLUSIVE; 184 spin_lock_irqsave(&q->lock, flags); 185 __add_wait_queue_tail(q, wait); 186 spin_unlock_irqrestore(&q->lock, flags); 187 } 188 189 void remove_wait_queue(wait_queue_head_t *q, wait_queue_t *waiti) 190 { 191 unsigned long flags; 192 struct __wait_queue *wait = *waiti; 193 194 spin_lock_irqsave(&q->lock, flags); 195 __remove_wait_queue(q, wait); 196 spin_unlock_irqrestore(&q->lock, flags); 197 } 198 199 /* 200 * Note: we use "set_current_state()" _after_ the wait-queue add, 201 * because we need a memory barrier there on SMP, so that any 202 * wake-function that tests for the wait-queue being active 203 * will be guaranteed to see waitqueue addition _or_ subsequent 204 * tests in this thread will see the wakeup having taken place. 205 * 206 * The spin_unlock() itself is semi-permeable and only protects 207 * one way (it only protects stuff inside the critical region and 208 * stops them from bleeding out - it would still allow subsequent 209 * loads to move into the critical region). 210 */ 211 void 212 prepare_to_wait(wait_queue_head_t *q, wait_queue_t *waiti, int state) 213 { 214 unsigned long flags; 215 struct __wait_queue *wait = *waiti; 216 217 wait->flags &= ~WQ_FLAG_EXCLUSIVE; 218 spin_lock_irqsave(&q->lock, flags); 219 if (list_empty(&wait->task_list)) 220 __add_wait_queue(q, wait); 221 /* 222 * don't alter the task state if this is just going to 223 * queue an async wait queue callback 224 */ 225 if (is_sync_wait(wait)) 226 set_current_state(state); 227 spin_unlock_irqrestore(&q->lock, flags); 228 } 229 230 void 231 prepare_to_wait_exclusive(wait_queue_head_t *q, wait_queue_t *waiti, int state) 232 { 233 unsigned long flags; 234 struct __wait_queue *wait = *waiti; 235 236 wait->flags |= WQ_FLAG_EXCLUSIVE; 237 spin_lock_irqsave(&q->lock, flags); 238 if (list_empty(&wait->task_list)) 239 __add_wait_queue_tail(q, wait); 240 /* 241 * don't alter the task state if this is just going to 242 * queue an async wait queue callback 243 */ 244 if (is_sync_wait(wait)) 245 set_current_state(state); 246 spin_unlock_irqrestore(&q->lock, flags); 247 } 248 EXPORT_SYMBOL(prepare_to_wait_exclusive); 249 250 void finish_wait(wait_queue_head_t *q, wait_queue_t *waiti) 251 { 252 unsigned long flags; 253 struct __wait_queue *wait = *waiti; 254 255 __set_current_state(TASK_RUNNING); 256 /* 257 * We can check for list emptiness outside the lock 258 * IFF: 259 * - we use the "careful" check that verifies both 260 * the next and prev pointers, so that there cannot 261 * be any half-pending updates in progress on other 262 * CPU's that we haven't seen yet (and that might 263 * still change the stack area. 264 * and 265 * - all other users take the lock (ie we can only 266 * have _one_ other CPU that looks at or modifies 267 * the list). 268 */ 269 if (!list_empty_careful(&wait->task_list)) { 270 spin_lock_irqsave(&q->lock, flags); 271 list_del_init(&wait->task_list); 272 spin_unlock_irqrestore(&q->lock, flags); 273 } 274 275 /* free wait */ 276 wait_queue_destroy(wait); 277 } 278 279 int wake_up(wait_queue_head_t *queue) 280 { 281 return 0; /* KeSetEvent(&wait->event, 0, FALSE); */ 282 } 283 284 285 // 286 // kernel timer routines 287 // 288 289 // 290 // buffer head routines 291 // 292 293 struct _EXT2_BUFFER_HEAD { 294 kmem_cache_t * bh_cache; 295 atomic_t bh_count; 296 atomic_t bh_acount; 297 } g_jbh = {NULL, ATOMIC_INIT(0)}; 298 299 int 300 ext2_init_bh() 301 { 302 g_jbh.bh_count.counter = 0; 303 g_jbh.bh_acount.counter = 0; 304 g_jbh.bh_cache = kmem_cache_create( 305 "ext2_bh", /* bh */ 306 sizeof(struct buffer_head), 307 0, /* offset */ 308 SLAB_TEMPORARY, /* flags */ 309 NULL); /* ctor */ 310 if (g_jbh.bh_cache == NULL) { 311 printk(KERN_EMERG "JBD: failed to create handle cache\n"); 312 return -ENOMEM; 313 } 314 return 0; 315 } 316 317 void 318 ext2_destroy_bh() 319 { 320 if (g_jbh.bh_cache) { 321 kmem_cache_destroy(g_jbh.bh_cache); 322 g_jbh.bh_cache = NULL; 323 } 324 } 325 326 struct buffer_head * 327 new_buffer_head() 328 { 329 struct buffer_head * bh = NULL; 330 bh = kmem_cache_alloc(g_jbh.bh_cache, GFP_NOFS); 331 if (bh) { 332 atomic_inc(&g_jbh.bh_count); 333 atomic_inc(&g_jbh.bh_acount); 334 335 memset(bh, 0, sizeof(struct buffer_head)); 336 InitializeListHead(&bh->b_link); 337 KeQuerySystemTime(&bh->b_ts_creat); 338 DEBUG(DL_BH, ("bh=%p allocated.\n", bh)); 339 INC_MEM_COUNT(PS_BUFF_HEAD, bh, sizeof(struct buffer_head)); 340 } 341 342 return bh; 343 } 344 345 void 346 free_buffer_head(struct buffer_head * bh) 347 { 348 if (bh) { 349 if (bh->b_mdl) { 350 351 DEBUG(DL_BH, ("bh=%p mdl=%p (Flags:%xh VA:%p) released.\n", bh, bh->b_mdl, 352 bh->b_mdl->MdlFlags, bh->b_mdl->MappedSystemVa)); 353 if (IsFlagOn(bh->b_mdl->MdlFlags, MDL_MAPPED_TO_SYSTEM_VA)) { 354 MmUnmapLockedPages(bh->b_mdl->MappedSystemVa, bh->b_mdl); 355 } 356 Ext2DestroyMdl(bh->b_mdl); 357 } 358 if (bh->b_bcb) { 359 CcUnpinDataForThread(bh->b_bcb, (ERESOURCE_THREAD)bh | 0x3); 360 } 361 362 DEBUG(DL_BH, ("bh=%p freed.\n", bh)); 363 DEC_MEM_COUNT(PS_BUFF_HEAD, bh, sizeof(struct buffer_head)); 364 kmem_cache_free(g_jbh.bh_cache, bh); 365 atomic_dec(&g_jbh.bh_count); 366 } 367 } 368 369 // 370 // Red-black tree insert routine. 371 // 372 373 static struct buffer_head *__buffer_head_search(struct rb_root *root, 374 sector_t blocknr) 375 { 376 struct rb_node *new = root->rb_node; 377 378 /* Figure out where to put new node */ 379 while (new) { 380 struct buffer_head *bh = 381 container_of(new, struct buffer_head, b_rb_node); 382 s64 result = blocknr - bh->b_blocknr; 383 384 if (result < 0) 385 new = new->rb_left; 386 else if (result > 0) 387 new = new->rb_right; 388 else 389 return bh; 390 391 } 392 393 return NULL; 394 } 395 396 static int buffer_head_blocknr_cmp(struct rb_node *a, struct rb_node *b) 397 { 398 struct buffer_head *a_bh, *b_bh; 399 s64 result; 400 a_bh = container_of(a, struct buffer_head, b_rb_node); 401 b_bh = container_of(b, struct buffer_head, b_rb_node); 402 result = a_bh->b_blocknr - b_bh->b_blocknr; 403 404 if (result < 0) 405 return -1; 406 if (result > 0) 407 return 1; 408 return 0; 409 } 410 411 static struct buffer_head *buffer_head_search(struct block_device *bdev, 412 sector_t blocknr) 413 { 414 struct rb_root *root; 415 root = &bdev->bd_bh_root; 416 return __buffer_head_search(root, blocknr); 417 } 418 419 static void buffer_head_insert(struct block_device *bdev, struct buffer_head *bh) 420 { 421 rb_insert(&bdev->bd_bh_root, &bh->b_rb_node, buffer_head_blocknr_cmp); 422 } 423 424 static void buffer_head_remove(struct block_device *bdev, struct buffer_head *bh) 425 { 426 rb_erase(&bh->b_rb_node, &bdev->bd_bh_root); 427 } 428 429 struct buffer_head * 430 get_block_bh_mdl( 431 struct block_device * bdev, 432 sector_t block, 433 unsigned long size, 434 int zero 435 ) 436 { 437 PEXT2_VCB Vcb = bdev->bd_priv; 438 LARGE_INTEGER offset; 439 PVOID bcb = NULL; 440 PVOID ptr = NULL; 441 442 struct list_head *entry; 443 444 /* allocate buffer_head and initialize it */ 445 struct buffer_head *bh = NULL, *tbh = NULL; 446 447 /* check the block is valid or not */ 448 if (block >= TOTAL_BLOCKS) { 449 DbgBreak(); 450 goto errorout; 451 } 452 453 /* search the bdev bh list */ 454 ExAcquireSharedStarveExclusive(&bdev->bd_bh_lock, TRUE); 455 tbh = buffer_head_search(bdev, block); 456 if (tbh) { 457 bh = tbh; 458 get_bh(bh); 459 ExReleaseResourceLite(&bdev->bd_bh_lock); 460 goto errorout; 461 } 462 ExReleaseResourceLite(&bdev->bd_bh_lock); 463 464 bh = new_buffer_head(); 465 if (!bh) { 466 goto errorout; 467 } 468 bh->b_bdev = bdev; 469 bh->b_blocknr = block; 470 bh->b_size = size; 471 bh->b_data = NULL; 472 473 again: 474 475 offset.QuadPart = (s64) bh->b_blocknr; 476 offset.QuadPart <<= BLOCK_BITS; 477 478 if (zero) { 479 if (!CcPreparePinWrite(Vcb->Volume, 480 &offset, 481 bh->b_size, 482 FALSE, 483 PIN_WAIT | PIN_EXCLUSIVE, 484 &bcb, 485 &ptr)) { 486 Ext2Sleep(100); 487 goto again; 488 } 489 } else { 490 if (!CcPinRead( Vcb->Volume, 491 &offset, 492 bh->b_size, 493 PIN_WAIT, 494 &bcb, 495 &ptr)) { 496 Ext2Sleep(100); 497 goto again; 498 } 499 set_buffer_uptodate(bh); 500 } 501 502 bh->b_mdl = Ext2CreateMdl(ptr, bh->b_size, IoModifyAccess); 503 if (bh->b_mdl) { 504 /* muse map the PTE to NonCached zone. journal recovery will 505 access the PTE under spinlock: DISPATCH_LEVEL IRQL */ 506 bh->b_data = MmMapLockedPagesSpecifyCache( 507 bh->b_mdl, KernelMode, MmNonCached, 508 NULL,FALSE, HighPagePriority); 509 /* bh->b_data = MmMapLockedPages(bh->b_mdl, KernelMode); */ 510 } 511 if (!bh->b_mdl || !bh->b_data) { 512 free_buffer_head(bh); 513 bh = NULL; 514 goto errorout; 515 } 516 517 get_bh(bh); 518 519 DEBUG(DL_BH, ("getblk: Vcb=%p bhcount=%u block=%u bh=%p mdl=%p (Flags:%xh VA:%p)\n", 520 Vcb, atomic_read(&g_jbh.bh_count), block, bh, bh->b_mdl, bh->b_mdl->MdlFlags, bh->b_data)); 521 522 ExAcquireResourceExclusiveLite(&bdev->bd_bh_lock, TRUE); 523 /* do search again here */ 524 tbh = buffer_head_search(bdev, block); 525 if (tbh) { 526 free_buffer_head(bh); 527 bh = tbh; 528 get_bh(bh); 529 RemoveEntryList(&bh->b_link); 530 InitializeListHead(&bh->b_link); 531 ExReleaseResourceLite(&bdev->bd_bh_lock); 532 goto errorout; 533 } else { 534 buffer_head_insert(bdev, bh); 535 } 536 ExReleaseResourceLite(&bdev->bd_bh_lock); 537 538 /* we get it */ 539 errorout: 540 541 if (bcb) 542 CcUnpinData(bcb); 543 544 return bh; 545 } 546 547 int submit_bh_mdl(int rw, struct buffer_head *bh) 548 { 549 struct block_device *bdev = bh->b_bdev; 550 PEXT2_VCB Vcb = bdev->bd_priv; 551 PBCB Bcb; 552 PVOID Buffer; 553 LARGE_INTEGER Offset; 554 555 ASSERT(Vcb->Identifier.Type == EXT2VCB); 556 ASSERT(bh->b_data); 557 558 if (rw == WRITE) { 559 560 if (IsVcbReadOnly(Vcb)) { 561 goto errorout; 562 } 563 564 SetFlag(Vcb->Volume->Flags, FO_FILE_MODIFIED); 565 Offset.QuadPart = ((LONGLONG)bh->b_blocknr) << BLOCK_BITS; 566 if (CcPreparePinWrite( 567 Vcb->Volume, 568 &Offset, 569 BLOCK_SIZE, 570 FALSE, 571 PIN_WAIT | PIN_EXCLUSIVE, 572 &Bcb, 573 &Buffer )) { 574 #if 0 575 if (memcmp(Buffer, bh->b_data, BLOCK_SIZE) != 0) { 576 DbgBreak(); 577 } 578 memmove(Buffer, bh->b_data, BLOCK_SIZE); 579 #endif 580 CcSetDirtyPinnedData(Bcb, NULL); 581 Ext2AddBlockExtent( Vcb, NULL, 582 (ULONG)bh->b_blocknr, 583 (ULONG)bh->b_blocknr, 584 (bh->b_size >> BLOCK_BITS)); 585 CcUnpinData(Bcb); 586 } else { 587 588 Ext2AddBlockExtent( Vcb, NULL, 589 (ULONG)bh->b_blocknr, 590 (ULONG)bh->b_blocknr, 591 (bh->b_size >> BLOCK_BITS)); 592 } 593 594 } else { 595 596 DbgBreak(); 597 } 598 599 errorout: 600 601 unlock_buffer(bh); 602 put_bh(bh); 603 return 0; 604 } 605 606 struct buffer_head * 607 get_block_bh_pin( 608 struct block_device * bdev, 609 sector_t block, 610 unsigned long size, 611 int zero 612 ) 613 { 614 PEXT2_VCB Vcb = bdev->bd_priv; 615 LARGE_INTEGER offset; 616 617 struct list_head *entry; 618 619 /* allocate buffer_head and initialize it */ 620 struct buffer_head *bh = NULL, *tbh = NULL; 621 622 /* check the block is valid or not */ 623 if (block >= TOTAL_BLOCKS) { 624 DbgBreak(); 625 goto errorout; 626 } 627 628 /* search the bdev bh list */ 629 ExAcquireSharedStarveExclusive(&bdev->bd_bh_lock, TRUE); 630 tbh = buffer_head_search(bdev, block); 631 if (tbh) { 632 bh = tbh; 633 get_bh(bh); 634 ExReleaseResourceLite(&bdev->bd_bh_lock); 635 goto errorout; 636 } 637 ExReleaseResourceLite(&bdev->bd_bh_lock); 638 639 bh = new_buffer_head(); 640 if (!bh) { 641 goto errorout; 642 } 643 bh->b_bdev = bdev; 644 bh->b_blocknr = block; 645 bh->b_size = size; 646 bh->b_data = NULL; 647 648 again: 649 650 offset.QuadPart = (s64) bh->b_blocknr; 651 offset.QuadPart <<= BLOCK_BITS; 652 653 if (zero) { 654 if (!CcPreparePinWrite(Vcb->Volume, 655 &offset, 656 bh->b_size, 657 FALSE, 658 PIN_WAIT, 659 &bh->b_bcb, 660 (PVOID *)&bh->b_data)) { 661 Ext2Sleep(100); 662 goto again; 663 } 664 } else { 665 if (!CcPinRead( Vcb->Volume, 666 &offset, 667 bh->b_size, 668 PIN_WAIT, 669 &bh->b_bcb, 670 (PVOID *)&bh->b_data)) { 671 Ext2Sleep(100); 672 goto again; 673 } 674 set_buffer_uptodate(bh); 675 } 676 677 if (bh->b_bcb) 678 CcSetBcbOwnerPointer(bh->b_bcb, (PVOID)((ERESOURCE_THREAD)bh | 0x3)); 679 680 if (!bh->b_data) { 681 free_buffer_head(bh); 682 bh = NULL; 683 goto errorout; 684 } 685 get_bh(bh); 686 687 DEBUG(DL_BH, ("getblk: Vcb=%p bhcount=%u block=%u bh=%p ptr=%p.\n", 688 Vcb, atomic_read(&g_jbh.bh_count), block, bh, bh->b_data)); 689 690 ExAcquireResourceExclusiveLite(&bdev->bd_bh_lock, TRUE); 691 /* do search again here */ 692 tbh = buffer_head_search(bdev, block); 693 if (tbh) { 694 get_bh(tbh); 695 ExReleaseResourceLite(&bdev->bd_bh_lock); 696 free_buffer_head(bh); 697 bh = tbh; 698 RemoveEntryList(&bh->b_link); 699 InitializeListHead(&bh->b_link); 700 goto errorout; 701 } else { 702 buffer_head_insert(bdev, bh); 703 } 704 ExReleaseResourceLite(&bdev->bd_bh_lock); 705 706 /* we get it */ 707 errorout: 708 709 return bh; 710 } 711 712 int submit_bh_pin(int rw, struct buffer_head *bh) 713 { 714 struct block_device *bdev = bh->b_bdev; 715 PEXT2_VCB Vcb = bdev->bd_priv; 716 PVOID Buffer; 717 LARGE_INTEGER Offset; 718 719 ASSERT(Vcb->Identifier.Type == EXT2VCB); 720 ASSERT(bh->b_data && bh->b_bcb); 721 722 if (rw == WRITE) { 723 724 if (IsVcbReadOnly(Vcb)) { 725 goto errorout; 726 } 727 728 SetFlag(Vcb->Volume->Flags, FO_FILE_MODIFIED); 729 Offset.QuadPart = ((LONGLONG)bh->b_blocknr) << BLOCK_BITS; 730 731 CcSetDirtyPinnedData(bh->b_bcb, NULL); 732 Ext2AddBlockExtent( Vcb, NULL, 733 (ULONG)bh->b_blocknr, 734 (ULONG)bh->b_blocknr, 735 (bh->b_size >> BLOCK_BITS)); 736 } else { 737 DbgBreak(); 738 } 739 740 errorout: 741 742 unlock_buffer(bh); 743 put_bh(bh); 744 return 0; 745 } 746 747 #if 0 748 749 struct buffer_head * 750 get_block_bh( 751 struct block_device * bdev, 752 sector_t block, 753 unsigned long size, 754 int zero 755 ) 756 { 757 return get_block_bh_mdl(bdev, block, size, zero); 758 } 759 760 int submit_bh(int rw, struct buffer_head *bh) 761 { 762 return submit_bh_mdl(rw, bh); 763 } 764 765 #else 766 767 struct buffer_head * 768 get_block_bh( 769 struct block_device * bdev, 770 sector_t block, 771 unsigned long size, 772 int zero 773 ) 774 { 775 return get_block_bh_pin(bdev, block, size, zero); 776 } 777 778 int submit_bh(int rw, struct buffer_head *bh) 779 { 780 return submit_bh_pin(rw, bh); 781 } 782 #endif 783 784 struct buffer_head * 785 __getblk( 786 struct block_device * bdev, 787 sector_t block, 788 unsigned long size 789 ) 790 { 791 return get_block_bh(bdev, block, size, 0); 792 } 793 794 void __brelse(struct buffer_head *bh) 795 { 796 struct block_device *bdev = bh->b_bdev; 797 PEXT2_VCB Vcb = (PEXT2_VCB)bdev->bd_priv; 798 799 ASSERT(Vcb->Identifier.Type == EXT2VCB); 800 801 /* write data in case it's dirty */ 802 while (buffer_dirty(bh)) { 803 ll_rw_block(WRITE, 1, &bh); 804 } 805 806 if (1 == atomic_read(&bh->b_count)) { 807 } else if (atomic_dec_and_test(&bh->b_count)) { 808 atomic_inc(&bh->b_count); 809 } else { 810 return; 811 } 812 813 ExAcquireResourceExclusiveLite(&bdev->bd_bh_lock, TRUE); 814 if (atomic_dec_and_test(&bh->b_count)) { 815 ASSERT(0 == atomic_read(&bh->b_count)); 816 } else { 817 ExReleaseResourceLite(&bdev->bd_bh_lock); 818 return; 819 } 820 buffer_head_remove(bdev, bh); 821 KeQuerySystemTime(&bh->b_ts_drop); 822 InsertTailList(&Vcb->bd.bd_bh_free, &bh->b_link); 823 KeClearEvent(&Vcb->bd.bd_bh_notify); 824 ExReleaseResourceLite(&bdev->bd_bh_lock); 825 KeSetEvent(&Ext2Global->bhReaper.Wait, 0, FALSE); 826 827 DEBUG(DL_BH, ("brelse: cnt=%u size=%u blk=%10.10xh bh=%p ptr=%p\n", 828 atomic_read(&g_jbh.bh_count) - 1, bh->b_size, 829 bh->b_blocknr, bh, bh->b_data )); 830 } 831 832 833 void __bforget(struct buffer_head *bh) 834 { 835 clear_buffer_dirty(bh); 836 __brelse(bh); 837 } 838 839 void __lock_buffer(struct buffer_head *bh) 840 { 841 } 842 843 void unlock_buffer(struct buffer_head *bh) 844 { 845 clear_buffer_locked(bh); 846 } 847 848 void __wait_on_buffer(struct buffer_head *bh) 849 { 850 } 851 852 void ll_rw_block(int rw, int nr, struct buffer_head * bhs[]) 853 { 854 int i; 855 856 for (i = 0; i < nr; i++) { 857 858 struct buffer_head *bh = bhs[i]; 859 860 if (rw == SWRITE) 861 lock_buffer(bh); 862 else if (test_set_buffer_locked(bh)) 863 continue; 864 865 if (rw == WRITE || rw == SWRITE) { 866 if (test_clear_buffer_dirty(bh)) { 867 get_bh(bh); 868 submit_bh(WRITE, bh); 869 continue; 870 } 871 } else { 872 if (!buffer_uptodate(bh)) { 873 get_bh(bh); 874 submit_bh(rw, bh); 875 continue; 876 } 877 } 878 unlock_buffer(bh); 879 } 880 } 881 882 int bh_submit_read(struct buffer_head *bh) 883 { 884 ll_rw_block(READ, 1, &bh); 885 return 0; 886 } 887 888 int sync_dirty_buffer(struct buffer_head *bh) 889 { 890 int ret = 0; 891 892 ASSERT(atomic_read(&bh->b_count) <= 1); 893 lock_buffer(bh); 894 if (test_clear_buffer_dirty(bh)) { 895 get_bh(bh); 896 ret = submit_bh(WRITE, bh); 897 wait_on_buffer(bh); 898 } else { 899 unlock_buffer(bh); 900 } 901 return ret; 902 } 903 904 void mark_buffer_dirty(struct buffer_head *bh) 905 { 906 set_buffer_dirty(bh); 907 } 908 909 int sync_blockdev(struct block_device *bdev) 910 { 911 PEXT2_VCB Vcb = (PEXT2_VCB) bdev->bd_priv; 912 Ext2FlushVolume(NULL, Vcb, FALSE); 913 return 0; 914 } 915 916 /* 917 * Perform a pagecache lookup for the matching buffer. If it's there, refre 918 * it in the LRU and mark it as accessed. If it is not present then return 919 * NULL 920 */ 921 struct buffer_head * 922 __find_get_block(struct block_device *bdev, sector_t block, unsigned long size) 923 { 924 return __getblk(bdev, block, size); 925 } 926 927 // 928 // inode block mapping 929 // 930 931 ULONGLONG bmap(struct inode *i, ULONGLONG b) 932 { 933 ULONGLONG lcn = 0; 934 struct super_block *s = i->i_sb; 935 936 PEXT2_MCB Mcb = (PEXT2_MCB)i->i_priv; 937 PEXT2_VCB Vcb = (PEXT2_VCB)s->s_priv; 938 PEXT2_EXTENT extent = NULL; 939 ULONGLONG offset = (ULONGLONG)b; 940 NTSTATUS status; 941 942 if (!Mcb || !Vcb) { 943 goto errorout; 944 } 945 946 offset <<= BLOCK_BITS; 947 status = Ext2BuildExtents( 948 NULL, 949 Vcb, 950 Mcb, 951 offset, 952 BLOCK_SIZE, 953 FALSE, 954 &extent 955 ); 956 957 if (!NT_SUCCESS(status)) { 958 goto errorout; 959 } 960 961 if (extent == NULL) { 962 goto errorout; 963 } 964 965 lcn = (unsigned long)(extent->Lba >> BLOCK_BITS); 966 967 errorout: 968 969 if (extent) { 970 Ext2FreeExtent(extent); 971 } 972 973 return lcn; 974 } 975 976 void iget(struct inode *inode) 977 { 978 atomic_inc(&inode->i_count); 979 } 980 981 void iput(struct inode *inode) 982 { 983 if (atomic_dec_and_test(&inode->i_count)) { 984 kfree(inode); 985 } 986 } 987 988 // 989 // initialzer and destructor 990 // 991 992 int 993 ext2_init_linux() 994 { 995 int rc = 0; 996 997 rc = ext2_init_bh(); 998 if (rc != 0) { 999 goto errorout; 1000 } 1001 1002 errorout: 1003 1004 return rc; 1005 } 1006 1007 void 1008 ext2_destroy_linux() 1009 { 1010 ext2_destroy_bh(); 1011 } 1012