Something went wrong. Try again.
Reactos
Something went wrong. Try again.
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170/* * COPYRIGHT: See COPYRIGHT.TXT * PROJECT: Ext2 File System Driver for WinNT/2K/XP * FILE: generic.c * PROGRAMMER: Matt Wu <mattwu@163.com> * HOMEPAGE: http://www.ext2fsd.com * UPDATE HISTORY: */
/* INCLUDES *****************************************************************/
#include "ext2fs.h"#ifdef __REACTOS__#include "linux/ext4.h"#else#include "linux\ext4.h"#endif
/* GLOBALS ***************************************************************/
extern PEXT2_GLOBAL Ext2Global;
/* DEFINITIONS *************************************************************/
/* FUNCTIONS ***************************************************************/
NTSTATUSExt2LoadSuper(IN PEXT2_VCB Vcb, IN BOOLEAN bVerify, OUT PEXT2_SUPER_BLOCK * Sb){ NTSTATUS Status; PEXT2_SUPER_BLOCK Ext2Sb = NULL;
Ext2Sb = (PEXT2_SUPER_BLOCK) Ext2AllocatePool( PagedPool, SUPER_BLOCK_SIZE, EXT2_SB_MAGIC ); if (!Ext2Sb) { Status = STATUS_INSUFFICIENT_RESOURCES; goto errorout; }
Status = Ext2ReadDisk( Vcb, (ULONGLONG) SUPER_BLOCK_OFFSET, SUPER_BLOCK_SIZE, (PVOID) Ext2Sb, bVerify );
if (!NT_SUCCESS(Status)) { Ext2FreePool(Ext2Sb, EXT2_SB_MAGIC); Ext2Sb = NULL; }
errorout:
*Sb = Ext2Sb; return Status;}
BOOLEANExt2SaveSuper( IN PEXT2_IRP_CONTEXT IrpContext, IN PEXT2_VCB Vcb){ LONGLONG offset; BOOLEAN rc;
offset = (LONGLONG) SUPER_BLOCK_OFFSET; rc = Ext2SaveBuffer( IrpContext, Vcb, offset, SUPER_BLOCK_SIZE, Vcb->SuperBlock );
if (IsFlagOn(Vcb->Flags, VCB_FLOPPY_DISK)) { Ext2StartFloppyFlushDpc(Vcb, NULL, NULL); }
return rc;}
BOOLEANExt2RefreshSuper ( IN PEXT2_IRP_CONTEXT IrpContext, IN PEXT2_VCB Vcb){ LONGLONG offset; IO_STATUS_BLOCK iosb;
offset = (LONGLONG) SUPER_BLOCK_OFFSET; if (!CcCopyRead( Vcb->Volume, (PLARGE_INTEGER)&offset, SUPER_BLOCK_SIZE, TRUE, (PVOID)Vcb->SuperBlock, &iosb )) { return FALSE; }
if (!NT_SUCCESS(iosb.Status)) { return FALSE; }
/* reload root inode */ if (Vcb->McbTree) {
if (!Ext2LoadInode(Vcb, &Vcb->McbTree->Inode)) return FALSE;
/* initializeroot node */ Vcb->McbTree->CreationTime = Ext2NtTime(Vcb->McbTree->Inode.i_ctime); Vcb->McbTree->LastAccessTime = Ext2NtTime(Vcb->McbTree->Inode.i_atime); Vcb->McbTree->LastWriteTime = Ext2NtTime(Vcb->McbTree->Inode.i_mtime); Vcb->McbTree->ChangeTime = Ext2NtTime(Vcb->McbTree->Inode.i_mtime); }
return TRUE;}
VOIDExt2DropGroupBH(IN PEXT2_VCB Vcb){ struct ext3_sb_info *sbi = &Vcb->sbi; unsigned long i;
if (NULL == Vcb->sbi.s_gd) { return; }
for (i = 0; i < Vcb->sbi.s_gdb_count; i++) { if (Vcb->sbi.s_gd[i].bh) { fini_bh(&sbi->s_gd[i].bh); Vcb->sbi.s_gd[i].bh = NULL; } }}
VOIDExt2PutGroup(IN PEXT2_VCB Vcb){ struct ext3_sb_info *sbi = &Vcb->sbi; unsigned long i;
if (NULL == Vcb->sbi.s_gd) { return; }
Ext2DropGroupBH(Vcb);
kfree(Vcb->sbi.s_gd); Vcb->sbi.s_gd = NULL;
ClearFlag(Vcb->Flags, VCB_GD_LOADED);}
BOOLEANExt2LoadGroupBH(IN PEXT2_VCB Vcb){ struct super_block *sb = &Vcb->sb; struct ext3_sb_info *sbi = &Vcb->sbi; unsigned long i; BOOLEAN rc = FALSE;
_SEH2_TRY {
ExAcquireResourceExclusiveLite(&Vcb->sbi.s_gd_lock, TRUE); ASSERT (NULL != sbi->s_gd);
for (i = 0; i < sbi->s_gdb_count; i++) { ASSERT (sbi->s_gd[i].block); if (sbi->s_gd[i].bh) continue; sbi->s_gd[i].bh = sb_getblk(sb, sbi->s_gd[i].block); if (!sbi->s_gd[i].bh) { DEBUG(DL_ERR, ("Ext2LoadGroupBH: can't read group descriptor %d\n", i)); DbgBreak(); _SEH2_LEAVE; } sbi->s_gd[i].gd = (struct ext4_group_desc *)sbi->s_gd[i].bh->b_data; }
rc = TRUE;
} _SEH2_FINALLY {
ExReleaseResourceLite(&Vcb->sbi.s_gd_lock); } _SEH2_END;
return rc;}
BOOLEANExt2LoadGroup(IN PEXT2_VCB Vcb){ struct super_block *sb = &Vcb->sb; struct ext3_sb_info *sbi = &Vcb->sbi; ext3_fsblk_t sb_block = 1; unsigned long i; BOOLEAN rc = FALSE;
_SEH2_TRY {
ExAcquireResourceExclusiveLite(&Vcb->sbi.s_gd_lock, TRUE);
if (NULL == sbi->s_gd) { sbi->s_gd = kzalloc(sbi->s_gdb_count * sizeof(struct ext3_gd), GFP_KERNEL); } if (sbi->s_gd == NULL) { DEBUG(DL_ERR, ("Ext2LoadGroup: not enough memory.\n")); _SEH2_LEAVE; }
if (BLOCK_SIZE != EXT3_MIN_BLOCK_SIZE) { sb_block = EXT4_MIN_BLOCK_SIZE / BLOCK_SIZE; }
for (i = 0; i < sbi->s_gdb_count; i++) { sbi->s_gd[i].block = descriptor_loc(sb, sb_block, i); if (!sbi->s_gd[i].block) { DEBUG(DL_ERR, ("Ext2LoadGroup: can't locate group descriptor %d\n", i)); _SEH2_LEAVE; } }
if (!Ext2LoadGroupBH(Vcb)) { DEBUG(DL_ERR, ("Ext2LoadGroup: Failed to load group descriptions !\n")); _SEH2_LEAVE; }
if (!ext4_check_descriptors(sb)) { DbgBreak(); DEBUG(DL_ERR, ("Ext2LoadGroup: group descriptors corrupted !\n")); _SEH2_LEAVE; }
SetFlag(Vcb->Flags, VCB_GD_LOADED); rc = TRUE;
} _SEH2_FINALLY {
if (!rc) Ext2PutGroup(Vcb);
ExReleaseResourceLite(&Vcb->sbi.s_gd_lock); } _SEH2_END;
return rc;}
VOIDExt2DropBH(IN PEXT2_VCB Vcb){ struct ext3_sb_info *sbi = &Vcb->sbi;
/* do nothing if Vcb is not initialized yet */ if (!IsFlagOn(Vcb->Flags, VCB_INITIALIZED)) return;
_SEH2_TRY {
/* acquire bd lock to avoid bh creation */ ExAcquireResourceExclusiveLite(&Vcb->bd.bd_bh_lock, TRUE);
SetFlag(Vcb->Flags, VCB_BEING_DROPPED); Ext2DropGroupBH(Vcb);
while (!IsListEmpty(&Vcb->bd.bd_bh_free)) { struct buffer_head *bh; PLIST_ENTRY l; l = RemoveHeadList(&Vcb->bd.bd_bh_free); bh = CONTAINING_RECORD(l, struct buffer_head, b_link); InitializeListHead(&bh->b_link); if (0 == atomic_read(&bh->b_count)) { buffer_head_remove(&Vcb->bd, bh); free_buffer_head(bh); } }
} _SEH2_FINALLY { ExReleaseResourceLite(&Vcb->bd.bd_bh_lock); } _SEH2_END;
ClearFlag(Vcb->Flags, VCB_BEING_DROPPED);}
VOIDExt2FlushRange(IN PEXT2_VCB Vcb, LARGE_INTEGER s, LARGE_INTEGER e){ ULONG len;
if (e.QuadPart <= s.QuadPart) return;
/* loop per 2G */ while (s.QuadPart < e.QuadPart) { if (e.QuadPart > s.QuadPart + 1024 * 1024 * 1024) { len = 1024 * 1024 * 1024; } else { len = (ULONG) (e.QuadPart - s.QuadPart); } CcFlushCache(&Vcb->SectionObject, &s, len, NULL); s.QuadPart += len; }}
NTSTATUSExt2FlushVcb(IN PEXT2_VCB Vcb){ LARGE_INTEGER s = {0}, o; struct ext3_sb_info *sbi = &Vcb->sbi; struct rb_node *node; struct buffer_head *bh;
if (!IsFlagOn(Vcb->Flags, VCB_GD_LOADED)) { CcFlushCache(&Vcb->SectionObject, NULL, 0, NULL); goto errorout; }
ASSERT(ExIsResourceAcquiredExclusiveLite(&Vcb->MainResource));
_SEH2_TRY {
/* acqurie gd block */ ExAcquireResourceExclusiveLite(&Vcb->sbi.s_gd_lock, TRUE);
/* acquire bd lock to avoid bh creation */ ExAcquireResourceExclusiveLite(&Vcb->bd.bd_bh_lock, TRUE);
/* drop unused bh */ Ext2DropBH(Vcb);
/* flush volume with all outstanding bh skipped */
node = rb_first(&Vcb->bd.bd_bh_root); while (node) {
bh = container_of(node, struct buffer_head, b_rb_node); node = rb_next(node);
o.QuadPart = bh->b_blocknr << BLOCK_BITS; ASSERT(o.QuadPart >= s.QuadPart);
if (o.QuadPart == s.QuadPart) { s.QuadPart = s.QuadPart + bh->b_size; continue; }
if (o.QuadPart > s.QuadPart) { Ext2FlushRange(Vcb, s, o); s.QuadPart = (bh->b_blocknr << BLOCK_BITS) + bh->b_size; continue; } }
o = Vcb->PartitionInformation.PartitionLength; Ext2FlushRange(Vcb, s, o);
} _SEH2_FINALLY {
ExReleaseResourceLite(&Vcb->bd.bd_bh_lock); ExReleaseResourceLite(&Vcb->sbi.s_gd_lock); } _SEH2_END;
errorout: return STATUS_SUCCESS;}
BOOLEANExt2SaveGroup( IN PEXT2_IRP_CONTEXT IrpContext, IN PEXT2_VCB Vcb, IN ULONG Group){ struct ext4_group_desc *gd; struct buffer_head *gb = NULL; unsigned long i;
gd = ext4_get_group_desc(&Vcb->sb, Group, &gb); if (!gd) return 0;
gd->bg_checksum = ext4_group_desc_csum(&Vcb->sbi, Group, gd); mark_buffer_dirty(gb); fini_bh(&gb);
return TRUE;}
BOOLEANExt2RefreshGroup( IN PEXT2_IRP_CONTEXT IrpContext, IN PEXT2_VCB Vcb){ return TRUE;}
BOOLEANExt2GetInodeLba ( IN PEXT2_VCB Vcb, IN ULONG inode, OUT PLONGLONG offset){ PEXT2_GROUP_DESC gd; struct buffer_head *bh = NULL; ext4_fsblk_t loc; int group;
if (inode < 1 || inode > INODES_COUNT) { DEBUG(DL_ERR, ( "Ext2GetInodeLba: Inode value %xh is invalid.\n",inode)); *offset = 0; return FALSE; }
group = (inode - 1) / INODES_PER_GROUP ; gd = ext4_get_group_desc(&Vcb->sb, group, &bh); if (!bh) { *offset = 0; DbgBreak(); return FALSE; } loc = (LONGLONG)ext4_inode_table(&Vcb->sb, gd); loc = loc << BLOCK_BITS; loc = loc + ((inode - 1) % INODES_PER_GROUP) * Vcb->InodeSize;
*offset = loc; __brelse(bh);
return TRUE;}
void Ext2DecodeInode(struct inode *dst, struct ext3_inode *src){ dst->i_mode = src->i_mode; dst->i_flags = src->i_flags; dst->i_uid = src->i_uid; dst->i_gid = src->i_gid; dst->i_nlink = src->i_links_count; dst->i_generation = src->i_generation; dst->i_size = src->i_size; if (S_ISREG(src->i_mode)) { dst->i_size |= (loff_t)src->i_size_high << 32; } dst->i_file_acl = src->i_file_acl_lo; dst->i_file_acl |= (ext4_fsblk_t)src->osd2.linux2.l_i_file_acl_high << 32; dst->i_atime = src->i_atime; dst->i_ctime = src->i_ctime; dst->i_mtime = src->i_mtime; dst->i_dtime = src->i_dtime; dst->i_blocks = ext3_inode_blocks(src, dst); memcpy(&dst->i_block[0], &src->i_block[0], sizeof(__u32) * 15); if (EXT3_HAS_RO_COMPAT_FEATURE(dst->i_sb, EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE)) dst->i_extra_isize = src->i_extra_isize; else dst->i_extra_isize = 0;}
void Ext2EncodeInode(struct ext3_inode *dst, struct inode *src){ dst->i_mode = src->i_mode; dst->i_flags = src->i_flags; dst->i_uid = src->i_uid; dst->i_gid = src->i_gid; dst->i_links_count = src->i_nlink; dst->i_generation = src->i_generation; dst->i_size = (__u32)src->i_size; if (S_ISREG(src->i_mode)) { dst->i_size_high = (__u32)(src->i_size >> 32); } dst->i_file_acl_lo = (__u32)src->i_file_acl; dst->osd2.linux2.l_i_file_acl_high |= (__u16)(src->i_file_acl >> 32); dst->i_atime = src->i_atime; dst->i_ctime = src->i_ctime; dst->i_mtime = src->i_mtime; dst->i_dtime = src->i_dtime; dst->i_extra_isize = src->i_extra_isize; ASSERT(src->i_sb); ext3_inode_blocks_set(dst, src); memcpy(&dst->i_block[0], &src->i_block[0], sizeof(__u32) * 15); if (EXT3_HAS_RO_COMPAT_FEATURE(src->i_sb, EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE)) dst->i_extra_isize = src->i_extra_isize;}
BOOLEANExt2LoadInode (IN PEXT2_VCB Vcb, IN struct inode *Inode){ struct ext3_inode ext3i = {0}; LONGLONG offset;
if (!Ext2GetInodeLba(Vcb, Inode->i_ino, &offset)) { DEBUG(DL_ERR, ("Ext2LoadInode: failed inode %u.\n", Inode->i_ino)); return FALSE; }
if (!Ext2LoadBuffer(NULL, Vcb, offset, sizeof(ext3i), &ext3i)) { return FALSE; }
Ext2DecodeInode(Inode, &ext3i);
return TRUE;}
BOOLEANExt2ClearInode ( IN PEXT2_IRP_CONTEXT IrpContext, IN PEXT2_VCB Vcb, IN ULONG Inode){ LONGLONG Offset = 0; BOOLEAN rc;
rc = Ext2GetInodeLba(Vcb, Inode, &Offset); if (!rc) { DEBUG(DL_ERR, ( "Ext2SaveInode: failed inode %u.\n", Inode)); goto errorout; }
rc = Ext2ZeroBuffer(IrpContext, Vcb, Offset, Vcb->InodeSize);
errorout:
return rc;}
BOOLEANExt2SaveInode ( IN PEXT2_IRP_CONTEXT IrpContext, IN PEXT2_VCB Vcb, IN struct inode *Inode){ struct ext3_inode ext3i = {0};
LONGLONG Offset = 0; ULONG InodeSize = sizeof(ext3i); BOOLEAN rc = 0;
DEBUG(DL_INF, ( "Ext2SaveInode: Saving Inode %xh: Mode=%xh Size=%xh\n", Inode->i_ino, Inode->i_mode, Inode->i_size)); rc = Ext2GetInodeLba(Vcb, Inode->i_ino, &Offset); if (!rc) { DEBUG(DL_ERR, ( "Ext2SaveInode: failed inode %u.\n", Inode->i_ino)); goto errorout; }
rc = Ext2LoadBuffer(NULL, Vcb, Offset, InodeSize, &ext3i); if (!rc) { DEBUG(DL_ERR, ( "Ext2SaveInode: failed reading inode %u.\n", Inode->i_ino)); goto errorout;; }
Ext2EncodeInode(&ext3i, Inode); if (InodeSize > Vcb->InodeSize) InodeSize = Vcb->InodeSize; rc = Ext2SaveBuffer(IrpContext, Vcb, Offset, InodeSize, &ext3i);
if (rc && IsFlagOn(Vcb->Flags, VCB_FLOPPY_DISK)) { Ext2StartFloppyFlushDpc(Vcb, NULL, NULL); }
errorout: return rc;}
BOOLEANExt2LoadInodeXattr(IN PEXT2_VCB Vcb, IN struct inode *Inode, IN PEXT2_INODE InodeXattr){ IO_STATUS_BLOCK IoStatus; LONGLONG Offset;
if (!Ext2GetInodeLba(Vcb, Inode->i_ino, &Offset)) { DEBUG(DL_ERR, ("Ext2LoadRawInode: error get inode(%xh)'s addr.\n", Inode->i_ino)); return FALSE; }
if (!CcCopyRead( Vcb->Volume, (PLARGE_INTEGER)&Offset, Vcb->InodeSize, PIN_WAIT, (PVOID)InodeXattr, &IoStatus)) { return FALSE; }
if (!NT_SUCCESS(IoStatus.Status)) { return FALSE; }
Ext2EncodeInode(InodeXattr, Inode); return TRUE;}
BOOLEANExt2SaveInodeXattr(IN PEXT2_IRP_CONTEXT IrpContext, IN PEXT2_VCB Vcb, IN struct inode *Inode, IN PEXT2_INODE InodeXattr){ IO_STATUS_BLOCK IoStatus; LONGLONG Offset = 0; ULONG InodeSize = Vcb->InodeSize; BOOLEAN rc = 0;
/* There is no way to put EA information in such a small inode */ if (InodeSize == EXT2_GOOD_OLD_INODE_SIZE) return FALSE;
DEBUG(DL_INF, ("Ext2SaveInodeXattr: Saving Inode %xh: Mode=%xh Size=%xh\n", Inode->i_ino, Inode->i_mode, Inode->i_size)); rc = Ext2GetInodeLba(Vcb, Inode->i_ino, &Offset); if (!rc) { DEBUG(DL_ERR, ("Ext2SaveInodeXattr: error get inode(%xh)'s addr.\n", Inode->i_ino)); goto errorout; }
rc = Ext2SaveBuffer(IrpContext, Vcb, Offset + EXT2_GOOD_OLD_INODE_SIZE + Inode->i_extra_isize, InodeSize - EXT2_GOOD_OLD_INODE_SIZE - Inode->i_extra_isize, (char *)InodeXattr + EXT2_GOOD_OLD_INODE_SIZE + Inode->i_extra_isize);
if (rc && IsFlagOn(Vcb->Flags, VCB_FLOPPY_DISK)) { Ext2StartFloppyFlushDpc(Vcb, NULL, NULL); }
errorout: return rc;}
BOOLEANExt2LoadBlock (IN PEXT2_VCB Vcb, IN ULONG Index, IN PVOID Buffer ){ struct buffer_head *bh = NULL; BOOLEAN rc = 0;
_SEH2_TRY {
bh = sb_getblk(&Vcb->sb, (sector_t)Index);
if (!bh) { DEBUG(DL_ERR, ("Ext2Loadblock: can't load block %u\n", Index)); DbgBreak(); _SEH2_LEAVE; }
if (!buffer_uptodate(bh)) { int err = bh_submit_read(bh); if (err < 0) { DEBUG(DL_ERR, ("Ext2LoadBlock: reading failed %d\n", err)); _SEH2_LEAVE; } }
RtlCopyMemory(Buffer, bh->b_data, BLOCK_SIZE); rc = TRUE;
} _SEH2_FINALLY {
if (bh) fini_bh(&bh); } _SEH2_END;
return rc;}
BOOLEANExt2SaveBlock ( IN PEXT2_IRP_CONTEXT IrpContext, IN PEXT2_VCB Vcb, IN ULONG Index, IN PVOID Buf ){ struct buffer_head *bh = NULL; BOOLEAN rc = 0;
_SEH2_TRY {
bh = sb_getblk_zero(&Vcb->sb, (sector_t)Index);
if (!bh) { DEBUG(DL_ERR, ("Ext2Saveblock: can't load block %u\n", Index)); DbgBreak(); _SEH2_LEAVE; }
if (!buffer_uptodate(bh)) { }
RtlCopyMemory(bh->b_data, Buf, BLOCK_SIZE); mark_buffer_dirty(bh); rc = TRUE;
} _SEH2_FINALLY {
if (bh) fini_bh(&bh); } _SEH2_END;
return rc;}
BOOLEANExt2LoadBuffer( IN PEXT2_IRP_CONTEXT IrpContext, IN PEXT2_VCB Vcb, IN LONGLONG offset, IN ULONG size, IN PVOID buf ){ struct buffer_head *bh = NULL; BOOLEAN rc;
_SEH2_TRY {
while (size) {
sector_t block; ULONG len = 0, delta = 0;
block = (sector_t) (offset >> BLOCK_BITS); delta = (ULONG)offset & (BLOCK_SIZE - 1); len = BLOCK_SIZE - delta; if (size < len) len = size;
bh = sb_getblk(&Vcb->sb, block); if (!bh) { DEBUG(DL_ERR, ("Ext2SaveBuffer: can't load block %I64u\n", block)); DbgBreak(); _SEH2_LEAVE; }
if (!buffer_uptodate(bh)) { int err = bh_submit_read(bh); if (err < 0) { DEBUG(DL_ERR, ("Ext2SaveBuffer: bh_submit_read failed: %d\n", err)); _SEH2_LEAVE; } }
_SEH2_TRY { RtlCopyMemory(buf, bh->b_data + delta, len); } _SEH2_FINALLY { fini_bh(&bh); } _SEH2_END;
buf = (PUCHAR)buf + len; offset = offset + len; size = size - len; }
rc = TRUE;
} _SEH2_FINALLY {
if (bh) fini_bh(&bh);
} _SEH2_END;
return rc;}
BOOLEANExt2ZeroBuffer( IN PEXT2_IRP_CONTEXT IrpContext, IN PEXT2_VCB Vcb, IN LONGLONG offset, IN ULONG size ){ struct buffer_head *bh = NULL; BOOLEAN rc = 0;
_SEH2_TRY {
while (size) {
sector_t block; ULONG len = 0, delta = 0;
block = (sector_t) (offset >> BLOCK_BITS); delta = (ULONG)offset & (BLOCK_SIZE - 1); len = BLOCK_SIZE - delta; if (size < len) len = size;
if (delta == 0 && len >= BLOCK_SIZE) { bh = sb_getblk_zero(&Vcb->sb, block); } else { bh = sb_getblk(&Vcb->sb, block); }
if (!bh) { DEBUG(DL_ERR, ("Ext2SaveBuffer: can't load block %I64u\n", block)); DbgBreak(); _SEH2_LEAVE; }
if (!buffer_uptodate(bh)) { int err = bh_submit_read(bh); if (err < 0) { DEBUG(DL_ERR, ("Ext2SaveBuffer: bh_submit_read failed: %d\n", err)); _SEH2_LEAVE; } }
_SEH2_TRY { if (delta == 0 && len >= BLOCK_SIZE) { /* bh (cache) was already cleaned as zero */ } else { RtlZeroMemory(bh->b_data + delta, len); } mark_buffer_dirty(bh); } _SEH2_FINALLY { fini_bh(&bh); } _SEH2_END;
offset = offset + len; size = size - len; }
rc = TRUE;
} _SEH2_FINALLY {
if (bh) fini_bh(&bh);
} _SEH2_END;
return rc;}
#ifdef __REACTOS__#define SIZE_256K 0x40000
BOOLEANExt2SaveBuffer( IN PEXT2_IRP_CONTEXT IrpContext, IN PEXT2_VCB Vcb, IN LONGLONG Offset, IN ULONG Size, IN PVOID Buf ){ BOOLEAN rc;
while (Size) {
PBCB Bcb; PVOID Buffer; ULONG Length;
Length = (ULONG)Offset & (SIZE_256K - 1); Length = SIZE_256K - Length; if (Size < Length) Length = Size;
if ( !CcPreparePinWrite( Vcb->Volume, (PLARGE_INTEGER) (&Offset), Length, FALSE, PIN_WAIT | PIN_EXCLUSIVE, &Bcb, &Buffer )) {
DEBUG(DL_ERR, ( "Ext2SaveBuffer: failed to PinLock offset %I64xh ...\n", Offset)); return FALSE; }
_SEH2_TRY {
RtlCopyMemory(Buffer, Buf, Length); CcSetDirtyPinnedData(Bcb, NULL ); SetFlag(Vcb->Volume->Flags, FO_FILE_MODIFIED);
rc = Ext2AddVcbExtent(Vcb, Offset, (LONGLONG)Length); if (!rc) { DbgBreak(); Ext2Sleep(100); rc = Ext2AddVcbExtent(Vcb, Offset, (LONGLONG)Length); }
} _SEH2_FINALLY { CcUnpinData(Bcb); } _SEH2_END;
Buf = (PUCHAR)Buf + Length; Offset = Offset + Length; Size = Size - Length; }
return rc;}#else
BOOLEANExt2SaveBuffer( IN PEXT2_IRP_CONTEXT IrpContext, IN PEXT2_VCB Vcb, IN LONGLONG offset, IN ULONG size, IN PVOID buf ){ struct buffer_head *bh = NULL; BOOLEAN rc = 0;
__try {
while (size) {
sector_t block; ULONG len = 0, delta = 0;
block = (sector_t) (offset >> BLOCK_BITS); delta = (ULONG)offset & (BLOCK_SIZE - 1); len = BLOCK_SIZE - delta; if (size < len) len = size;
if (delta == 0 && len >= BLOCK_SIZE) { bh = sb_getblk_zero(&Vcb->sb, block); } else { bh = sb_getblk(&Vcb->sb, block); }
if (!bh) { DEBUG(DL_ERR, ("Ext2SaveBuffer: can't load block %I64u\n", block)); DbgBreak(); __leave; }
if (!buffer_uptodate(bh)) { int err = bh_submit_read(bh); if (err < 0) { DEBUG(DL_ERR, ("Ext2SaveBuffer: bh_submit_read failed: %d\n", err)); __leave; } }
__try { RtlCopyMemory(bh->b_data + delta, buf, len); mark_buffer_dirty(bh); } __finally { fini_bh(&bh); }
buf = (PUCHAR)buf + len; offset = offset + len; size = size - len; }
rc = TRUE;
} __finally {
if (bh) fini_bh(&bh);
}
return rc;}#endif
VOIDExt2UpdateVcbStat( IN PEXT2_IRP_CONTEXT IrpContext, IN PEXT2_VCB Vcb){ Vcb->SuperBlock->s_free_inodes_count = ext4_count_free_inodes(&Vcb->sb); ext3_free_blocks_count_set(SUPER_BLOCK, ext4_count_free_blocks(&Vcb->sb)); Ext2SaveSuper(IrpContext, Vcb);}
NTSTATUSExt2NewBlock( IN PEXT2_IRP_CONTEXT IrpContext, IN PEXT2_VCB Vcb, IN ULONG GroupHint, IN ULONG BlockHint, OUT PULONG Block, IN OUT PULONG Number){ struct super_block *sb = &Vcb->sb; PEXT2_GROUP_DESC gd; struct buffer_head *gb = NULL; struct buffer_head *bh = NULL; ext4_fsblk_t bitmap_blk;
RTL_BITMAP BlockBitmap;
ULONG Group = 0; ULONG Index = 0xFFFFFFFF; ULONG dwHint = 0; ULONG Count = 0; ULONG Length = 0;
NTSTATUS Status = STATUS_DISK_FULL;
*Block = 0;
ExAcquireResourceExclusiveLite(&Vcb->MetaBlock, TRUE);
/* validate the hint group and hint block */ if (GroupHint >= Vcb->sbi.s_groups_count) { DbgBreak(); GroupHint = Vcb->sbi.s_groups_count - 1; }
if (BlockHint != 0) { GroupHint = (BlockHint - EXT2_FIRST_DATA_BLOCK) / BLOCKS_PER_GROUP; dwHint = (BlockHint - EXT2_FIRST_DATA_BLOCK) % BLOCKS_PER_GROUP; }
Group = GroupHint;
Again:
if (bh) fini_bh(&bh);
if (gb) fini_bh(&gb);
gd = ext4_get_group_desc(sb, Group, &gb); if (!gd) { DbgBreak(); Status = STATUS_INSUFFICIENT_RESOURCES; goto errorout; }
bitmap_blk = ext4_block_bitmap(sb, gd);
if (gd->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) { bh = sb_getblk_zero(sb, bitmap_blk); if (!bh) { DbgBreak(); Status = STATUS_INSUFFICIENT_RESOURCES; goto errorout; } gd->bg_checksum = ext4_group_desc_csum(EXT3_SB(sb), Group, gd); ext4_init_block_bitmap(sb, bh, Group, gd); set_buffer_uptodate(bh); gd->bg_flags &= cpu_to_le16(~EXT4_BG_BLOCK_UNINIT); Ext2SaveGroup(IrpContext, Vcb, Group); } else { bh = sb_getblk(sb, bitmap_blk); if (!bh) { DbgBreak(); Status = STATUS_INSUFFICIENT_RESOURCES; goto errorout; } }
if (!buffer_uptodate(bh)) { int err = bh_submit_read(bh); if (err < 0) { DbgPrint("bh_submit_read error! err: %d\n", err); Status = Ext2WinntError(err); goto errorout; } }
if (ext4_free_blks_count(sb, gd)) {
if (Group == Vcb->sbi.s_groups_count - 1) {
Length = (ULONG)(TOTAL_BLOCKS % BLOCKS_PER_GROUP);
/* s_blocks_count is integer multiple of s_blocks_per_group */ if (Length == 0) { Length = BLOCKS_PER_GROUP; } } else { Length = BLOCKS_PER_GROUP; }
/* initialize bitmap buffer */ RtlInitializeBitMap(&BlockBitmap, (PULONG)bh->b_data, Length);
/* try to find a clear bit range */ Index = RtlFindClearBits(&BlockBitmap, *Number, dwHint);
/* We could not get new block in the prefered group */ if (Index == 0xFFFFFFFF) {
/* search clear bits from the hint block */ Count = RtlFindNextForwardRunClear(&BlockBitmap, dwHint, &Index); if (dwHint != 0 && Count == 0) { /* search clear bits from the very beginning */ Count = RtlFindNextForwardRunClear(&BlockBitmap, 0, &Index); }
if (Count == 0) {
RtlZeroMemory(&BlockBitmap, sizeof(RTL_BITMAP));
/* no blocks found: set bg_free_blocks_count to 0 */ ext4_free_blks_set(sb, gd, 0); Ext2SaveGroup(IrpContext, Vcb, Group);
/* will try next group */ goto Again;
} else {
/* we got free blocks */ if (Count <= *Number) { *Number = Count; } } }
} else {
/* try next group */ dwHint = 0; Group = (Group + 1) % Vcb->sbi.s_groups_count; if (Group != GroupHint) { goto Again; }
Index = 0xFFFFFFFF; }
if (Index < Length) {
/* mark block bits as allocated */ RtlSetBits(&BlockBitmap, Index, *Number);
/* set block bitmap dirty in cache */ mark_buffer_dirty(bh);
/* update group description */ ext4_free_blks_set(sb, gd, RtlNumberOfClearBits(&BlockBitmap)); Ext2SaveGroup(IrpContext, Vcb, Group);
/* update Vcb free blocks */ Ext2UpdateVcbStat(IrpContext, Vcb);
/* validate the new allocated block number */ *Block = Index + EXT2_FIRST_DATA_BLOCK + Group * BLOCKS_PER_GROUP; if (*Block >= TOTAL_BLOCKS || *Block + *Number > TOTAL_BLOCKS) { DbgBreak(); dwHint = 0; goto Again; }
if (ext4_block_bitmap(sb, gd) == *Block || ext4_inode_bitmap(sb, gd) == *Block || ext4_inode_table(sb, gd) == *Block ) { DbgBreak(); dwHint = 0; goto Again; }
/* Always remove dirty MCB to prevent Volume's lazy writing. Metadata blocks will be re-added during modifications.*/ if (Ext2RemoveBlockExtent(Vcb, NULL, *Block, *Number)) { } else { DbgBreak(); Ext2RemoveBlockExtent(Vcb, NULL, *Block, *Number); }
DEBUG(DL_INF, ("Ext2NewBlock: Block %xh - %x allocated.\n", *Block, *Block + *Number)); Status = STATUS_SUCCESS; }
errorout:
ExReleaseResourceLite(&Vcb->MetaBlock);
if (bh) fini_bh(&bh);
if (gb) fini_bh(&gb);
return Status;}
NTSTATUSExt2FreeBlock( IN PEXT2_IRP_CONTEXT IrpContext, IN PEXT2_VCB Vcb, IN ULONG Block, IN ULONG Number){ struct super_block *sb = &Vcb->sb; PEXT2_GROUP_DESC gd; struct buffer_head *gb = NULL; ext4_fsblk_t bitmap_blk;
RTL_BITMAP BlockBitmap; LARGE_INTEGER Offset;
PBCB BitmapBcb; PVOID BitmapCache;
ULONG Group; ULONG Index; ULONG Length; ULONG Count;
NTSTATUS Status = STATUS_UNSUCCESSFUL;
ExAcquireResourceExclusiveLite(&Vcb->MetaBlock, TRUE);
DEBUG(DL_INF, ("Ext2FreeBlock: Block %xh - %x to be freed.\n", Block, Block + Number));
Group = (Block - EXT2_FIRST_DATA_BLOCK) / BLOCKS_PER_GROUP; Index = (Block - EXT2_FIRST_DATA_BLOCK) % BLOCKS_PER_GROUP;
Again:
if (gb) fini_bh(&gb);
if ( Block < EXT2_FIRST_DATA_BLOCK || Block >= TOTAL_BLOCKS || Group >= Vcb->sbi.s_groups_count) {
DbgBreak(); Status = STATUS_SUCCESS;
} else {
gd = ext4_get_group_desc(sb, Group, &gb); if (!gd) { DbgBreak(); Status = STATUS_INSUFFICIENT_RESOURCES; goto errorout; } bitmap_blk = ext4_block_bitmap(sb, gd);
/* check the block is valid or not */ if (bitmap_blk >= TOTAL_BLOCKS) { DbgBreak(); Status = STATUS_DISK_CORRUPT_ERROR; goto errorout; }
/* get bitmap block offset and length */ Offset.QuadPart = bitmap_blk; Offset.QuadPart = Offset.QuadPart << BLOCK_BITS;
if (Group == Vcb->sbi.s_groups_count - 1) {
Length = (ULONG)(TOTAL_BLOCKS % BLOCKS_PER_GROUP);
/* s_blocks_count is integer multiple of s_blocks_per_group */ if (Length == 0) { Length = BLOCKS_PER_GROUP; }
} else { Length = BLOCKS_PER_GROUP; }
/* read and initialize bitmap */ if (!CcPinRead( Vcb->Volume, &Offset, Vcb->BlockSize, PIN_WAIT, &BitmapBcb, &BitmapCache ) ) {
DEBUG(DL_ERR, ("Ext2FreeBlock: failed to PinLock bitmap block %xh.\n", bitmap_blk)); Status = STATUS_CANT_WAIT; DbgBreak(); goto errorout; }
/* clear usused bits */ RtlInitializeBitMap(&BlockBitmap, BitmapCache, Length); Count = min(Length - Index, Number); RtlClearBits(&BlockBitmap, Index, Count);
/* update group description table */ ext4_free_blks_set(sb, gd, RtlNumberOfClearBits(&BlockBitmap));
/* indict the cache range is dirty */ CcSetDirtyPinnedData(BitmapBcb, NULL ); Ext2AddVcbExtent(Vcb, Offset.QuadPart, (LONGLONG)Vcb->BlockSize); CcUnpinData(BitmapBcb); BitmapBcb = NULL; BitmapCache = NULL; Ext2SaveGroup(IrpContext, Vcb, Group);
/* remove dirty MCB to prevent Volume's lazy writing. */ if (Ext2RemoveBlockExtent(Vcb, NULL, Block, Count)) { } else { DbgBreak(); Ext2RemoveBlockExtent(Vcb, NULL, Block, Count); }
/* save super block (used/unused blocks statics) */ Ext2UpdateVcbStat(IrpContext, Vcb);
/* try next group to clear all remaining */ Number -= Count; if (Number) { Group += 1; if (Group < Vcb->sbi.s_groups_count) { Index = 0; Block += Count; goto Again; } else { DEBUG(DL_ERR, ("Ext2FreeBlock: block number beyonds max group.\n")); goto errorout; } } }
Status = STATUS_SUCCESS;
errorout:
if (gb) fini_bh(&gb);
ExReleaseResourceLite(&Vcb->MetaBlock);
return Status;}
NTSTATUSExt2NewInode( IN PEXT2_IRP_CONTEXT IrpContext, IN PEXT2_VCB Vcb, IN ULONG GroupHint, IN ULONG Type, OUT PULONG Inode){ struct super_block *sb = &Vcb->sb; PEXT2_GROUP_DESC gd; struct buffer_head *gb = NULL; struct buffer_head *bh = NULL; ext4_fsblk_t bitmap_blk;
RTL_BITMAP InodeBitmap;
ULONG Group, i, j; ULONG Average, Length;
ULONG dwInode;
NTSTATUS Status = STATUS_DISK_FULL;
*Inode = dwInode = 0XFFFFFFFF;
ExAcquireResourceExclusiveLite(&Vcb->MetaInode, TRUE);
if (GroupHint >= Vcb->sbi.s_groups_count) GroupHint = GroupHint % Vcb->sbi.s_groups_count;
repeat:
if (bh) fini_bh(&bh);
if (gb) fini_bh(&gb);
Group = i = 0; gd = NULL;
if (Type == EXT2_FT_DIR) {
Average = Vcb->SuperBlock->s_free_inodes_count / Vcb->sbi.s_groups_count;
for (j = 0; j < Vcb->sbi.s_groups_count; j++) {
i = (j + GroupHint) % (Vcb->sbi.s_groups_count); gd = ext4_get_group_desc(sb, i, &gb); if (!gd) { DbgBreak(); Status = STATUS_INSUFFICIENT_RESOURCES; goto errorout; }
if ((gd->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)) || (ext4_used_dirs_count(sb, gd) << 8 < ext4_free_inodes_count(sb, gd)) ) { Group = i + 1; break; } fini_bh(&gb); }
if (!Group) {
PEXT2_GROUP_DESC desc = NULL;
gd = NULL;
/* get the group with the biggest vacancy */ for (j = 0; j < Vcb->sbi.s_groups_count; j++) {
struct buffer_head *gt = NULL; desc = ext4_get_group_desc(sb, j, >); if (!desc) { DbgBreak(); Status = STATUS_INSUFFICIENT_RESOURCES; goto errorout; }
/* return the group if it's not initialized yet */ if (desc->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)) { Group = j + 1; gd = desc;
if (gb) fini_bh(&gb); gb = gt; gt = NULL; break; }
if (!gd) { if (ext4_free_inodes_count(sb, desc) > 0) { Group = j + 1; gd = desc; if (gb) fini_bh(&gb); gb = gt; gt = NULL; } } else { if (ext4_free_inodes_count(sb, desc) > ext4_free_inodes_count(sb, gd)) { Group = j + 1; gd = desc; if (gb) fini_bh(&gb); gb = gt; gt = NULL; break; } } if (gt) fini_bh(>); } }
} else {
/* * Try to place the inode in its parent directory (GroupHint) */
gd = ext4_get_group_desc(sb, GroupHint, &gb); if (!gb) { DbgBreak(); Status = STATUS_INSUFFICIENT_RESOURCES; goto errorout; }
if (gd->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT) || ext4_free_inodes_count(sb, gd)) {
Group = GroupHint + 1;
} else {
/* this group is 100% cocucpied */ fini_bh(&gb);
i = GroupHint;
/* * Use a quadratic hash to find a group with a free inode */
for (j = 1; j < Vcb->sbi.s_groups_count; j <<= 1) {
i = (i + j) % Vcb->sbi.s_groups_count; gd = ext4_get_group_desc(sb, i, &gb); if (!gd) { DbgBreak(); Status = STATUS_INSUFFICIENT_RESOURCES; goto errorout; }
if (gd->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT) || ext4_free_inodes_count(sb, gd)) { Group = i + 1; break; }
fini_bh(&gb); } }
if (!Group) { /* * That failed: try linear search for a free inode */ i = GroupHint; for (j = 2; j < Vcb->sbi.s_groups_count; j++) {
i = (i + 1) % Vcb->sbi.s_groups_count; gd = ext4_get_group_desc(sb, i, &gb); if (!gd) { DbgBreak(); Status = STATUS_INSUFFICIENT_RESOURCES; goto errorout; }
if (gd->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT) || ext4_free_inodes_count(sb, gd)) { Group = i + 1; break; }
fini_bh(&gb); } } }
if (gd == NULL || Group == 0) { goto errorout; }
/* finally we got the group, but is it valid ? */ if (Group > Vcb->sbi.s_groups_count) { DbgBreak(); goto errorout; }
/* valid group number starts from 1, not 0 */ Group -= 1;
ASSERT(gd); bitmap_blk = ext4_inode_bitmap(sb, gd); /* check the block is valid or not */ if (bitmap_blk == 0 || bitmap_blk >= TOTAL_BLOCKS) { DbgBreak(); Status = STATUS_DISK_CORRUPT_ERROR; goto errorout; }
if (gd->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)) { bh = sb_getblk_zero(sb, bitmap_blk); if (!bh) { DbgBreak(); Status = STATUS_INSUFFICIENT_RESOURCES; goto errorout; } gd->bg_checksum = ext4_group_desc_csum(EXT3_SB(sb), Group, gd); ext4_init_inode_bitmap(sb, bh, Group, gd); set_buffer_uptodate(bh); gd->bg_flags &= cpu_to_le16(~EXT4_BG_INODE_UNINIT); Ext2SaveGroup(IrpContext, Vcb, Group); } else { bh = sb_getblk(sb, bitmap_blk); if (!bh) { DbgBreak(); Status = STATUS_INSUFFICIENT_RESOURCES; goto errorout; } }
if (!buffer_uptodate(bh)) { int err = bh_submit_read(bh); if (err < 0) { DbgPrint("bh_submit_read error! err: %d\n", err); Status = Ext2WinntError(err); goto errorout; } }
if (Vcb->sbi.s_groups_count == 1) { Length = INODES_COUNT; } else { if (Group + 1 == Vcb->sbi.s_groups_count) { Length = INODES_COUNT % INODES_PER_GROUP; if (!Length) { /* INODES_COUNT is integer multiple of INODES_PER_GROUP */ Length = INODES_PER_GROUP; } } else { Length = INODES_PER_GROUP; } }
RtlInitializeBitMap(&InodeBitmap, (PULONG)bh->b_data, Length); dwInode = RtlFindClearBits(&InodeBitmap, 1, 0);
if (dwInode == 0xFFFFFFFF || dwInode >= Length) {
RtlZeroMemory(&InodeBitmap, sizeof(RTL_BITMAP)); if (ext4_free_inodes_count(sb, gd) > 0) { ext4_free_inodes_set(sb, gd, 0); Ext2SaveGroup(IrpContext, Vcb, Group); } goto repeat;
} else {
__u32 count = 0;
/* update unused inodes count */ count = ext4_free_inodes_count(sb, gd) - 1; ext4_free_inodes_set(sb, gd, count);
RtlSetBits(&InodeBitmap, dwInode, 1);
/* set block bitmap dirty in cache */ mark_buffer_dirty(bh);
/* If we didn't allocate from within the initialized part of the inode * table then we need to initialize up to this inode. */ if (EXT3_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) {
__u32 free;
if (gd->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)) { gd->bg_flags &= cpu_to_le16(~EXT4_BG_INODE_UNINIT); /* When marking the block group with * ~EXT4_BG_INODE_UNINIT we don't want to depend * on the value of bg_itable_unused even though * mke2fs could have initialized the same for us. * Instead we calculated the value below */
free = 0; } else { free = EXT3_INODES_PER_GROUP(sb) - ext4_itable_unused_count(sb, gd); }
/* * Check the relative inode number against the last used * relative inode number in this group. if it is greater * we need to update the bg_itable_unused count * */ if (dwInode + 1 > free) { ext4_itable_unused_set(sb, gd, (EXT3_INODES_PER_GROUP(sb) - 1 - dwInode)); }
/* We may have to initialize the block bitmap if it isn't already */ if (gd->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) {
struct buffer_head *block_bitmap_bh = NULL;
/* recheck and clear flag under lock if we still need to */ block_bitmap_bh = sb_getblk_zero(sb, ext4_block_bitmap(sb, gd)); if (block_bitmap_bh) { gd->bg_checksum = ext4_group_desc_csum(EXT3_SB(sb), Group, gd); free = ext4_init_block_bitmap(sb, block_bitmap_bh, Group, gd); set_buffer_uptodate(block_bitmap_bh); brelse(block_bitmap_bh); gd->bg_flags &= cpu_to_le16(~EXT4_BG_BLOCK_UNINIT); ext4_free_blks_set(sb, gd, free); Ext2SaveGroup(IrpContext, Vcb, Group); } } }
*Inode = dwInode + 1 + Group * INODES_PER_GROUP;
/* update group_desc / super_block */ if (Type == EXT2_FT_DIR) { ext4_used_dirs_set(sb, gd, ext4_used_dirs_count(sb, gd) + 1); } Ext2SaveGroup(IrpContext, Vcb, Group); Ext2UpdateVcbStat(IrpContext, Vcb); Status = STATUS_SUCCESS; }
errorout:
ExReleaseResourceLite(&Vcb->MetaInode);
if (bh) fini_bh(&bh);
if (gb) fini_bh(&gb);
return Status;}
NTSTATUSExt2UpdateGroupDirStat( IN PEXT2_IRP_CONTEXT IrpContext, IN PEXT2_VCB Vcb, IN ULONG group ){ struct super_block *sb = &Vcb->sb; PEXT2_GROUP_DESC gd; struct buffer_head *gb = NULL; NTSTATUS status;
ExAcquireResourceExclusiveLite(&Vcb->MetaInode, TRUE);
/* get group desc */ gd = ext4_get_group_desc(sb, group, &gb); if (!gd) { status = STATUS_INSUFFICIENT_RESOURCES; goto errorout; }
/* update group_desc and super_block */ ext4_used_dirs_set(sb, gd, ext4_used_dirs_count(sb, gd) - 1); Ext2SaveGroup(IrpContext, Vcb, group); Ext2UpdateVcbStat(IrpContext, Vcb); status = STATUS_SUCCESS;
errorout:
ExReleaseResourceLite(&Vcb->MetaInode);
if (gb) fini_bh(&gb);
return status;}
NTSTATUSExt2FreeInode( IN PEXT2_IRP_CONTEXT IrpContext, IN PEXT2_VCB Vcb, IN ULONG Inode, IN ULONG Type){ struct super_block *sb = &Vcb->sb; PEXT2_GROUP_DESC gd; struct buffer_head *gb = NULL; struct buffer_head *bh = NULL; ext4_fsblk_t bitmap_blk;
RTL_BITMAP InodeBitmap; ULONG Group; ULONG Length; LARGE_INTEGER Offset;
ULONG dwIno; BOOLEAN bModified = FALSE;
NTSTATUS Status = STATUS_UNSUCCESSFUL;
ExAcquireResourceExclusiveLite(&Vcb->MetaInode, TRUE);
Group = (Inode - 1) / INODES_PER_GROUP; dwIno = (Inode - 1) % INODES_PER_GROUP;
DEBUG(DL_INF, ( "Ext2FreeInode: Inode: %xh (Group/Off = %xh/%xh)\n", Inode, Group, dwIno));
if (Group >= Vcb->sbi.s_groups_count) { DbgBreak(); goto errorout; }
gd = ext4_get_group_desc(sb, Group, &gb); if (!gd) { DbgBreak(); Status = STATUS_INSUFFICIENT_RESOURCES; goto errorout; }
bitmap_blk = ext4_inode_bitmap(sb, gd); bh = sb_getblk(sb, bitmap_blk); if (!bh) { DbgBreak(); Status = STATUS_INSUFFICIENT_RESOURCES; goto errorout; } if (!buffer_uptodate(bh)) { int err = bh_submit_read(bh); if (err < 0) { DbgPrint("bh_submit_read error! err: %d\n", err); Status = Ext2WinntError(err); goto errorout; } }
if (Group == Vcb->sbi.s_groups_count - 1) {
Length = INODES_COUNT % INODES_PER_GROUP; if (!Length) { /* s_inodes_count is integer multiple of s_inodes_per_group */ Length = INODES_PER_GROUP; } } else { Length = INODES_PER_GROUP; }
RtlInitializeBitMap(&InodeBitmap, (PULONG)bh->b_data, Length);
if (RtlCheckBit(&InodeBitmap, dwIno) == 0) { DbgBreak(); Status = STATUS_SUCCESS; } else { RtlClearBits(&InodeBitmap, dwIno, 1); bModified = TRUE; }
if (bModified) { /* update group free inodes */ ext4_free_inodes_set(sb, gd, RtlNumberOfClearBits(&InodeBitmap));
/* set inode block dirty and add to vcb dirty range */ mark_buffer_dirty(bh);
/* update group_desc and super_block */ if (Type == EXT2_FT_DIR) { ext4_used_dirs_set(sb, gd, ext4_used_dirs_count(sb, gd) - 1); } Ext2SaveGroup(IrpContext, Vcb, Group); Ext2UpdateVcbStat(IrpContext, Vcb); Status = STATUS_SUCCESS; }
errorout:
ExReleaseResourceLite(&Vcb->MetaInode);
if (bh) fini_bh(&bh);
if (gb) fini_bh(&gb);
return Status;}
NTSTATUSExt2AddEntry ( IN PEXT2_IRP_CONTEXT IrpContext, IN PEXT2_VCB Vcb, IN PEXT2_FCB Dcb, IN struct inode *Inode, IN PUNICODE_STRING FileName, struct dentry **Dentry){ struct dentry *de = NULL;
NTSTATUS status = STATUS_UNSUCCESSFUL; OEM_STRING oem; int rc;
BOOLEAN MainResourceAcquired = FALSE;
if (!IsDirectory(Dcb)) { DbgBreak(); return STATUS_NOT_A_DIRECTORY; }
ExAcquireResourceExclusiveLite(&Dcb->MainResource, TRUE); MainResourceAcquired = TRUE;
_SEH2_TRY {
Ext2ReferXcb(&Dcb->ReferenceCount); de = Ext2BuildEntry(Vcb, Dcb->Mcb, FileName); if (!de) { status = STATUS_INSUFFICIENT_RESOURCES; _SEH2_LEAVE; } de->d_inode = Inode;
rc = ext3_add_entry(IrpContext, de, Inode); status = Ext2WinntError(rc); if (NT_SUCCESS(status)) {
/* increase dir inode's nlink for .. */ if (S_ISDIR(Inode->i_mode)) { ext3_inc_count(Dcb->Inode); ext3_mark_inode_dirty(IrpContext, Dcb->Inode); }
/* increase inode nlink reference */ ext3_inc_count(Inode); ext3_mark_inode_dirty(IrpContext, Inode);
if (Dentry) { *Dentry = de; de = NULL; } }
} _SEH2_FINALLY {
Ext2DerefXcb(&Dcb->ReferenceCount);
if (MainResourceAcquired) { ExReleaseResourceLite(&Dcb->MainResource); }
if (de) Ext2FreeEntry(de); } _SEH2_END;
return status;}
NTSTATUSExt2SetFileType ( IN PEXT2_IRP_CONTEXT IrpContext, IN PEXT2_VCB Vcb, IN PEXT2_FCB Dcb, IN PEXT2_MCB Mcb, IN umode_t mode ){ struct inode *dir = Dcb->Inode; struct buffer_head *bh = NULL; struct ext3_dir_entry_2 *de; struct inode *inode; NTSTATUS Status = STATUS_UNSUCCESSFUL; BOOLEAN MainResourceAcquired = FALSE;
if (!EXT3_HAS_INCOMPAT_FEATURE(dir->i_sb, EXT3_FEATURE_INCOMPAT_FILETYPE)) { return STATUS_SUCCESS; }
if (!IsDirectory(Dcb)) { return STATUS_NOT_A_DIRECTORY; }
ExAcquireResourceExclusiveLite(&Dcb->MainResource, TRUE); MainResourceAcquired = TRUE;
_SEH2_TRY {
Ext2ReferXcb(&Dcb->ReferenceCount);
bh = ext3_find_entry(IrpContext, Mcb->de, &de); if (!bh) _SEH2_LEAVE;
inode = &Mcb->Inode; if (le32_to_cpu(de->inode) != inode->i_ino) _SEH2_LEAVE;
ext3_set_de_type(inode->i_sb, de, mode); mark_buffer_dirty(bh);
if (S_ISDIR(inode->i_mode) == S_ISDIR(mode)) { } else if (S_ISDIR(inode->i_mode)) { ext3_dec_count(dir); } else if (S_ISDIR(mode)) { ext3_inc_count(dir); } dir->i_ctime = dir->i_mtime = ext3_current_time(dir); ext3_mark_inode_dirty(IrpContext, dir);
inode->i_mode = mode; ext3_mark_inode_dirty(IrpContext, inode);
Status = STATUS_SUCCESS;
} _SEH2_FINALLY {
Ext2DerefXcb(&Dcb->ReferenceCount);
if (MainResourceAcquired) ExReleaseResourceLite(&Dcb->MainResource);
if (bh) brelse(bh); } _SEH2_END;
return Status;}
NTSTATUSExt2RemoveEntry ( IN PEXT2_IRP_CONTEXT IrpContext, IN PEXT2_VCB Vcb, IN PEXT2_FCB Dcb, IN PEXT2_MCB Mcb){ struct inode *dir = Dcb->Inode; struct buffer_head *bh = NULL; struct ext3_dir_entry_2 *de; struct inode *inode; int rc = -ENOENT; NTSTATUS Status = STATUS_UNSUCCESSFUL; BOOLEAN MainResourceAcquired = FALSE;
if (!IsDirectory(Dcb)) { return STATUS_NOT_A_DIRECTORY; }
ExAcquireResourceExclusiveLite(&Dcb->MainResource, TRUE); MainResourceAcquired = TRUE;
_SEH2_TRY {
Ext2ReferXcb(&Dcb->ReferenceCount);
bh = ext3_find_entry(IrpContext, Mcb->de, &de); if (!bh) _SEH2_LEAVE;
inode = &Mcb->Inode; if (le32_to_cpu(de->inode) != inode->i_ino) _SEH2_LEAVE;
if (!inode->i_nlink) { ext3_warning (inode->i_sb, "ext3_unlink", "Deleting nonexistent file (%lu), %d", inode->i_ino, inode->i_nlink); inode->i_nlink = 1; } rc = ext3_delete_entry(IrpContext, dir, de, bh); if (rc) { Status = Ext2WinntError(rc); _SEH2_LEAVE; } /* if (!inode->i_nlink) ext3_orphan_add(handle, inode); */ inode->i_ctime = dir->i_ctime = dir->i_mtime = ext3_current_time(dir); ext3_dec_count(inode); ext3_mark_inode_dirty(IrpContext, inode);
/* decrease dir inode's nlink for .. */ if (S_ISDIR(inode->i_mode)) { ext3_update_dx_flag(dir); ext3_dec_count(dir); ext3_mark_inode_dirty(IrpContext, dir); }
Status = STATUS_SUCCESS;
} _SEH2_FINALLY {
Ext2DerefXcb(&Dcb->ReferenceCount);
if (MainResourceAcquired) ExReleaseResourceLite(&Dcb->MainResource);
if (bh) brelse(bh); } _SEH2_END;
return Status;}
NTSTATUSExt2SetParentEntry ( IN PEXT2_IRP_CONTEXT IrpContext, IN PEXT2_VCB Vcb, IN PEXT2_FCB Dcb, IN ULONG OldParent, IN ULONG NewParent ){ NTSTATUS Status = STATUS_UNSUCCESSFUL;
PEXT2_DIR_ENTRY2 pSelf = NULL; PEXT2_DIR_ENTRY2 pParent = NULL;
ULONG dwBytes = 0;
BOOLEAN MainResourceAcquired = FALSE;
ULONG Offset = 0;
if (!IsDirectory(Dcb)) { return STATUS_NOT_A_DIRECTORY; }
if (OldParent == NewParent) { return STATUS_SUCCESS; }
MainResourceAcquired = ExAcquireResourceExclusiveLite(&Dcb->MainResource, TRUE);
_SEH2_TRY {
Ext2ReferXcb(&Dcb->ReferenceCount);
pSelf = (PEXT2_DIR_ENTRY2) Ext2AllocatePool( PagedPool, EXT2_DIR_REC_LEN(1) + EXT2_DIR_REC_LEN(2), EXT2_DENTRY_MAGIC ); if (!pSelf) { DEBUG(DL_ERR, ( "Ex2SetParentEntry: failed to allocate pSelf.\n")); Status = STATUS_INSUFFICIENT_RESOURCES; _SEH2_LEAVE; }
dwBytes = 0;
// // Reading the DCB contents //
Status = Ext2ReadInode( IrpContext, Vcb, Dcb->Mcb, (ULONGLONG)Offset, (PVOID)pSelf, EXT2_DIR_REC_LEN(1) + EXT2_DIR_REC_LEN(2), FALSE, &dwBytes );
if (!NT_SUCCESS(Status)) { DEBUG(DL_ERR, ( "Ext2SetParentEntry: failed to read directory.\n")); _SEH2_LEAVE; }
ASSERT(dwBytes == EXT2_DIR_REC_LEN(1) + EXT2_DIR_REC_LEN(2));
pParent = (PEXT2_DIR_ENTRY2)((PUCHAR)pSelf + pSelf->rec_len);
if (pSelf->name_len == 1 && pSelf->name[0] == '.' && pParent->name_len == 2 && pParent->name[0] == '.' && pParent->name[1] == '.') {
if (pParent->inode != OldParent) { DbgBreak(); } pParent->inode = NewParent;
Status = Ext2WriteInode( IrpContext, Vcb, Dcb->Mcb, (ULONGLONG)Offset, pSelf, dwBytes, FALSE, &dwBytes ); } else { DbgBreak(); }
} _SEH2_FINALLY {
if (Ext2DerefXcb(&Dcb->ReferenceCount) == 0) { DEBUG(DL_ERR, ( "Ext2SetParentEntry: Dcb reference goes to ZERO.\n")); }
if (MainResourceAcquired) { ExReleaseResourceLite(&Dcb->MainResource); }
if (pSelf) { Ext2FreePool(pSelf, EXT2_DENTRY_MAGIC); } } _SEH2_END;
return Status;}
int ext3_check_dir_entry (const char * function, struct inode * dir, struct ext3_dir_entry_2 * de, struct buffer_head * bh, unsigned long offset){ const char * error_msg = NULL; const int rlen = ext3_rec_len_from_disk(de->rec_len);
if (rlen < EXT3_DIR_REC_LEN(1)) error_msg = "rec_len is smaller than minimal"; else if (rlen % 4 != 0) error_msg = "rec_len % 4 != 0"; else if (rlen < EXT3_DIR_REC_LEN(de->name_len)) error_msg = "rec_len is too small for name_len"; else if ((char *) de + rlen > bh->b_data + dir->i_sb->s_blocksize) error_msg = "directory entry across blocks"; else if (le32_to_cpu(de->inode) > le32_to_cpu(EXT3_SB(dir->i_sb)->s_es->s_inodes_count)) error_msg = "inode out of bounds";
if (error_msg != NULL) { DEBUG(DL_ERR, ("%s: bad entry in directory %u: %s - " "offset=%u, inode=%u, rec_len=%d, name_len=%d\n", function, dir->i_ino, error_msg, offset, (unsigned long) le32_to_cpu(de->inode), rlen, de->name_len)); } return error_msg == NULL ? 1 : 0;}
/* * p is at least 6 bytes before the end of page */struct ext3_dir_entry_2 * ext3_next_entry(struct ext3_dir_entry_2 *p){ return (struct ext3_dir_entry_2 *)((char *)p + ext3_rec_len_from_disk(p->rec_len));}
#define MAX_LFS_FILESIZE 0x7fffffffffffffff
/* * Maximal extent format file size. * Resulting logical blkno at s_maxbytes must fit in our on-disk * extent format containers, within a sector_t, and within i_blocks * in the vfs. ext4 inode has 48 bits of i_block in fsblock units, * so that won't be a limiting factor. * * Note, this does *not* consider any metadata overhead for vfs i_blocks. */static loff_t ext4_max_size(int blkbits, int has_huge_files){ loff_t res; loff_t upper_limit = MAX_LFS_FILESIZE;
/* small i_blocks in vfs inode? */ if (!has_huge_files || sizeof(blkcnt_t) < sizeof(u64)) { /* * CONFIG_LBD is not enabled implies the inode * i_block represent total blocks in 512 bytes * 32 == size of vfs inode i_blocks * 8 */ upper_limit = (1LL << 32) - 1;
/* total blocks in file system block size */ upper_limit >>= (blkbits - 9); upper_limit <<= blkbits; }
/* 32-bit extent-start container, ee_block */ res = 1LL << 32; res <<= blkbits; res -= 1;
/* Sanity check against vm- & vfs- imposed limits */ if (res > upper_limit) res = upper_limit;
return res;}
/* * Maximal extent format file size. * Resulting logical blkno at s_maxbytes must fit in our on-disk * extent format containers, within a sector_t, and within i_blocks * in the vfs. ext4 inode has 48 bits of i_block in fsblock units, * so that won't be a limiting factor. * * Note, this does *not* consider any metadata overhead for vfs i_blocks. */loff_t ext3_max_size(int blkbits, int has_huge_files){ loff_t res; loff_t upper_limit = MAX_LFS_FILESIZE;
/* small i_blocks in vfs inode? */ if (!has_huge_files) { /* * CONFIG_LBD is not enabled implies the inode * i_block represent total blocks in 512 bytes * 32 == size of vfs inode i_blocks * 8 */ upper_limit = ((loff_t)1 << 32) - 1;
/* total blocks in file system block size */ upper_limit >>= (blkbits - 9); upper_limit <<= blkbits; }
/* 32-bit extent-start container, ee_block */ res = (loff_t)1 << 32; res <<= blkbits; res -= 1;
/* Sanity check against vm- & vfs- imposed limits */ if (res > upper_limit) res = upper_limit;
return res;}
/* * Maximal bitmap file size. There is a direct, and {,double-,triple-}indirect * block limit, and also a limit of (2^48 - 1) 512-byte sectors in i_blocks. * We need to be 1 filesystem block less than the 2^48 sector limit. */loff_t ext3_max_bitmap_size(int bits, int has_huge_files){ loff_t res = EXT3_NDIR_BLOCKS; int meta_blocks; loff_t upper_limit; /* This is calculated to be the largest file size for a * dense, bitmapped file such that the total number of * sectors in the file, including data and all indirect blocks, * does not exceed 2^48 -1 * __u32 i_blocks_lo and _u16 i_blocks_high representing the * total number of 512 bytes blocks of the file */
if (!has_huge_files) { /* * !has_huge_files or CONFIG_LBD is not enabled * implies the inode i_block represent total blocks in * 512 bytes 32 == size of vfs inode i_blocks * 8 */ upper_limit = ((loff_t)1 << 32) - 1;
/* total blocks in file system block size */ upper_limit >>= (bits - 9);
} else { /* * We use 48 bit ext4_inode i_blocks * With EXT4_HUGE_FILE_FL set the i_blocks * represent total number of blocks in * file system block size */ upper_limit = ((loff_t)1 << 48) - 1;
}
/* indirect blocks */ meta_blocks = 1; /* double indirect blocks */ meta_blocks += 1 + ((loff_t)1 << (bits-2)); /* tripple indirect blocks */ meta_blocks += 1 + ((loff_t)1 << (bits-2)) + ((loff_t)1 << (2*(bits-2)));
upper_limit -= meta_blocks; upper_limit <<= bits;
res += (loff_t)1 << (bits-2); res += (loff_t)1 << (2*(bits-2)); res += (loff_t)1 << (3*(bits-2)); res <<= bits; if (res > upper_limit) res = upper_limit;
if (res > MAX_LFS_FILESIZE) res = MAX_LFS_FILESIZE;
return res;}
blkcnt_t ext3_inode_blocks(struct ext3_inode *raw_inode, struct inode *inode){ blkcnt_t i_blocks ; struct super_block *sb = inode->i_sb; PEXT2_VCB Vcb = (PEXT2_VCB)sb->s_priv;
if (EXT3_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_HUGE_FILE)) { /* we are using combined 48 bit field */ i_blocks = ((u64)le16_to_cpu(raw_inode->i_blocks_high)) << 32 | le32_to_cpu(raw_inode->i_blocks); if (inode->i_flags & EXT4_HUGE_FILE_FL) { /* i_blocks represent file system block size */ return i_blocks << (BLOCK_BITS - 9); } else { return i_blocks; } } else { return le32_to_cpu(raw_inode->i_blocks); }}
int ext3_inode_blocks_set(struct ext3_inode *raw_inode, struct inode * inode){ u64 i_blocks = inode->i_blocks; struct super_block *sb = inode->i_sb; PEXT2_VCB Vcb = (PEXT2_VCB)sb->s_priv;
if (i_blocks < 0x100000000) { /* * i_blocks can be represnted in a 32 bit variable * as multiple of 512 bytes */ raw_inode->i_blocks = cpu_to_le32(i_blocks); raw_inode->i_blocks_high = 0; inode->i_flags &= ~EXT4_HUGE_FILE_FL; return 0; }
if (!EXT3_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_HUGE_FILE)) { EXT3_SET_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_HUGE_FILE); Ext2SaveSuper(NULL, Vcb); }
if (i_blocks <= 0xffffffffffff) { /* * i_blocks can be represented in a 48 bit variable * as multiple of 512 bytes */ raw_inode->i_blocks = (__u32)cpu_to_le32(i_blocks); raw_inode->i_blocks_high = (__u16)cpu_to_le16(i_blocks >> 32); inode->i_flags &= ~EXT4_HUGE_FILE_FL; } else { inode->i_flags |= EXT4_HUGE_FILE_FL; /* i_block is stored in file system block size */ i_blocks = i_blocks >> (BLOCK_BITS - 9); raw_inode->i_blocks = (__u32)cpu_to_le32(i_blocks); raw_inode->i_blocks_high = (__u16)cpu_to_le16(i_blocks >> 32); } return 0;}
ext4_fsblk_t ext4_block_bitmap(struct super_block *sb, struct ext4_group_desc *bg){ return le32_to_cpu(bg->bg_block_bitmap) | (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ? (ext4_fsblk_t)le32_to_cpu(bg->bg_block_bitmap_hi) << 32 : 0);}
ext4_fsblk_t ext4_inode_bitmap(struct super_block *sb, struct ext4_group_desc *bg){ return le32_to_cpu(bg->bg_inode_bitmap) | (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ? (ext4_fsblk_t)le32_to_cpu(bg->bg_inode_bitmap_hi) << 32 : 0);}
ext4_fsblk_t ext4_inode_table(struct super_block *sb, struct ext4_group_desc *bg){ return le32_to_cpu(bg->bg_inode_table) | (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ? (ext4_fsblk_t)le32_to_cpu(bg->bg_inode_table_hi) << 32 : 0);}
__u32 ext4_free_blks_count(struct super_block *sb, struct ext4_group_desc *bg){ return le16_to_cpu(bg->bg_free_blocks_count) | (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ? (__u32)le16_to_cpu(bg->bg_free_blocks_count_hi) << 16 : 0);}
__u32 ext4_free_inodes_count(struct super_block *sb, struct ext4_group_desc *bg){ return le16_to_cpu(bg->bg_free_inodes_count) | (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ? (__u32)le16_to_cpu(bg->bg_free_inodes_count_hi) << 16 : 0);}
__u32 ext4_used_dirs_count(struct super_block *sb, struct ext4_group_desc *bg){ return le16_to_cpu(bg->bg_used_dirs_count) | (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ? (__u32)le16_to_cpu(bg->bg_used_dirs_count_hi) << 16 : 0);}
__u32 ext4_itable_unused_count(struct super_block *sb, struct ext4_group_desc *bg){ return le16_to_cpu(bg->bg_itable_unused) | (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ? (__u32)le16_to_cpu(bg->bg_itable_unused_hi) << 16 : 0);}
void ext4_block_bitmap_set(struct super_block *sb, struct ext4_group_desc *bg, ext4_fsblk_t blk){ bg->bg_block_bitmap = cpu_to_le32((u32)blk); if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT) bg->bg_block_bitmap_hi = cpu_to_le32(blk >> 32);}
void ext4_inode_bitmap_set(struct super_block *sb, struct ext4_group_desc *bg, ext4_fsblk_t blk){ bg->bg_inode_bitmap = cpu_to_le32((u32)blk); if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT) bg->bg_inode_bitmap_hi = cpu_to_le32(blk >> 32);}
void ext4_inode_table_set(struct super_block *sb, struct ext4_group_desc *bg, ext4_fsblk_t blk){ bg->bg_inode_table = cpu_to_le32((u32)blk); if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT) bg->bg_inode_table_hi = cpu_to_le32(blk >> 32);}
void ext4_free_blks_set(struct super_block *sb, struct ext4_group_desc *bg, __u32 count){ bg->bg_free_blocks_count = cpu_to_le16((__u16)count); if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT) bg->bg_free_blocks_count_hi = cpu_to_le16(count >> 16);}
void ext4_free_inodes_set(struct super_block *sb, struct ext4_group_desc *bg, __u32 count){ bg->bg_free_inodes_count = cpu_to_le16((__u16)count); if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT) bg->bg_free_inodes_count_hi = cpu_to_le16(count >> 16);}
void ext4_used_dirs_set(struct super_block *sb, struct ext4_group_desc *bg, __u32 count){ bg->bg_used_dirs_count = cpu_to_le16((__u16)count); if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT) bg->bg_used_dirs_count_hi = cpu_to_le16(count >> 16);}
void ext4_itable_unused_set(struct super_block *sb, struct ext4_group_desc *bg, __u32 count){ bg->bg_itable_unused = cpu_to_le16((__u16)count); if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT) bg->bg_itable_unused_hi = cpu_to_le16(count >> 16);}
/** CRC table for the CRC-16. The poly is 0x8005 (x16 + x15 + x2 + 1) */__u16 const crc16_table[256] = { 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241, 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440, 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40, 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841, 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40, 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41, 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641, 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040, 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240, 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441, 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41, 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840, 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41, 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40, 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640, 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041, 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240, 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441, 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41, 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840, 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41, 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40, 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640, 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041, 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241, 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440, 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40, 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841, 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40, 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41, 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641, 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040};
static inline __u16 crc16_byte(__u16 crc, const __u8 data){ return (crc >> 8) ^ crc16_table[(crc ^ data) & 0xff];}
__u16 crc16(__u16 crc, __u8 const *buffer, size_t len){ while (len--) crc = crc16_byte(crc, *buffer++); return crc;}
__le16 ext4_group_desc_csum(struct ext3_sb_info *sbi, __u32 block_group, struct ext4_group_desc *gdp){ int offset; __u16 crc = 0; __le32 le_group = cpu_to_le32(block_group);
/* old crc16 code */ if (!(sbi->s_es->s_feature_ro_compat & cpu_to_le32(EXT4_FEATURE_RO_COMPAT_GDT_CSUM))) return 0;
offset = offsetof(struct ext4_group_desc, bg_checksum);
crc = crc16(~0, sbi->s_es->s_uuid, sizeof(sbi->s_es->s_uuid)); crc = crc16(crc, (__u8 *)&le_group, sizeof(le_group)); crc = crc16(crc, (__u8 *)gdp, offset); offset += sizeof(gdp->bg_checksum); /* skip checksum */ /* for checksum of struct ext4_group_desc do the rest...*/ if ((sbi->s_es->s_feature_incompat & cpu_to_le32(EXT4_FEATURE_INCOMPAT_64BIT)) && offset < le16_to_cpu(sbi->s_es->s_desc_size)) crc = crc16(crc, (__u8 *)gdp + offset, le16_to_cpu(sbi->s_es->s_desc_size) - offset);
return cpu_to_le16(crc);}
int ext4_group_desc_csum_verify(struct ext3_sb_info *sbi, __u32 block_group, struct ext4_group_desc *gdp){ if ((sbi->s_es->s_feature_ro_compat & cpu_to_le32(EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) && (gdp->bg_checksum != ext4_group_desc_csum(sbi, block_group, gdp))) return 0;
return 1;}
static inline int test_root(ext3_group_t a, ext3_group_t b){ ext3_group_t num = b;
while (a > num) num *= b; return num == a;}
static int ext3_group_sparse(ext3_group_t group){ if (group <= 1) return 1; if (!(group & 1)) return 0; return (test_root(group, 7) || test_root(group, 5) || test_root(group, 3));}
/** * ext4_bg_has_super - number of blocks used by the superblock in group * @sb: superblock for filesystem * @group: group number to check * * Return the number of blocks used by the superblock (primary or backup) * in this group. Currently this will be only 0 or 1. */int ext3_bg_has_super(struct super_block *sb, ext3_group_t group){ if (EXT3_HAS_RO_COMPAT_FEATURE(sb, EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER) && !ext3_group_sparse(group)) return 0; return 1;}
static unsigned long ext4_bg_num_gdb_meta(struct super_block *sb, ext4_group_t group){ unsigned long metagroup = group / EXT4_DESC_PER_BLOCK(sb); ext4_group_t first = metagroup * EXT4_DESC_PER_BLOCK(sb); ext4_group_t last = first + EXT4_DESC_PER_BLOCK(sb) - 1;
if (group == first || group == first + 1 || group == last) return 1; return 0;}
static unsigned long ext4_bg_num_gdb_nometa(struct super_block *sb, ext4_group_t group){ return ext3_bg_has_super(sb, group) ? EXT3_SB(sb)->s_gdb_count : 0;}
/** * ext4_bg_num_gdb - number of blocks used by the group table in group * @sb: superblock for filesystem * @group: group number to check * * Return the number of blocks used by the group descriptor table * (primary or backup) in this group. In the future there may be a * different number of descriptor blocks in each group. */unsigned long ext4_bg_num_gdb(struct super_block *sb, ext4_group_t group){ unsigned long first_meta_bg = le32_to_cpu(EXT3_SB(sb)->s_es->s_first_meta_bg); unsigned long metagroup = group / EXT4_DESC_PER_BLOCK(sb);
if (!EXT3_HAS_INCOMPAT_FEATURE(sb,EXT4_FEATURE_INCOMPAT_META_BG) || metagroup < first_meta_bg) return ext4_bg_num_gdb_nometa(sb, group);
return ext4_bg_num_gdb_meta(sb,group);
}
ext3_fsblk_t descriptor_loc(struct super_block *sb, ext3_fsblk_t logical_sb_block, unsigned int nr){ struct ext3_sb_info *sbi = EXT3_SB(sb); ext3_group_t bg, first_meta_bg; int has_super = 0;
first_meta_bg = le32_to_cpu(sbi->s_es->s_first_meta_bg);
if (!EXT3_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_META_BG) || nr < first_meta_bg) return logical_sb_block + nr + 1; bg = sbi->s_desc_per_block * nr; if (ext3_bg_has_super(sb, bg)) has_super = 1; return (has_super + ext3_group_first_block_no(sb, bg));}
#define ext4_set_bit(n, p) set_bit((int)(n), (unsigned long *)(p))
/* * The free inodes are managed by bitmaps. A file system contains several * blocks groups. Each group contains 1 bitmap block for blocks, 1 bitmap * block for inodes, N blocks for the inode table and data blocks. * * The file system contains group descriptors which are located after the * super block. Each descriptor contains the number of the bitmap block and * the free blocks count in the block. */
/* * To avoid calling the atomic setbit hundreds or thousands of times, we only * need to use it within a single byte (to ensure we get endianness right). * We can use memset for the rest of the bitmap as there are no other users. */void mark_bitmap_end(int start_bit, int end_bit, char *bitmap){ int i;
if (start_bit >= end_bit) return;
DEBUG(DL_INF, ("mark end bits +%d through +%d used\n", start_bit, end_bit)); for (i = start_bit; (unsigned)i < ((start_bit + 7) & ~7UL); i++) ext4_set_bit(i, bitmap); if (i < end_bit) memset(bitmap + (i >> 3), 0xff, (end_bit - i) >> 3);}
/* Initializes an uninitialized inode bitmap */unsigned ext4_init_inode_bitmap(struct super_block *sb, struct buffer_head *bh, ext4_group_t block_group, struct ext4_group_desc *gdp){ struct ext3_sb_info *sbi = EXT3_SB(sb);
mark_buffer_dirty(bh);
/* If checksum is bad mark all blocks and inodes use to prevent * allocation, essentially implementing a per-group read-only flag. */ if (!ext4_group_desc_csum_verify(sbi, block_group, gdp)) { ext4_error(sb, __FUNCTION__, "Checksum bad for group %u", block_group); ext4_free_blks_set(sb, gdp, 0); ext4_free_inodes_set(sb, gdp, 0); ext4_itable_unused_set(sb, gdp, 0); memset(bh->b_data, 0xff, sb->s_blocksize); return 0; }
memset(bh->b_data, 0, (EXT4_INODES_PER_GROUP(sb) + 7) / 8); mark_bitmap_end(EXT4_INODES_PER_GROUP(sb), sb->s_blocksize * 8, bh->b_data); ext4_itable_unused_set(sb, gdp, EXT4_INODES_PER_GROUP(sb));
return EXT4_INODES_PER_GROUP(sb);}
/* * Calculate the block group number and offset, given a block number */void ext4_get_group_no_and_offset(struct super_block *sb, ext4_fsblk_t blocknr, ext4_group_t *blockgrpp, ext4_grpblk_t *offsetp){ struct ext3_super_block *es = EXT3_SB(sb)->s_es; ext4_grpblk_t offset;
blocknr = blocknr - le32_to_cpu(es->s_first_data_block); offset = do_div(blocknr, EXT4_BLOCKS_PER_GROUP(sb)); if (offsetp) *offsetp = offset; if (blockgrpp) *blockgrpp = (ext4_grpblk_t)blocknr;
}
static int ext4_block_in_group(struct super_block *sb, ext4_fsblk_t block, ext4_group_t block_group){ ext4_group_t actual_group; ext4_get_group_no_and_offset(sb, block, &actual_group, NULL); if (actual_group == block_group) return 1; return 0;}
static int ext4_group_used_meta_blocks(struct super_block *sb, ext4_group_t block_group){ ext4_fsblk_t tmp; struct ext3_sb_info *sbi = EXT3_SB(sb); /* block bitmap, inode bitmap, and inode table blocks */ int used_blocks = sbi->s_itb_per_group + 2;
if (EXT3_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FLEX_BG)) { struct ext4_group_desc *gdp; struct buffer_head *bh = NULL;
gdp = ext4_get_group_desc(sb, block_group, &bh); if (!ext4_block_in_group(sb, ext4_block_bitmap(sb, gdp), block_group)) used_blocks--;
if (!ext4_block_in_group(sb, ext4_inode_bitmap(sb, gdp), block_group)) used_blocks--;
tmp = ext4_inode_table(sb, gdp); for (; tmp < ext4_inode_table(sb, gdp) + sbi->s_itb_per_group; tmp++) { if (!ext4_block_in_group(sb, tmp, block_group)) used_blocks -= 1; } if (bh) fini_bh(&bh); } return used_blocks;}
/* Initializes an uninitialized block bitmap if given, and returns the * number of blocks free in the group. */unsigned ext4_init_block_bitmap(struct super_block *sb, struct buffer_head *bh, ext4_group_t block_group, struct ext4_group_desc *gdp){ int bit, bit_max; unsigned free_blocks, group_blocks; struct ext3_sb_info *sbi = EXT3_SB(sb);
if (bh) { mark_buffer_dirty(bh); /* If checksum is bad mark all blocks used to prevent allocation * essentially implementing a per-group read-only flag. */ if (!ext4_group_desc_csum_verify(sbi, block_group, gdp)) { ext4_error(sb, __FUNCTION__, "Checksum bad for group %u", block_group); ext4_free_blks_set(sb, gdp, 0); ext4_free_inodes_set(sb, gdp, 0); ext4_itable_unused_set(sb, gdp, 0); memset(bh->b_data, 0xff, sb->s_blocksize); return 0; } memset(bh->b_data, 0, sb->s_blocksize); }
/* Check for superblock and gdt backups in this group */ bit_max = ext3_bg_has_super(sb, block_group);
if (!EXT3_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_META_BG) || block_group < le32_to_cpu(sbi->s_es->s_first_meta_bg) * sbi->s_desc_per_block) { if (bit_max) { bit_max += ext4_bg_num_gdb(sb, block_group); bit_max += le16_to_cpu(sbi->s_es->s_reserved_gdt_blocks); } } else { /* For META_BG_BLOCK_GROUPS */ bit_max += ext4_bg_num_gdb(sb, block_group); }
if (block_group == sbi->s_groups_count - 1) { /* * Even though mke2fs always initialize first and last group * if some other tool enabled the EXT4_BG_BLOCK_UNINIT we need * to make sure we calculate the right free blocks */ group_blocks = (unsigned int)(ext3_blocks_count(sbi->s_es) - le32_to_cpu(sbi->s_es->s_first_data_block) - (EXT4_BLOCKS_PER_GROUP(sb) * (sbi->s_groups_count - 1))); } else { group_blocks = EXT4_BLOCKS_PER_GROUP(sb); }
free_blocks = group_blocks - bit_max;
if (bh) { ext4_fsblk_t start, tmp; int flex_bg = 0;
for (bit = 0; bit < bit_max; bit++) ext4_set_bit(bit, bh->b_data);
start = ext3_group_first_block_no(sb, block_group);
if (EXT3_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FLEX_BG)) flex_bg = 1;
/* Set bits for block and inode bitmaps, and inode table */ tmp = ext4_block_bitmap(sb, gdp); if (!flex_bg || ext4_block_in_group(sb, tmp, block_group)) ext4_set_bit(tmp - start, bh->b_data);
tmp = ext4_inode_bitmap(sb, gdp); if (!flex_bg || ext4_block_in_group(sb, tmp, block_group)) ext4_set_bit(tmp - start, bh->b_data);
tmp = ext4_inode_table(sb, gdp); for (; tmp < ext4_inode_table(sb, gdp) + sbi->s_itb_per_group; tmp++) { if (!flex_bg || ext4_block_in_group(sb, tmp, block_group)) ext4_set_bit(tmp - start, bh->b_data); } /* * Also if the number of blocks within the group is * less than the blocksize * 8 ( which is the size * of bitmap ), set rest of the block bitmap to 1 */ mark_bitmap_end(group_blocks, sb->s_blocksize * 8, bh->b_data); } return free_blocks - ext4_group_used_meta_blocks(sb, block_group);}
/** * ext4_get_group_desc() -- load group descriptor from disk * @sb: super block * @block_group: given block group * @bh: pointer to the buffer head to store the block * group descriptor */struct ext4_group_desc * ext4_get_group_desc(struct super_block *sb, ext4_group_t block_group, struct buffer_head **bh){ struct ext4_group_desc *desc = NULL; struct ext3_sb_info *sbi = EXT3_SB(sb); PEXT2_VCB vcb = sb->s_priv; ext4_group_t group; ext4_group_t offset;
if (bh) *bh = NULL;
if (block_group >= sbi->s_groups_count) { ext4_error(sb, "ext4_get_group_desc", "block_group >= groups_count - " "block_group = %u, groups_count = %u", block_group, sbi->s_groups_count);
return NULL; }
_SEH2_TRY {
group = block_group >> EXT4_DESC_PER_BLOCK_BITS(sb); offset = block_group & (EXT4_DESC_PER_BLOCK(sb) - 1);
if (!sbi->s_gd) { if (!Ext2LoadGroup(vcb)) { _SEH2_LEAVE; } } else if ( !sbi->s_gd[group].block || !sbi->s_gd[group].bh) { if (!Ext2LoadGroupBH(vcb)) { _SEH2_LEAVE; } }
desc = (struct ext4_group_desc *)((PCHAR)sbi->s_gd[group].gd + offset * EXT4_DESC_SIZE(sb)); if (bh) { atomic_inc(&sbi->s_gd[group].bh->b_count); *bh = sbi->s_gd[group].bh; } } _SEH2_FINALLY { /* do cleanup */ } _SEH2_END;
return desc;}
/** * ext4_count_free_blocks() -- count filesystem free blocks * @sb: superblock * * Adds up the number of free blocks from each block group. */ext4_fsblk_t ext4_count_free_blocks(struct super_block *sb){ ext4_fsblk_t desc_count; struct ext4_group_desc *gdp; struct buffer_head *bh = NULL; ext4_group_t i; ext4_group_t ngroups = EXT3_SB(sb)->s_groups_count;
desc_count = 0; smp_rmb(); for (i = 0; i < ngroups; i++) { gdp = ext4_get_group_desc(sb, i, &bh); if (!bh) continue; desc_count += ext4_free_blks_count(sb, gdp); fini_bh(&bh); }
return desc_count;}
unsigned long ext4_count_free_inodes(struct super_block *sb){ unsigned long desc_count; struct ext4_group_desc *gdp; struct buffer_head *bh = NULL; ext4_group_t i;
desc_count = 0; for (i = 0; i < EXT3_SB(sb)->s_groups_count; i++) { gdp = ext4_get_group_desc(sb, i, &bh); if (!bh) continue; desc_count += ext4_free_inodes_count(sb, gdp); fini_bh(&bh); } return desc_count;}
/* Called at mount-time, super-block is locked */unsigned long ext4_count_dirs(struct super_block * sb){ struct ext4_group_desc *gdp; struct buffer_head *bh = NULL; unsigned long count = 0; ext4_group_t i;
for (i = 0; i < EXT3_SB(sb)->s_groups_count; i++) { gdp = ext4_get_group_desc(sb, i, &bh); if (!bh) continue; count += ext4_used_dirs_count(sb, gdp); fini_bh(&bh); } return count;}
/* Called at mount-time, super-block is locked */int ext4_check_descriptors(struct super_block *sb){ PEXT2_VCB Vcb = sb->s_priv; struct ext3_sb_info *sbi = EXT3_SB(sb); ext4_fsblk_t first_block = le32_to_cpu(sbi->s_es->s_first_data_block); ext4_fsblk_t last_block; ext4_fsblk_t block_bitmap; ext4_fsblk_t inode_bitmap; ext4_fsblk_t inode_table; int flexbg_flag = 0; ext4_group_t i;
if (EXT3_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FLEX_BG)) flexbg_flag = 1;
DEBUG(DL_INF, ("Checking group descriptors"));
for (i = 0; i < sbi->s_groups_count; i++) {
struct buffer_head *bh = NULL; struct ext4_group_desc *gdp = ext4_get_group_desc(sb, i, &bh);
if (!bh) continue;
if (i == sbi->s_groups_count - 1 || flexbg_flag) last_block = ext3_blocks_count(sbi->s_es) - 1; else last_block = first_block + (EXT3_BLOCKS_PER_GROUP(sb) - 1);
block_bitmap = ext4_block_bitmap(sb, gdp); if (block_bitmap < first_block || block_bitmap > last_block) { printk(KERN_ERR "EXT4-fs: ext4_check_descriptors: " "Block bitmap for group %u not in group " "(block %llu)!\n", i, block_bitmap); __brelse(bh); return 0; } inode_bitmap = ext4_inode_bitmap(sb, gdp); if (inode_bitmap < first_block || inode_bitmap > last_block) { printk(KERN_ERR "EXT4-fs: ext4_check_descriptors: " "Inode bitmap for group %u not in group " "(block %llu)!\n", i, inode_bitmap); __brelse(bh); return 0; } inode_table = ext4_inode_table(sb, gdp); if (inode_table < first_block || inode_table + sbi->s_itb_per_group - 1 > last_block) { printk(KERN_ERR "EXT4-fs: ext4_check_descriptors: " "Inode table for group %u not in group " "(block %llu)!\n", i, inode_table); __brelse(bh); return 0; }
if (!ext4_group_desc_csum_verify(sbi, i, gdp)) { printk(KERN_ERR "EXT4-fs: ext4_check_descriptors: " "Checksum for group %u failed (%u!=%u)\n", i, le16_to_cpu(ext4_group_desc_csum(sbi, i, gdp)), le16_to_cpu(gdp->bg_checksum)); if (!IsVcbReadOnly(Vcb)) { __brelse(bh); return 0; } }
if (!flexbg_flag) first_block += EXT4_BLOCKS_PER_GROUP(sb);
__brelse(bh); }
ext3_free_blocks_count_set(sbi->s_es, ext4_count_free_blocks(sb)); sbi->s_es->s_free_inodes_count = cpu_to_le32(ext4_count_free_inodes(sb)); return 1;}