Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023/* * COPYRIGHT: See COPYRIGHT.TXT * PROJECT: Ext2 File System Driver for WinNT/2K/XP * FILE: linux.c * PROGRAMMER: Matt Wu <mattwu@163.com> * HOMEPAGE: http://www.ext2fsd.com * UPDATE HISTORY: */
/* INCLUDES *****************************************************************/
#include <ext2fs.h>#include <linux/jbd.h>#include <linux/errno.h>
/* GLOBALS ***************************************************************/
extern PEXT2_GLOBAL Ext2Global;
/* DEFINITIONS *************************************************************/
#ifdef ALLOC_PRAGMA#pragma alloc_text(PAGE, kzalloc)#endif
struct task_struct current_task = { /* pid */ 0, /* tid */ 1, /* comm */ "current\0", /* journal_info */ NULL};struct task_struct *current = ¤t_task;
void *kzalloc(int size, int flags){ void *buffer = kmalloc(size, flags); if (buffer) { memset(buffer, 0, size); } return buffer;}
//// slab routines//
kmem_cache_t *kmem_cache_create( const char * name, size_t size, size_t offset, unsigned long flags, kmem_cache_cb_t ctor){ kmem_cache_t *kc = NULL;
kc = kmalloc(sizeof(kmem_cache_t), GFP_KERNEL); if (kc == NULL) { goto errorout; }
memset(kc, 0, sizeof(kmem_cache_t)); ExInitializeNPagedLookasideList( &kc->la, NULL, NULL, 0, size, 'JBKC', 0);
kc->size = size; strncpy(kc->name, name, 31); kc->constructor = ctor;
errorout:
return kc;}
int kmem_cache_destroy(kmem_cache_t * kc){ ASSERT(kc != NULL);
ExDeleteNPagedLookasideList(&(kc->la)); kfree(kc);
return 0;}
void* kmem_cache_alloc(kmem_cache_t *kc, int flags){ PVOID ptr = NULL; ptr = ExAllocateFromNPagedLookasideList(&(kc->la)); if (ptr) { atomic_inc(&kc->count); atomic_inc(&kc->acount); } return ptr;}
void kmem_cache_free(kmem_cache_t *kc, void *p){ if (p) { atomic_dec(&kc->count); ExFreeToNPagedLookasideList(&(kc->la), p); }}
//// wait queue routines//
void init_waitqueue_head(wait_queue_head_t *q){ spin_lock_init(&q->lock); INIT_LIST_HEAD(&q->task_list);}
struct __wait_queue *wait_queue_create(){ struct __wait_queue * wait = NULL; wait = kmalloc(sizeof(struct __wait_queue), GFP_KERNEL); if (!wait) { return NULL; }
memset(wait, 0, sizeof(struct __wait_queue)); wait->flags = WQ_FLAG_AUTO_REMOVAL; wait->private = (void *)KeGetCurrentThread(); INIT_LIST_HEAD(&wait->task_list); KeInitializeEvent(&(wait->event), SynchronizationEvent, FALSE);
return wait;}
voidwait_queue_destroy(struct __wait_queue * wait){ kfree(wait);}
static inline void __add_wait_queue(wait_queue_head_t *head, struct __wait_queue *new){ list_add(&new->task_list, &head->task_list);}
/* * Used for wake-one threads: */static inline void __add_wait_queue_tail(wait_queue_head_t *head, struct __wait_queue *new){ list_add_tail(&new->task_list, &head->task_list);}
static inline void __remove_wait_queue(wait_queue_head_t *head, struct __wait_queue *old){ list_del(&old->task_list);}
void add_wait_queue(wait_queue_head_t *q, wait_queue_t *waiti){ unsigned long flags; struct __wait_queue *wait = *waiti;
wait->flags &= ~WQ_FLAG_EXCLUSIVE; spin_lock_irqsave(&q->lock, flags); __add_wait_queue(q, wait); spin_unlock_irqrestore(&q->lock, flags);}
void add_wait_queue_exclusive(wait_queue_head_t *q, wait_queue_t *waiti){ unsigned long flags; struct __wait_queue *wait = *waiti;
wait->flags |= WQ_FLAG_EXCLUSIVE; spin_lock_irqsave(&q->lock, flags); __add_wait_queue_tail(q, wait); spin_unlock_irqrestore(&q->lock, flags);}
void remove_wait_queue(wait_queue_head_t *q, wait_queue_t *waiti){ unsigned long flags; struct __wait_queue *wait = *waiti;
spin_lock_irqsave(&q->lock, flags); __remove_wait_queue(q, wait); spin_unlock_irqrestore(&q->lock, flags);}
/* * Note: we use "set_current_state()" _after_ the wait-queue add, * because we need a memory barrier there on SMP, so that any * wake-function that tests for the wait-queue being active * will be guaranteed to see waitqueue addition _or_ subsequent * tests in this thread will see the wakeup having taken place. * * The spin_unlock() itself is semi-permeable and only protects * one way (it only protects stuff inside the critical region and * stops them from bleeding out - it would still allow subsequent * loads to move into the critical region). */voidprepare_to_wait(wait_queue_head_t *q, wait_queue_t *waiti, int state){ unsigned long flags; struct __wait_queue *wait = *waiti;
wait->flags &= ~WQ_FLAG_EXCLUSIVE; spin_lock_irqsave(&q->lock, flags); if (list_empty(&wait->task_list)) __add_wait_queue(q, wait); /* * don't alter the task state if this is just going to * queue an async wait queue callback */ if (is_sync_wait(wait)) set_current_state(state); spin_unlock_irqrestore(&q->lock, flags);}
voidprepare_to_wait_exclusive(wait_queue_head_t *q, wait_queue_t *waiti, int state){ unsigned long flags; struct __wait_queue *wait = *waiti;
wait->flags |= WQ_FLAG_EXCLUSIVE; spin_lock_irqsave(&q->lock, flags); if (list_empty(&wait->task_list)) __add_wait_queue_tail(q, wait); /* * don't alter the task state if this is just going to * queue an async wait queue callback */ if (is_sync_wait(wait)) set_current_state(state); spin_unlock_irqrestore(&q->lock, flags);}EXPORT_SYMBOL(prepare_to_wait_exclusive);
void finish_wait(wait_queue_head_t *q, wait_queue_t *waiti){ unsigned long flags; struct __wait_queue *wait = *waiti;
__set_current_state(TASK_RUNNING); /* * We can check for list emptiness outside the lock * IFF: * - we use the "careful" check that verifies both * the next and prev pointers, so that there cannot * be any half-pending updates in progress on other * CPU's that we haven't seen yet (and that might * still change the stack area. * and * - all other users take the lock (ie we can only * have _one_ other CPU that looks at or modifies * the list). */ if (!list_empty_careful(&wait->task_list)) { spin_lock_irqsave(&q->lock, flags); list_del_init(&wait->task_list); spin_unlock_irqrestore(&q->lock, flags); }
/* free wait */ wait_queue_destroy(wait);}
int wake_up(wait_queue_head_t *queue){ return 0; /* KeSetEvent(&wait->event, 0, FALSE); */}
//// kernel timer routines//
//// buffer head routines//
struct _EXT2_BUFFER_HEAD { kmem_cache_t * bh_cache; atomic_t bh_count; atomic_t bh_acount;} g_jbh = {NULL, ATOMIC_INIT(0)};
intext2_init_bh(){ g_jbh.bh_count.counter = 0; g_jbh.bh_acount.counter = 0; g_jbh.bh_cache = kmem_cache_create( "ext2_bh", /* bh */ sizeof(struct buffer_head), 0, /* offset */ SLAB_TEMPORARY, /* flags */ NULL); /* ctor */ if (g_jbh.bh_cache == NULL) { printk(KERN_EMERG "JBD: failed to create handle cache\n"); return -ENOMEM; } return 0;}
voidext2_destroy_bh(){ if (g_jbh.bh_cache) { kmem_cache_destroy(g_jbh.bh_cache); g_jbh.bh_cache = NULL; }}
struct buffer_head *new_buffer_head(){ struct buffer_head * bh = NULL; bh = kmem_cache_alloc(g_jbh.bh_cache, GFP_NOFS); if (bh) { atomic_inc(&g_jbh.bh_count); atomic_inc(&g_jbh.bh_acount);
memset(bh, 0, sizeof(struct buffer_head)); InitializeListHead(&bh->b_link); KeQuerySystemTime(&bh->b_ts_creat); DEBUG(DL_BH, ("bh=%p allocated.\n", bh)); INC_MEM_COUNT(PS_BUFF_HEAD, bh, sizeof(struct buffer_head)); }
return bh;}
voidfree_buffer_head(struct buffer_head * bh){ if (bh) { if (bh->b_mdl) {
DEBUG(DL_BH, ("bh=%p mdl=%p (Flags:%xh VA:%p) released.\n", bh, bh->b_mdl, bh->b_mdl->MdlFlags, bh->b_mdl->MappedSystemVa)); if (IsFlagOn(bh->b_mdl->MdlFlags, MDL_MAPPED_TO_SYSTEM_VA)) { MmUnmapLockedPages(bh->b_mdl->MappedSystemVa, bh->b_mdl); } Ext2DestroyMdl(bh->b_mdl); } if (bh->b_bcb) { CcUnpinDataForThread(bh->b_bcb, (ERESOURCE_THREAD)bh | 0x3); }
DEBUG(DL_BH, ("bh=%p freed.\n", bh)); DEC_MEM_COUNT(PS_BUFF_HEAD, bh, sizeof(struct buffer_head)); kmem_cache_free(g_jbh.bh_cache, bh); atomic_dec(&g_jbh.bh_count); }}
//// Red-black tree insert routine.//
static struct buffer_head *__buffer_head_search(struct rb_root *root, sector_t blocknr){ struct rb_node *new = root->rb_node;
/* Figure out where to put new node */ while (new) { struct buffer_head *bh = container_of(new, struct buffer_head, b_rb_node); s64 result = blocknr - bh->b_blocknr;
if (result < 0) new = new->rb_left; else if (result > 0) new = new->rb_right; else return bh;
}
return NULL;}
static int buffer_head_blocknr_cmp(struct rb_node *a, struct rb_node *b){ struct buffer_head *a_bh, *b_bh; s64 result; a_bh = container_of(a, struct buffer_head, b_rb_node); b_bh = container_of(b, struct buffer_head, b_rb_node); result = a_bh->b_blocknr - b_bh->b_blocknr;
if (result < 0) return -1; if (result > 0) return 1; return 0;}
static struct buffer_head *buffer_head_search(struct block_device *bdev, sector_t blocknr){ struct rb_root *root; root = &bdev->bd_bh_root; return __buffer_head_search(root, blocknr);}
static void buffer_head_insert(struct block_device *bdev, struct buffer_head *bh){ rb_insert(&bdev->bd_bh_root, &bh->b_rb_node, buffer_head_blocknr_cmp);}
void buffer_head_remove(struct block_device *bdev, struct buffer_head *bh){ rb_erase(&bh->b_rb_node, &bdev->bd_bh_root);}
struct buffer_head *get_block_bh_mdl( struct block_device * bdev, sector_t block, unsigned long size, int zero){ PEXT2_VCB Vcb = bdev->bd_priv; LARGE_INTEGER offset; PVOID bcb = NULL; PVOID ptr = NULL;
struct list_head *entry;
/* allocate buffer_head and initialize it */ struct buffer_head *bh = NULL, *tbh = NULL;
/* check the block is valid or not */ if (block >= TOTAL_BLOCKS) { DbgBreak(); goto errorout; }
/* search the bdev bh list */ ExAcquireSharedStarveExclusive(&bdev->bd_bh_lock, TRUE); tbh = buffer_head_search(bdev, block); if (tbh) { bh = tbh; get_bh(bh); ExReleaseResourceLite(&bdev->bd_bh_lock); goto errorout; } ExReleaseResourceLite(&bdev->bd_bh_lock);
bh = new_buffer_head(); if (!bh) { goto errorout; } bh->b_bdev = bdev; bh->b_blocknr = block; bh->b_size = size; bh->b_data = NULL;#ifdef __REACTOS__ InitializeListHead(&bh->b_link);#endif
again:
offset.QuadPart = (s64) bh->b_blocknr; offset.QuadPart <<= BLOCK_BITS;
if (zero) { /* PIN_EXCLUSIVE disabled, likely to deadlock with volume operations */ if (!CcPreparePinWrite(Vcb->Volume, &offset, bh->b_size, FALSE, PIN_WAIT /* | PIN_EXCLUSIVE */, &bcb, &ptr)) { Ext2Sleep(100); goto again; } } else { if (!CcPinRead( Vcb->Volume, &offset, bh->b_size, PIN_WAIT, &bcb, &ptr)) { Ext2Sleep(100); goto again; } set_buffer_uptodate(bh); }
bh->b_mdl = Ext2CreateMdl(ptr, bh->b_size, IoModifyAccess); if (bh->b_mdl) { /* muse map the PTE to NonCached zone. journal recovery will access the PTE under spinlock: DISPATCH_LEVEL IRQL */ bh->b_data = MmMapLockedPagesSpecifyCache( bh->b_mdl, KernelMode, MmNonCached, NULL,FALSE, HighPagePriority); /* bh->b_data = MmMapLockedPages(bh->b_mdl, KernelMode); */ } if (!bh->b_mdl || !bh->b_data) { free_buffer_head(bh); bh = NULL; goto errorout; }
get_bh(bh);
DEBUG(DL_BH, ("getblk: Vcb=%p bhcount=%u block=%u bh=%p mdl=%p (Flags:%xh VA:%p)\n", Vcb, atomic_read(&g_jbh.bh_count), block, bh, bh->b_mdl, bh->b_mdl->MdlFlags, bh->b_data));
ExAcquireResourceExclusiveLite(&bdev->bd_bh_lock, TRUE); /* do search again here */ tbh = buffer_head_search(bdev, block); if (tbh) { free_buffer_head(bh); bh = tbh; get_bh(bh); RemoveEntryList(&bh->b_link); InitializeListHead(&bh->b_link); ExReleaseResourceLite(&bdev->bd_bh_lock); goto errorout; } else { buffer_head_insert(bdev, bh); } ExReleaseResourceLite(&bdev->bd_bh_lock);
/* we get it */errorout:
if (bcb) CcUnpinData(bcb);
return bh;}
int submit_bh_mdl(int rw, struct buffer_head *bh){ struct block_device *bdev = bh->b_bdev; PEXT2_VCB Vcb = bdev->bd_priv; PBCB Bcb; PVOID Buffer; LARGE_INTEGER Offset;
ASSERT(Vcb->Identifier.Type == EXT2VCB); ASSERT(bh->b_data);
if (rw == WRITE) {
if (IsVcbReadOnly(Vcb)) { goto errorout; }
SetFlag(Vcb->Volume->Flags, FO_FILE_MODIFIED); Offset.QuadPart = ((LONGLONG)bh->b_blocknr) << BLOCK_BITS;
/* PIN_EXCLUSIVE disabled, likely to deadlock with volume operations */ if (CcPreparePinWrite( Vcb->Volume, &Offset, BLOCK_SIZE, FALSE, PIN_WAIT /* | PIN_EXCLUSIVE */, &Bcb, &Buffer )) {#if 0 if (memcmp(Buffer, bh->b_data, BLOCK_SIZE) != 0) { DbgBreak(); } memmove(Buffer, bh->b_data, BLOCK_SIZE);#endif CcSetDirtyPinnedData(Bcb, NULL); Ext2AddBlockExtent( Vcb, NULL, (ULONG)bh->b_blocknr, (ULONG)bh->b_blocknr, (bh->b_size >> BLOCK_BITS)); CcUnpinData(Bcb); } else {
Ext2AddBlockExtent( Vcb, NULL, (ULONG)bh->b_blocknr, (ULONG)bh->b_blocknr, (bh->b_size >> BLOCK_BITS)); }
} else { }
errorout:
unlock_buffer(bh); put_bh(bh); return 0;}
struct buffer_head *get_block_bh_pin( struct block_device * bdev, sector_t block, unsigned long size, int zero){ PEXT2_VCB Vcb = bdev->bd_priv; LARGE_INTEGER offset;
struct list_head *entry;
/* allocate buffer_head and initialize it */ struct buffer_head *bh = NULL, *tbh = NULL;
/* check the block is valid or not */ if (block >= TOTAL_BLOCKS) { DbgBreak(); goto errorout; }
/* search the bdev bh list */ ExAcquireSharedStarveExclusive(&bdev->bd_bh_lock, TRUE); tbh = buffer_head_search(bdev, block); if (tbh) { bh = tbh; get_bh(bh); ExReleaseResourceLite(&bdev->bd_bh_lock); goto errorout; } ExReleaseResourceLite(&bdev->bd_bh_lock);
bh = new_buffer_head(); if (!bh) { goto errorout; } bh->b_bdev = bdev; bh->b_blocknr = block; bh->b_size = size; bh->b_data = NULL;#ifdef __REACTOS__ InitializeListHead(&bh->b_link);#endif
again:
offset.QuadPart = (s64) bh->b_blocknr; offset.QuadPart <<= BLOCK_BITS;
if (zero) { if (!CcPreparePinWrite(Vcb->Volume, &offset, bh->b_size, FALSE, PIN_WAIT, &bh->b_bcb,#ifdef __REACTOS__ (PVOID *)&bh->b_data)) {#else &bh->b_data)) {#endif Ext2Sleep(100); goto again; } } else { if (!CcPinRead( Vcb->Volume, &offset, bh->b_size, PIN_WAIT, &bh->b_bcb,#ifdef __REACTOS__ (PVOID *)&bh->b_data)) {#else &bh->b_data)) {#endif Ext2Sleep(100); goto again; } set_buffer_uptodate(bh); }
if (bh->b_bcb) CcSetBcbOwnerPointer(bh->b_bcb, (PVOID)((ERESOURCE_THREAD)bh | 0x3));
if (!bh->b_data) { free_buffer_head(bh); bh = NULL; goto errorout; } get_bh(bh);
DEBUG(DL_BH, ("getblk: Vcb=%p bhcount=%u block=%u bh=%p ptr=%p.\n", Vcb, atomic_read(&g_jbh.bh_count), block, bh, bh->b_data));
ExAcquireResourceExclusiveLite(&bdev->bd_bh_lock, TRUE); /* do search again here */ tbh = buffer_head_search(bdev, block); if (tbh) { get_bh(tbh); free_buffer_head(bh); bh = tbh; RemoveEntryList(&bh->b_link); InitializeListHead(&bh->b_link); ExReleaseResourceLite(&bdev->bd_bh_lock); goto errorout; } else { buffer_head_insert(bdev, bh); } ExReleaseResourceLite(&bdev->bd_bh_lock);
/* we get it */errorout:
return bh;}
int submit_bh_pin(int rw, struct buffer_head *bh){ struct block_device *bdev = bh->b_bdev; PEXT2_VCB Vcb = bdev->bd_priv; PVOID Buffer; LARGE_INTEGER Offset;
ASSERT(Vcb->Identifier.Type == EXT2VCB); ASSERT(bh->b_data && bh->b_bcb);
if (rw == WRITE) {
if (IsVcbReadOnly(Vcb)) { goto errorout; }
SetFlag(Vcb->Volume->Flags, FO_FILE_MODIFIED); Offset.QuadPart = ((LONGLONG)bh->b_blocknr) << BLOCK_BITS;
CcSetDirtyPinnedData(bh->b_bcb, NULL); Ext2AddBlockExtent( Vcb, NULL, (ULONG)bh->b_blocknr, (ULONG)bh->b_blocknr, (bh->b_size >> BLOCK_BITS)); } else { }
errorout:
unlock_buffer(bh); put_bh(bh); return 0;}
#if 0
struct buffer_head *get_block_bh( struct block_device * bdev, sector_t block, unsigned long size, int zero){ return get_block_bh_mdl(bdev, block, size, zero);}
int submit_bh(int rw, struct buffer_head *bh){ return submit_bh_mdl(rw, bh);}
#else
struct buffer_head *get_block_bh( struct block_device * bdev, sector_t block, unsigned long size, int zero){ return get_block_bh_pin(bdev, block, size, zero);}
int submit_bh(int rw, struct buffer_head *bh){ return submit_bh_pin(rw, bh);}#endif
struct buffer_head *__getblk( struct block_device * bdev, sector_t block, unsigned long size){ return get_block_bh(bdev, block, size, 0);}
void __brelse(struct buffer_head *bh){ struct block_device *bdev = bh->b_bdev; PEXT2_VCB Vcb = (PEXT2_VCB)bdev->bd_priv;
ASSERT(Vcb->Identifier.Type == EXT2VCB);
/* write data in case it's dirty */ while (buffer_dirty(bh)) { ll_rw_block(WRITE, 1, &bh); }
ExAcquireResourceExclusiveLite(&bdev->bd_bh_lock, TRUE); if (atomic_dec_and_test(&bh->b_count)) { ASSERT(0 == atomic_read(&bh->b_count)); } else { ExReleaseResourceLite(&bdev->bd_bh_lock); return; } KeQuerySystemTime(&bh->b_ts_drop);#ifdef __REACTOS__ if (!IsListEmpty(&bh->b_link))#endif RemoveEntryList(&bh->b_link); InsertTailList(&Vcb->bd.bd_bh_free, &bh->b_link); KeClearEvent(&Vcb->bd.bd_bh_notify); ExReleaseResourceLite(&bdev->bd_bh_lock); KeSetEvent(&Ext2Global->bhReaper.Wait, 0, FALSE);
DEBUG(DL_BH, ("brelse: cnt=%u size=%u blk=%10.10xh bh=%p ptr=%p\n", atomic_read(&g_jbh.bh_count) - 1, bh->b_size, bh->b_blocknr, bh, bh->b_data ));}
void __bforget(struct buffer_head *bh){ clear_buffer_dirty(bh); __brelse(bh);}
void __lock_buffer(struct buffer_head *bh){}
void unlock_buffer(struct buffer_head *bh){ clear_buffer_locked(bh);}
void __wait_on_buffer(struct buffer_head *bh){}
void ll_rw_block(int rw, int nr, struct buffer_head * bhs[]){ int i;
for (i = 0; i < nr; i++) {
struct buffer_head *bh = bhs[i];
if (rw == SWRITE) lock_buffer(bh); else if (test_set_buffer_locked(bh)) continue;
if (rw == WRITE || rw == SWRITE) { if (test_clear_buffer_dirty(bh)) { get_bh(bh); submit_bh(WRITE, bh); continue; } } else { if (!buffer_uptodate(bh)) { get_bh(bh); submit_bh(rw, bh); continue; } } unlock_buffer(bh); }}
int bh_submit_read(struct buffer_head *bh){ ll_rw_block(READ, 1, &bh); return 0;}
int sync_dirty_buffer(struct buffer_head *bh){ int ret = 0;
ASSERT(atomic_read(&bh->b_count) <= 1); lock_buffer(bh); if (test_clear_buffer_dirty(bh)) { get_bh(bh); ret = submit_bh(WRITE, bh); wait_on_buffer(bh); } else { unlock_buffer(bh); } return ret;}
void mark_buffer_dirty(struct buffer_head *bh){ set_buffer_dirty(bh);}
int sync_blockdev(struct block_device *bdev){ PEXT2_VCB Vcb = (PEXT2_VCB) bdev->bd_priv; Ext2FlushVolume(NULL, Vcb, FALSE); return 0;}
/* * Perform a pagecache lookup for the matching buffer. If it's there, refre * it in the LRU and mark it as accessed. If it is not present then return * NULL */struct buffer_head *__find_get_block(struct block_device *bdev, sector_t block, unsigned long size){ return __getblk(bdev, block, size);}
//// inode block mapping//
ULONGLONG bmap(struct inode *i, ULONGLONG b){ ULONGLONG lcn = 0; struct super_block *s = i->i_sb;
PEXT2_MCB Mcb = (PEXT2_MCB)i->i_priv; PEXT2_VCB Vcb = (PEXT2_VCB)s->s_priv; PEXT2_EXTENT extent = NULL; ULONGLONG offset = (ULONGLONG)b; NTSTATUS status;
if (!Mcb || !Vcb) { goto errorout; }
offset <<= BLOCK_BITS; status = Ext2BuildExtents( NULL, Vcb, Mcb, offset, BLOCK_SIZE, FALSE, &extent );
if (!NT_SUCCESS(status)) { goto errorout; }
if (extent == NULL) { goto errorout; }
lcn = (unsigned long)(extent->Lba >> BLOCK_BITS);
errorout:
if (extent) { Ext2FreeExtent(extent); }
return lcn;}
void iget(struct inode *inode){ atomic_inc(&inode->i_count);}
void iput(struct inode *inode){ if (atomic_dec_and_test(&inode->i_count)) { kfree(inode); }}
//// initialzer and destructor//
intext2_init_linux(){ int rc = 0;
rc = ext2_init_bh(); if (rc != 0) { goto errorout; }
errorout:
return rc;}
voidext2_destroy_linux(){ ext2_destroy_bh();}