[NTFS]
[reactos.git] / drivers / filesystems / ext2 / src / linux.c
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 = &current_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 }