| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453945494559456945794589459946094619462946394649465946694679468946994709471947294739474947594769477947894799480948194829483948494859486948794889489949094919492949394949495949694979498949995009501950295039504950595069507950895099510951195129513951495159516951795189519952095219522952395249525952695279528952995309531953295339534953595369537953895399540954195429543954495459546954795489549955095519552955395549555955695579558955995609561956295639564956595669567956895699570957195729573957495759576957795789579958095819582958395849585958695879588958995909591959295939594959595969597959895999600960196029603960496059606960796089609961096119612961396149615961696179618961996209621962296239624962596269627962896299630963196329633963496359636963796389639964096419642964396449645964696479648964996509651965296539654965596569657965896599660966196629663966496659666966796689669967096719672967396749675967696779678967996809681968296839684968596869687968896899690969196929693969496959696969796989699970097019702970397049705970697079708970997109711971297139714971597169717971897199720972197229723972497259726972797289729973097319732973397349735973697379738973997409741974297439744974597469747974897499750975197529753975497559756975797589759976097619762976397649765976697679768976997709771977297739774977597769777977897799780978197829783978497859786978797889789979097919792979397949795979697979798979998009801980298039804980598069807980898099810981198129813981498159816981798189819982098219822982398249825982698279828982998309831983298339834983598369837983898399840984198429843984498459846984798489849985098519852985398549855985698579858985998609861986298639864986598669867986898699870987198729873987498759876987798789879988098819882988398849885988698879888988998909891989298939894989598969897989898999900990199029903990499059906990799089909991099119912991399149915991699179918991999209921992299239924992599269927992899299930993199329933993499359936993799389939994099419942994399449945994699479948994999509951995299539954995599569957995899599960996199629963996499659966996799689969997099719972997399749975997699779978997999809981998299839984998599869987998899899990999199929993999499959996999799989999100001000110002100031000410005100061000710008100091001010011100121001310014100151001610017100181001910020100211002210023100241002510026100271002810029100301003110032100331003410035100361003710038100391004010041100421004310044100451004610047100481004910050100511005210053100541005510056100571005810059100601006110062100631006410065100661006710068100691007010071100721007310074100751007610077100781007910080100811008210083100841008510086100871008810089100901009110092100931009410095100961009710098100991010010101101021010310104101051010610107101081010910110101111011210113101141011510116101171011810119101201012110122101231012410125101261012710128101291013010131101321013310134101351013610137101381013910140101411014210143101441014510146101471014810149101501015110152101531015410155101561015710158101591016010161101621016310164101651016610167101681016910170101711017210173101741017510176101771017810179101801018110182101831018410185101861018710188101891019010191101921019310194101951019610197101981019910200102011020210203102041020510206102071020810209102101021110212102131021410215102161021710218102191022010221102221022310224102251022610227102281022910230102311023210233102341023510236102371023810239102401024110242102431024410245102461024710248102491025010251102521025310254102551025610257102581025910260102611026210263102641026510266102671026810269102701027110272102731027410275102761027710278102791028010281102821028310284102851028610287102881028910290102911029210293102941029510296102971029810299103001030110302103031030410305103061030710308103091031010311103121031310314103151031610317103181031910320103211032210323103241032510326103271032810329103301033110332103331033410335103361033710338103391034010341103421034310344103451034610347103481034910350103511035210353103541035510356103571035810359103601036110362103631036410365103661036710368103691037010371103721037310374103751037610377103781037910380103811038210383103841038510386103871038810389103901039110392103931039410395103961039710398103991040010401104021040310404104051040610407104081040910410104111041210413104141041510416104171041810419104201042110422104231042410425104261042710428104291043010431104321043310434104351043610437104381043910440104411044210443104441044510446104471044810449104501045110452104531045410455104561045710458104591046010461104621046310464104651046610467104681046910470104711047210473104741047510476104771047810479104801048110482104831048410485104861048710488104891049010491104921049310494104951049610497104981049910500105011050210503105041050510506105071050810509105101051110512105131051410515105161051710518105191052010521105221052310524105251052610527105281052910530105311053210533105341053510536105371053810539105401054110542105431054410545105461054710548105491055010551105521055310554105551055610557105581055910560105611056210563105641056510566105671056810569105701057110572105731057410575105761057710578105791058010581105821058310584105851058610587105881058910590105911059210593105941059510596105971059810599106001060110602106031060410605106061060710608106091061010611106121061310614106151061610617106181061910620106211062210623106241062510626106271062810629106301063110632106331063410635106361063710638106391064010641106421064310644106451064610647106481064910650106511065210653106541065510656106571065810659106601066110662106631066410665106661066710668106691067010671106721067310674106751067610677106781067910680106811068210683106841068510686106871068810689106901069110692106931069410695106961069710698106991070010701107021070310704107051070610707107081070910710107111071210713107141071510716107171071810719107201072110722107231072410725107261072710728107291073010731107321073310734107351073610737107381073910740107411074210743107441074510746107471074810749107501075110752107531075410755107561075710758107591076010761107621076310764107651076610767107681076910770107711077210773107741077510776107771077810779107801078110782107831078410785107861078710788107891079010791107921079310794107951079610797107981079910800108011080210803108041080510806108071080810809108101081110812108131081410815108161081710818108191082010821108221082310824108251082610827108281082910830108311083210833108341083510836108371083810839108401084110842108431084410845108461084710848108491085010851108521085310854108551085610857108581085910860108611086210863108641086510866108671086810869108701087110872108731087410875108761087710878108791088010881108821088310884108851088610887108881088910890108911089210893108941089510896108971089810899109001090110902109031090410905109061090710908109091091010911109121091310914109151091610917109181091910920109211092210923109241092510926109271092810929109301093110932109331093410935109361093710938109391094010941109421094310944109451094610947109481094910950109511095210953109541095510956109571095810959109601096110962109631096410965109661096710968109691097010971109721097310974109751097610977109781097910980109811098210983109841098510986109871098810989109901099110992109931099410995109961099710998109991100011001110021100311004110051100611007110081100911010110111101211013110141101511016110171101811019110201102111022110231102411025110261102711028110291103011031110321103311034110351103611037110381103911040110411104211043110441104511046110471104811049110501105111052110531105411055110561105711058110591106011061110621106311064110651106611067110681106911070110711107211073110741107511076110771107811079110801108111082110831108411085110861108711088110891109011091110921109311094110951109611097110981109911100111011110211103111041110511106111071110811109111101111111112111131111411115111161111711118111191112011121111221112311124111251112611127111281112911130111311113211133111341113511136111371113811139111401114111142111431114411145111461114711148111491115011151111521115311154111551115611157111581115911160111611116211163111641116511166111671116811169111701117111172111731117411175111761117711178111791118011181111821118311184111851118611187111881118911190111911119211193111941119511196111971119811199112001120111202112031120411205112061120711208112091121011211112121121311214112151121611217112181121911220112211122211223112241122511226112271122811229112301123111232112331123411235112361123711238112391124011241112421124311244112451124611247112481124911250112511125211253112541125511256112571125811259112601126111262112631126411265112661126711268112691127011271112721127311274112751127611277112781127911280112811128211283112841128511286112871128811289112901129111292112931129411295112961129711298112991130011301113021130311304113051130611307113081130911310113111131211313113141131511316113171131811319113201132111322113231132411325113261132711328113291133011331113321133311334113351133611337113381133911340113411134211343113441134511346113471134811349113501135111352113531135411355113561135711358113591136011361113621136311364113651136611367113681136911370113711137211373113741137511376113771137811379113801138111382113831138411385113861138711388113891139011391113921139311394113951139611397113981139911400114011140211403114041140511406114071140811409114101141111412114131141411415114161141711418114191142011421114221142311424114251142611427114281142911430114311143211433114341143511436114371143811439114401144111442114431144411445114461144711448114491145011451114521145311454114551145611457114581145911460114611146211463114641146511466114671146811469114701147111472114731147411475114761147711478114791148011481114821148311484114851148611487114881148911490114911149211493114941149511496114971149811499115001150111502115031150411505115061150711508115091151011511115121151311514115151151611517115181151911520115211152211523115241152511526115271152811529115301153111532115331153411535115361153711538115391154011541115421154311544115451154611547115481154911550115511155211553115541155511556115571155811559115601156111562115631156411565115661156711568115691157011571115721157311574115751157611577115781157911580115811158211583115841158511586115871158811589115901159111592115931159411595115961159711598115991160011601116021160311604116051160611607116081160911610116111161211613116141161511616116171161811619116201162111622116231162411625116261162711628116291163011631116321163311634116351163611637116381163911640116411164211643116441164511646116471164811649116501165111652116531165411655116561165711658116591166011661116621166311664116651166611667116681166911670116711167211673116741167511676116771167811679116801168111682116831168411685116861168711688116891169011691116921169311694116951169611697116981169911700117011170211703117041170511706117071170811709117101171111712117131171411715117161171711718117191172011721117221172311724117251172611727117281172911730117311173211733117341173511736117371173811739117401174111742117431174411745117461174711748117491175011751117521175311754117551175611757117581175911760117611176211763117641176511766117671176811769117701177111772117731177411775117761177711778117791178011781117821178311784117851178611787117881178911790117911179211793117941179511796117971179811799118001180111802118031180411805118061180711808118091181011811118121181311814118151181611817118181181911820118211182211823118241182511826118271182811829118301183111832118331183411835118361183711838118391184011841118421184311844118451184611847118481184911850118511185211853118541185511856118571185811859118601186111862118631186411865118661186711868118691187011871118721187311874118751187611877118781187911880118811188211883118841188511886118871188811889118901189111892118931189411895118961189711898118991190011901119021190311904119051190611907119081190911910119111191211913119141191511916119171191811919119201192111922119231192411925119261192711928119291193011931119321193311934119351193611937119381193911940119411194211943119441194511946119471194811949119501195111952119531195411955119561195711958119591196011961119621196311964119651196611967119681196911970119711197211973119741197511976119771197811979119801198111982119831198411985119861198711988119891199011991119921199311994119951199611997119981199912000120011200212003120041200512006120071200812009120101201112012120131201412015120161201712018120191202012021120221202312024120251202612027120281202912030120311203212033120341203512036120371203812039120401204112042120431204412045120461204712048120491205012051120521205312054120551205612057120581205912060120611206212063120641206512066120671206812069120701207112072120731207412075120761207712078120791208012081120821208312084120851208612087120881208912090120911209212093120941209512096120971209812099121001210112102121031210412105121061210712108121091211012111121121211312114121151211612117121181211912120121211212212123121241212512126121271212812129121301213112132121331213412135121361213712138121391214012141121421214312144121451214612147121481214912150121511215212153121541215512156121571215812159121601216112162121631216412165121661216712168121691217012171121721217312174121751217612177121781217912180121811218212183121841218512186121871218812189121901219112192121931219412195121961219712198121991220012201122021220312204122051220612207122081220912210122111221212213122141221512216122171221812219122201222112222122231222412225122261222712228122291223012231122321223312234122351223612237122381223912240122411224212243122441224512246122471224812249122501225112252122531225412255122561225712258122591226012261122621226312264122651226612267122681226912270122711227212273122741227512276122771227812279122801228112282122831228412285122861228712288122891229012291122921229312294122951229612297122981229912300123011230212303123041230512306123071230812309123101231112312123131231412315123161231712318123191232012321123221232312324123251232612327123281232912330123311233212333123341233512336123371233812339123401234112342123431234412345123461234712348123491235012351123521235312354123551235612357123581235912360123611236212363123641236512366123671236812369123701237112372123731237412375123761237712378123791238012381123821238312384123851238612387123881238912390123911239212393123941239512396123971239812399124001240112402124031240412405124061240712408124091241012411124121241312414124151241612417124181241912420124211242212423124241242512426124271242812429124301243112432124331243412435124361243712438124391244012441124421244312444124451244612447124481244912450124511245212453124541245512456124571245812459124601246112462124631246412465124661246712468124691247012471124721247312474124751247612477124781247912480124811248212483124841248512486124871248812489124901249112492124931249412495124961249712498124991250012501125021250312504125051250612507125081250912510125111251212513125141251512516125171251812519125201252112522125231252412525125261252712528125291253012531125321253312534125351253612537125381253912540125411254212543125441254512546125471254812549125501255112552125531255412555125561255712558125591256012561125621256312564125651256612567125681256912570125711257212573125741257512576125771257812579125801258112582125831258412585125861258712588125891259012591125921259312594125951259612597125981259912600126011260212603126041260512606126071260812609126101261112612126131261412615126161261712618126191262012621126221262312624126251262612627126281262912630126311263212633126341263512636126371263812639126401264112642126431264412645126461264712648126491265012651126521265312654126551265612657126581265912660126611266212663126641266512666126671266812669126701267112672126731267412675126761267712678126791268012681126821268312684126851268612687126881268912690126911269212693126941269512696126971269812699127001270112702127031270412705127061270712708127091271012711127121271312714127151271612717127181271912720127211272212723127241272512726127271272812729127301273112732127331273412735127361273712738127391274012741127421274312744127451274612747127481274912750127511275212753127541275512756127571275812759127601276112762127631276412765127661276712768127691277012771127721277312774127751277612777127781277912780127811278212783127841278512786127871278812789127901279112792127931279412795127961279712798127991280012801128021280312804128051280612807128081280912810128111281212813128141281512816128171281812819128201282112822128231282412825128261282712828128291283012831128321283312834128351283612837128381283912840128411284212843128441284512846128471284812849128501285112852128531285412855128561285712858128591286012861128621286312864128651286612867128681286912870128711287212873128741287512876128771287812879128801288112882128831288412885128861288712888128891289012891128921289312894128951289612897128981289912900129011290212903129041290512906129071290812909129101291112912129131291412915129161291712918129191292012921129221292312924129251292612927129281292912930129311293212933129341293512936129371293812939129401294112942129431294412945129461294712948129491295012951129521295312954129551295612957129581295912960129611296212963129641296512966129671296812969129701297112972129731297412975129761297712978129791298012981129821298312984129851298612987129881298912990129911299212993129941299512996129971299812999130001300113002130031300413005130061300713008130091301013011130121301313014130151301613017130181301913020130211302213023130241302513026130271302813029130301303113032130331303413035130361303713038130391304013041130421304313044130451304613047130481304913050130511305213053130541305513056130571305813059130601306113062130631306413065130661306713068130691307013071130721307313074130751307613077130781307913080130811308213083130841308513086130871308813089130901309113092130931309413095130961309713098130991310013101131021310313104131051310613107131081310913110131111311213113131141311513116131171311813119131201312113122131231312413125131261312713128131291313013131131321313313134131351313613137131381313913140131411314213143131441314513146131471314813149131501315113152131531315413155131561315713158131591316013161131621316313164131651316613167131681316913170131711317213173131741317513176131771317813179131801318113182131831318413185131861318713188131891319013191131921319313194131951319613197131981319913200132011320213203132041320513206132071320813209132101321113212132131321413215132161321713218132191322013221132221322313224132251322613227132281322913230132311323213233132341323513236132371323813239132401324113242132431324413245132461324713248132491325013251132521325313254132551325613257132581325913260132611326213263132641326513266132671326813269132701327113272132731327413275132761327713278132791328013281132821328313284132851328613287132881328913290132911329213293132941329513296132971329813299133001330113302133031330413305133061330713308133091331013311133121331313314133151331613317133181331913320133211332213323133241332513326133271332813329133301333113332133331333413335133361333713338133391334013341133421334313344133451334613347133481334913350133511335213353133541335513356133571335813359133601336113362133631336413365133661336713368133691337013371133721337313374133751337613377133781337913380133811338213383133841338513386133871338813389133901339113392133931339413395133961339713398133991340013401134021340313404134051340613407134081340913410134111341213413134141341513416134171341813419134201342113422134231342413425134261342713428134291343013431134321343313434134351343613437134381343913440134411344213443134441344513446134471344813449134501345113452134531345413455134561345713458134591346013461134621346313464134651346613467134681346913470134711347213473134741347513476134771347813479134801348113482134831348413485134861348713488134891349013491134921349313494134951349613497134981349913500135011350213503135041350513506135071350813509135101351113512135131351413515135161351713518135191352013521135221352313524135251352613527135281352913530135311353213533135341353513536135371353813539135401354113542135431354413545135461354713548135491355013551135521355313554135551355613557135581355913560135611356213563135641356513566135671356813569135701357113572135731357413575135761357713578135791358013581135821358313584135851358613587135881358913590135911359213593135941359513596135971359813599136001360113602136031360413605136061360713608136091361013611136121361313614136151361613617136181361913620136211362213623136241362513626136271362813629136301363113632136331363413635136361363713638136391364013641136421364313644136451364613647136481364913650136511365213653136541365513656136571365813659136601366113662136631366413665136661366713668136691367013671136721367313674136751367613677136781367913680136811368213683136841368513686136871368813689136901369113692136931369413695136961369713698136991370013701137021370313704137051370613707137081370913710137111371213713137141371513716137171371813719137201372113722137231372413725137261372713728137291373013731137321373313734137351373613737137381373913740137411374213743137441374513746137471374813749137501375113752137531375413755137561375713758137591376013761137621376313764137651376613767137681376913770137711377213773137741377513776137771377813779137801378113782137831378413785137861378713788137891379013791137921379313794137951379613797137981379913800138011380213803138041380513806138071380813809138101381113812138131381413815138161381713818138191382013821138221382313824138251382613827138281382913830138311383213833138341383513836138371383813839138401384113842138431384413845138461384713848138491385013851138521385313854138551385613857138581385913860138611386213863138641386513866138671386813869138701387113872138731387413875138761387713878138791388013881138821388313884138851388613887138881388913890138911389213893138941389513896138971389813899139001390113902139031390413905139061390713908139091391013911139121391313914139151391613917139181391913920139211392213923139241392513926139271392813929139301393113932139331393413935139361393713938139391394013941139421394313944139451394613947139481394913950139511395213953139541395513956139571395813959139601396113962139631396413965139661396713968139691397013971139721397313974139751397613977139781397913980139811398213983139841398513986139871398813989139901399113992139931399413995139961399713998139991400014001140021400314004140051400614007140081400914010140111401214013140141401514016140171401814019140201402114022140231402414025140261402714028140291403014031140321403314034140351403614037140381403914040140411404214043140441404514046140471404814049140501405114052140531405414055140561405714058140591406014061140621406314064140651406614067140681406914070140711407214073140741407514076140771407814079140801408114082140831408414085140861408714088140891409014091140921409314094140951409614097140981409914100141011410214103141041410514106141071410814109141101411114112141131411414115141161411714118141191412014121141221412314124141251412614127141281412914130141311413214133141341413514136141371413814139141401414114142141431414414145141461414714148141491415014151141521415314154141551415614157141581415914160141611416214163141641416514166141671416814169141701417114172141731417414175141761417714178141791418014181141821418314184141851418614187141881418914190141911419214193141941419514196141971419814199142001420114202142031420414205142061420714208142091421014211142121421314214142151421614217142181421914220142211422214223142241422514226142271422814229142301423114232142331423414235142361423714238142391424014241142421424314244142451424614247142481424914250142511425214253142541425514256142571425814259142601426114262142631426414265142661426714268142691427014271142721427314274142751427614277142781427914280142811428214283142841428514286142871428814289142901429114292142931429414295142961429714298142991430014301143021430314304143051430614307143081430914310143111431214313143141431514316143171431814319143201432114322143231432414325143261432714328143291433014331143321433314334143351433614337143381433914340143411434214343143441434514346143471434814349143501435114352143531435414355143561435714358143591436014361143621436314364143651436614367143681436914370143711437214373143741437514376143771437814379143801438114382143831438414385143861438714388143891439014391143921439314394143951439614397143981439914400144011440214403144041440514406144071440814409144101441114412144131441414415144161441714418144191442014421144221442314424144251442614427144281442914430144311443214433144341443514436144371443814439144401444114442144431444414445144461444714448144491445014451144521445314454144551445614457144581445914460144611446214463144641446514466144671446814469144701447114472144731447414475144761447714478144791448014481144821448314484144851448614487144881448914490144911449214493144941449514496144971449814499145001450114502145031450414505145061450714508145091451014511145121451314514145151451614517145181451914520145211452214523145241452514526145271452814529145301453114532145331453414535145361453714538145391454014541145421454314544145451454614547145481454914550145511455214553145541455514556145571455814559145601456114562145631456414565145661456714568145691457014571145721457314574145751457614577145781457914580145811458214583145841458514586145871458814589145901459114592145931459414595145961459714598145991460014601146021460314604146051460614607146081460914610146111461214613146141461514616146171461814619146201462114622146231462414625146261462714628146291463014631146321463314634146351463614637146381463914640146411464214643146441464514646146471464814649146501465114652146531465414655146561465714658146591466014661146621466314664146651466614667146681466914670146711467214673146741467514676146771467814679146801468114682146831468414685146861468714688146891469014691146921469314694146951469614697146981469914700147011470214703147041470514706147071470814709147101471114712147131471414715147161471714718147191472014721147221472314724147251472614727147281472914730147311473214733147341473514736147371473814739147401474114742147431474414745147461474714748147491475014751147521475314754147551475614757147581475914760147611476214763147641476514766147671476814769147701477114772147731477414775147761477714778147791478014781147821478314784147851478614787147881478914790147911479214793147941479514796147971479814799148001480114802148031480414805148061480714808148091481014811148121481314814148151481614817148181481914820148211482214823148241482514826148271482814829148301483114832148331483414835148361483714838148391484014841148421484314844148451484614847148481484914850148511485214853148541485514856148571485814859148601486114862148631486414865148661486714868148691487014871148721487314874148751487614877148781487914880148811488214883148841488514886148871488814889148901489114892148931489414895148961489714898148991490014901149021490314904149051490614907149081490914910149111491214913149141491514916149171491814919149201492114922149231492414925149261492714928149291493014931149321493314934149351493614937149381493914940149411494214943149441494514946149471494814949149501495114952149531495414955149561495714958149591496014961149621496314964149651496614967149681496914970149711497214973149741497514976149771497814979149801498114982149831498414985149861498714988149891499014991149921499314994149951499614997149981499915000150011500215003150041500515006150071500815009150101501115012150131501415015150161501715018150191502015021150221502315024150251502615027150281502915030150311503215033150341503515036150371503815039150401504115042150431504415045150461504715048150491505015051150521505315054150551505615057150581505915060150611506215063150641506515066 | diff -Nur linux-2.6.30.orig/fs/Kconfig linux-2.6.30/fs/Kconfig--- linux-2.6.30.orig/fs/Kconfig	2009-06-10 05:05:27.000000000 +0200+++ linux-2.6.30/fs/Kconfig	2009-06-11 09:21:04.000000000 +0200@@ -162,6 +162,10 @@ source "fs/befs/Kconfig" source "fs/bfs/Kconfig" source "fs/efs/Kconfig"++# Patched by YAFFS+source "fs/yaffs2/Kconfig"+ source "fs/jffs2/Kconfig" # UBIFS File system configuration source "fs/ubifs/Kconfig"diff -Nur linux-2.6.30.orig/fs/Makefile linux-2.6.30/fs/Makefile--- linux-2.6.30.orig/fs/Makefile	2009-06-10 05:05:27.000000000 +0200+++ linux-2.6.30/fs/Makefile	2009-06-11 09:21:31.000000000 +0200@@ -124,3 +124,4 @@ obj-$(CONFIG_BTRFS_FS)		+= btrfs/ obj-$(CONFIG_GFS2_FS)           += gfs2/ obj-$(CONFIG_EXOFS_FS)          += exofs/+obj-$(CONFIG_YAFFS_FS)		+= yaffs2/diff -Nur linux-2.6.30.orig/fs/Makefile.pre.yaffs linux-2.6.30/fs/Makefile.pre.yaffs--- linux-2.6.30.orig/fs/Makefile.pre.yaffs	1970-01-01 01:00:00.000000000 +0100+++ linux-2.6.30/fs/Makefile.pre.yaffs	2009-06-11 09:21:04.000000000 +0200@@ -0,0 +1,126 @@+#+# Makefile for the Linux filesystems.+#+# 14 Sep 2000, Christoph Hellwig <hch@infradead.org>+# Rewritten to use lists instead of if-statements.+# ++obj-y :=	open.o read_write.o file_table.o super.o \+		char_dev.o stat.o exec.o pipe.o namei.o fcntl.o \+		ioctl.o readdir.o select.o fifo.o dcache.o inode.o \+		attr.o bad_inode.o file.o filesystems.o namespace.o \+		seq_file.o xattr.o libfs.o fs-writeback.o \+		pnode.o drop_caches.o splice.o sync.o utimes.o \+		stack.o++ifeq ($(CONFIG_BLOCK),y)+obj-y +=	buffer.o bio.o block_dev.o direct-io.o mpage.o ioprio.o+else+obj-y +=	no-block.o+endif++obj-$(CONFIG_BLK_DEV_INTEGRITY) += bio-integrity.o+obj-y				+= notify/+obj-$(CONFIG_EPOLL)		+= eventpoll.o+obj-$(CONFIG_ANON_INODES)	+= anon_inodes.o+obj-$(CONFIG_SIGNALFD)		+= signalfd.o+obj-$(CONFIG_TIMERFD)		+= timerfd.o+obj-$(CONFIG_EVENTFD)		+= eventfd.o+obj-$(CONFIG_AIO)               += aio.o+obj-$(CONFIG_FILE_LOCKING)      += locks.o+obj-$(CONFIG_COMPAT)		+= compat.o compat_ioctl.o++nfsd-$(CONFIG_NFSD)		:= nfsctl.o+obj-y				+= $(nfsd-y) $(nfsd-m)++obj-$(CONFIG_BINFMT_AOUT)	+= binfmt_aout.o+obj-$(CONFIG_BINFMT_EM86)	+= binfmt_em86.o+obj-$(CONFIG_BINFMT_MISC)	+= binfmt_misc.o++# binfmt_script is always there+obj-y				+= binfmt_script.o++obj-$(CONFIG_BINFMT_ELF)	+= binfmt_elf.o+obj-$(CONFIG_COMPAT_BINFMT_ELF)	+= compat_binfmt_elf.o+obj-$(CONFIG_BINFMT_ELF_FDPIC)	+= binfmt_elf_fdpic.o+obj-$(CONFIG_BINFMT_SOM)	+= binfmt_som.o+obj-$(CONFIG_BINFMT_FLAT)	+= binfmt_flat.o++obj-$(CONFIG_FS_MBCACHE)	+= mbcache.o+obj-$(CONFIG_FS_POSIX_ACL)	+= posix_acl.o xattr_acl.o+obj-$(CONFIG_NFS_COMMON)	+= nfs_common/+obj-$(CONFIG_GENERIC_ACL)	+= generic_acl.o++obj-$(CONFIG_QUOTA)		+= dquot.o+obj-$(CONFIG_QFMT_V1)		+= quota_v1.o+obj-$(CONFIG_QFMT_V2)		+= quota_v2.o+obj-$(CONFIG_QUOTA_TREE)	+= quota_tree.o+obj-$(CONFIG_QUOTACTL)		+= quota.o++obj-$(CONFIG_PROC_FS)		+= proc/+obj-y				+= partitions/+obj-$(CONFIG_SYSFS)		+= sysfs/+obj-$(CONFIG_CONFIGFS_FS)	+= configfs/+obj-y				+= devpts/++obj-$(CONFIG_PROFILING)		+= dcookies.o+obj-$(CONFIG_DLM)		+= dlm/+ +# Do not add any filesystems before this line+obj-$(CONFIG_REISERFS_FS)	+= reiserfs/+obj-$(CONFIG_EXT3_FS)		+= ext3/ # Before ext2 so root fs can be ext3+obj-$(CONFIG_EXT2_FS)		+= ext2/+# We place ext4 after ext2 so plain ext2 root fs's are mounted using ext2+# unless explicitly requested by rootfstype+obj-$(CONFIG_EXT4_FS)		+= ext4/+obj-$(CONFIG_JBD)		+= jbd/+obj-$(CONFIG_JBD2)		+= jbd2/+obj-$(CONFIG_CRAMFS)		+= cramfs/+obj-$(CONFIG_SQUASHFS)		+= squashfs/+obj-y				+= ramfs/+obj-$(CONFIG_HUGETLBFS)		+= hugetlbfs/+obj-$(CONFIG_CODA_FS)		+= coda/+obj-$(CONFIG_MINIX_FS)		+= minix/+obj-$(CONFIG_FAT_FS)		+= fat/+obj-$(CONFIG_BFS_FS)		+= bfs/+obj-$(CONFIG_ISO9660_FS)	+= isofs/+obj-$(CONFIG_HFSPLUS_FS)	+= hfsplus/ # Before hfs to find wrapped HFS++obj-$(CONFIG_HFS_FS)		+= hfs/+obj-$(CONFIG_ECRYPT_FS)		+= ecryptfs/+obj-$(CONFIG_VXFS_FS)		+= freevxfs/+obj-$(CONFIG_NFS_FS)		+= nfs/+obj-$(CONFIG_EXPORTFS)		+= exportfs/+obj-$(CONFIG_NFSD)		+= nfsd/+obj-$(CONFIG_LOCKD)		+= lockd/+obj-$(CONFIG_NLS)		+= nls/+obj-$(CONFIG_SYSV_FS)		+= sysv/+obj-$(CONFIG_SMB_FS)		+= smbfs/+obj-$(CONFIG_CIFS)		+= cifs/+obj-$(CONFIG_NCP_FS)		+= ncpfs/+obj-$(CONFIG_HPFS_FS)		+= hpfs/+obj-$(CONFIG_NTFS_FS)		+= ntfs/+obj-$(CONFIG_UFS_FS)		+= ufs/+obj-$(CONFIG_EFS_FS)		+= efs/+obj-$(CONFIG_JFFS2_FS)		+= jffs2/+obj-$(CONFIG_UBIFS_FS)		+= ubifs/+obj-$(CONFIG_AFFS_FS)		+= affs/+obj-$(CONFIG_ROMFS_FS)		+= romfs/+obj-$(CONFIG_QNX4FS_FS)		+= qnx4/+obj-$(CONFIG_AUTOFS_FS)		+= autofs/+obj-$(CONFIG_AUTOFS4_FS)	+= autofs4/+obj-$(CONFIG_ADFS_FS)		+= adfs/+obj-$(CONFIG_FUSE_FS)		+= fuse/+obj-$(CONFIG_UDF_FS)		+= udf/+obj-$(CONFIG_SUN_OPENPROMFS)	+= openpromfs/+obj-$(CONFIG_OMFS_FS)		+= omfs/+obj-$(CONFIG_JFS_FS)		+= jfs/+obj-$(CONFIG_XFS_FS)		+= xfs/+obj-$(CONFIG_9P_FS)		+= 9p/+obj-$(CONFIG_AFS_FS)		+= afs/+obj-$(CONFIG_BEFS_FS)		+= befs/+obj-$(CONFIG_HOSTFS)		+= hostfs/+obj-$(CONFIG_HPPFS)		+= hppfs/+obj-$(CONFIG_DEBUG_FS)		+= debugfs/+obj-$(CONFIG_OCFS2_FS)		+= ocfs2/+obj-$(CONFIG_BTRFS_FS)		+= btrfs/+obj-$(CONFIG_GFS2_FS)           += gfs2/diff -Nur linux-2.6.30.orig/fs/yaffs2/devextras.h linux-2.6.30/fs/yaffs2/devextras.h--- linux-2.6.30.orig/fs/yaffs2/devextras.h	1970-01-01 01:00:00.000000000 +0100+++ linux-2.6.30/fs/yaffs2/devextras.h	2009-06-11 09:21:04.000000000 +0200@@ -0,0 +1,196 @@+/*+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.+ *+ * Copyright (C) 2002-2007 Aleph One Ltd.+ *   for Toby Churchill Ltd and Brightstar Engineering+ *+ * Created by Charles Manning <charles@aleph1.co.uk>+ *+ * This program is free software; you can redistribute it and/or modify+ * it under the terms of the GNU Lesser General Public License version 2.1 as+ * published by the Free Software Foundation.+ *+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.+ */++/*+ * This file is just holds extra declarations of macros that would normally+ * be providesd in the Linux kernel. These macros have been written from+ * scratch but are functionally equivalent to the Linux ones.+ *+ */++#ifndef __EXTRAS_H__+#define __EXTRAS_H__+++#if !(defined __KERNEL__)++/* Definition of types */+typedef unsigned char __u8;+typedef unsigned short __u16;+typedef unsigned __u32;++#endif++/*+ * This is a simple doubly linked list implementation that matches the+ * way the Linux kernel doubly linked list implementation works.+ */++struct ylist_head {+	struct ylist_head *next; /* next in chain */+	struct ylist_head *prev; /* previous in chain */+};+++/* Initialise a static list */+#define YLIST_HEAD(name) \+struct ylist_head name = { &(name), &(name)}++++/* Initialise a list head to an empty list */+#define YINIT_LIST_HEAD(p) \+do { \+	(p)->next = (p);\+	(p)->prev = (p); \+} while (0)+++/* Add an element to a list */+static __inline__ void ylist_add(struct ylist_head *newEntry,+				struct ylist_head *list)+{+	struct ylist_head *listNext = list->next;++	list->next = newEntry;+	newEntry->prev = list;+	newEntry->next = listNext;+	listNext->prev = newEntry;++}++static __inline__ void ylist_add_tail(struct ylist_head *newEntry,+				 struct ylist_head *list)+{+	struct ylist_head *listPrev = list->prev;++	list->prev = newEntry;+	newEntry->next = list;+	newEntry->prev = listPrev;+	listPrev->next = newEntry;++}+++/* Take an element out of its current list, with or without+ * reinitialising the links.of the entry*/+static __inline__ void ylist_del(struct ylist_head *entry)+{+	struct ylist_head *listNext = entry->next;+	struct ylist_head *listPrev = entry->prev;++	listNext->prev = listPrev;+	listPrev->next = listNext;++}++static __inline__ void ylist_del_init(struct ylist_head *entry)+{+	ylist_del(entry);+	entry->next = entry->prev = entry;+}+++/* Test if the list is empty */+static __inline__ int ylist_empty(struct ylist_head *entry)+{+	return (entry->next == entry);+}+++/* ylist_entry takes a pointer to a list entry and offsets it to that+ * we can find a pointer to the object it is embedded in.+ */+++#define ylist_entry(entry, type, member) \+	((type *)((char *)(entry)-(unsigned long)(&((type *)NULL)->member)))+++/* ylist_for_each and list_for_each_safe  iterate over lists.+ * ylist_for_each_safe uses temporary storage to make the list delete safe+ */++#define ylist_for_each(itervar, list) \+	for (itervar = (list)->next; itervar != (list); itervar = itervar->next)++#define ylist_for_each_safe(itervar, saveVar, list) \+	for (itervar = (list)->next, saveVar = (list)->next->next; \+		itervar != (list); itervar = saveVar, saveVar = saveVar->next)+++#if !(defined __KERNEL__)+++#ifndef WIN32+#include <sys/stat.h>+#endif+++#ifdef CONFIG_YAFFS_PROVIDE_DEFS+/* File types */+++#define DT_UNKNOWN	0+#define DT_FIFO		1+#define DT_CHR		2+#define DT_DIR		4+#define DT_BLK		6+#define DT_REG		8+#define DT_LNK		10+#define DT_SOCK		12+#define DT_WHT		14+++#ifndef WIN32+#include <sys/stat.h>+#endif++/*+ * Attribute flags.  These should be or-ed together to figure out what+ * has been changed!+ */+#define ATTR_MODE	1+#define ATTR_UID	2+#define ATTR_GID	4+#define ATTR_SIZE	8+#define ATTR_ATIME	16+#define ATTR_MTIME	32+#define ATTR_CTIME	64++struct iattr {+	unsigned int ia_valid;+	unsigned ia_mode;+	unsigned ia_uid;+	unsigned ia_gid;+	unsigned ia_size;+	unsigned ia_atime;+	unsigned ia_mtime;+	unsigned ia_ctime;+	unsigned int ia_attr_flags;+};++#endif++#else++#include <linux/types.h>+#include <linux/fs.h>+#include <linux/stat.h>++#endif+++#endifdiff -Nur linux-2.6.30.orig/fs/yaffs2/Kconfig linux-2.6.30/fs/yaffs2/Kconfig--- linux-2.6.30.orig/fs/yaffs2/Kconfig	1970-01-01 01:00:00.000000000 +0100+++ linux-2.6.30/fs/yaffs2/Kconfig	2009-06-11 09:21:04.000000000 +0200@@ -0,0 +1,156 @@+#+# YAFFS file system configurations+#++config YAFFS_FS+	tristate "YAFFS2 file system support"+	default n+	depends on MTD_BLOCK+	select YAFFS_YAFFS1+	select YAFFS_YAFFS2+	help+	  YAFFS2, or Yet Another Flash Filing System, is a filing system+	  optimised for NAND Flash chips.++	  To compile the YAFFS2 file system support as a module, choose M+	  here: the module will be called yaffs2.++	  If unsure, say N.++	  Further information on YAFFS2 is available at+	  <http://www.aleph1.co.uk/yaffs/>.++config YAFFS_YAFFS1+	bool "512 byte / page devices"+	depends on YAFFS_FS+	default y+	help+	  Enable YAFFS1 support -- yaffs for 512 byte / page devices++	  Not needed for 2K-page devices.++	  If unsure, say Y.++config YAFFS_9BYTE_TAGS+	bool "Use older-style on-NAND data format with pageStatus byte"+	depends on YAFFS_YAFFS1+	default n+	help++	  Older-style on-NAND data format has a "pageStatus" byte to record+	  chunk/page state.  This byte is zero when the page is discarded.+	  Choose this option if you have existing on-NAND data using this+	  format that you need to continue to support.  New data written+	  also uses the older-style format.  Note: Use of this option+	  generally requires that MTD's oob layout be adjusted to use the+	  older-style format.  See notes on tags formats and MTD versions+	  in yaffs_mtdif1.c.++	  If unsure, say N.++config YAFFS_DOES_ECC+	bool "Lets Yaffs do its own ECC"+	depends on YAFFS_FS && YAFFS_YAFFS1 && !YAFFS_9BYTE_TAGS+	default n+	help+	  This enables Yaffs to use its own ECC functions instead of using+	  the ones from the generic MTD-NAND driver.++	  If unsure, say N.++config YAFFS_ECC_WRONG_ORDER+	bool "Use the same ecc byte order as Steven Hill's nand_ecc.c"+	depends on YAFFS_FS && YAFFS_DOES_ECC && !YAFFS_9BYTE_TAGS+	default n+	help+	  This makes yaffs_ecc.c use the same ecc byte order as Steven+	  Hill's nand_ecc.c. If not set, then you get the same ecc byte+	  order as SmartMedia.++	  If unsure, say N.++config YAFFS_YAFFS2+	bool "2048 byte (or larger) / page devices"+	depends on YAFFS_FS+	default y+	help+	  Enable YAFFS2 support -- yaffs for >= 2K bytes per page devices++	  If unsure, say Y.++config YAFFS_AUTO_YAFFS2+	bool "Autoselect yaffs2 format"+	depends on YAFFS_YAFFS2+	default y+	help+	  Without this, you need to explicitely use yaffs2 as the file+	  system type. With this, you can say "yaffs" and yaffs or yaffs2+	  will be used depending on the device page size (yaffs on+	  512-byte page devices, yaffs2 on 2K page devices).++	  If unsure, say Y.++config YAFFS_DISABLE_LAZY_LOAD+	bool "Disable lazy loading"+	depends on YAFFS_YAFFS2+	default n+	help+	  "Lazy loading" defers loading file details until they are+	  required. This saves mount time, but makes the first look-up+	  a bit longer.++	  Lazy loading will only happen if enabled by this option being 'n'+	  and if the appropriate tags are available, else yaffs2 will+	  automatically fall back to immediate loading and do the right+	  thing.++	  Lazy laoding will be required by checkpointing.++	  Setting this to 'y' will disable lazy loading.++	  If unsure, say N.+++config YAFFS_DISABLE_WIDE_TNODES+	bool "Turn off wide tnodes"+	depends on YAFFS_FS+	default n+	help+	  Wide tnodes are only used for NAND arrays >=32MB for 512-byte+	  page devices and >=128MB for 2k page devices. They use slightly+	  more RAM but are faster since they eliminate chunk group+	  searching.++	  Setting this to 'y' will force tnode width to 16 bits and save+	  memory but make large arrays slower.++	  If unsure, say N.++config YAFFS_ALWAYS_CHECK_CHUNK_ERASED+	bool "Force chunk erase check"+	depends on YAFFS_FS+	default n+	help+          Normally YAFFS only checks chunks before writing until an erased+	  chunk is found. This helps to detect any partially written+	  chunks that might have happened due to power loss.++	  Enabling this forces on the test that chunks are erased in flash+	  before writing to them. This takes more time but is potentially+	  a bit more secure.++	  Suggest setting Y during development and ironing out driver+	  issues etc. Suggest setting to N if you want faster writing.++	  If unsure, say Y.++config YAFFS_SHORT_NAMES_IN_RAM+	bool "Cache short names in RAM"+	depends on YAFFS_FS+	default y+	help+	  If this config is set, then short names are stored with the+	  yaffs_Object.  This costs an extra 16 bytes of RAM per object,+	  but makes look-ups faster.++	  If unsure, say Y.diff -Nur linux-2.6.30.orig/fs/yaffs2/Makefile linux-2.6.30/fs/yaffs2/Makefile--- linux-2.6.30.orig/fs/yaffs2/Makefile	1970-01-01 01:00:00.000000000 +0100+++ linux-2.6.30/fs/yaffs2/Makefile	2009-06-11 09:21:04.000000000 +0200@@ -0,0 +1,10 @@+#+# Makefile for the linux YAFFS filesystem routines.+#++obj-$(CONFIG_YAFFS_FS) += yaffs.o++yaffs-y := yaffs_ecc.o yaffs_fs.o yaffs_guts.o yaffs_checkptrw.o+yaffs-y += yaffs_packedtags1.o yaffs_packedtags2.o yaffs_nand.o yaffs_qsort.o+yaffs-y += yaffs_tagscompat.o yaffs_tagsvalidity.o+yaffs-y += yaffs_mtdif.o yaffs_mtdif1.o yaffs_mtdif2.odiff -Nur linux-2.6.30.orig/fs/yaffs2/moduleconfig.h linux-2.6.30/fs/yaffs2/moduleconfig.h--- linux-2.6.30.orig/fs/yaffs2/moduleconfig.h	1970-01-01 01:00:00.000000000 +0100+++ linux-2.6.30/fs/yaffs2/moduleconfig.h	2009-06-11 09:21:04.000000000 +0200@@ -0,0 +1,65 @@+/*+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.+ *+ * Copyright (C) 2002-2007 Aleph One Ltd.+ *   for Toby Churchill Ltd and Brightstar Engineering+ *+ * Created by Martin Fouts <Martin.Fouts@palmsource.com>+ *+ * This program is free software; you can redistribute it and/or modify+ * it under the terms of the GNU Lesser General Public License version 2.1 as+ * published by the Free Software Foundation.+ *+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.+ */++#ifndef __YAFFS_CONFIG_H__+#define __YAFFS_CONFIG_H__++#ifdef YAFFS_OUT_OF_TREE++/* DO NOT UNSET THESE THREE. YAFFS2 will not compile if you do. */+#define CONFIG_YAFFS_FS+#define CONFIG_YAFFS_YAFFS1+#define CONFIG_YAFFS_YAFFS2++/* These options are independent of each other.  Select those that matter. */++/* Default: Not selected */+/* Meaning: Yaffs does its own ECC, rather than using MTD ECC */+/* #define CONFIG_YAFFS_DOES_ECC */++/* Default: Not selected */+/* Meaning: ECC byte order is 'wrong'.  Only meaningful if */+/*          CONFIG_YAFFS_DOES_ECC is set */+/* #define CONFIG_YAFFS_ECC_WRONG_ORDER */++/* Default: Selected */+/* Meaning: Disables testing whether chunks are erased before writing to them*/+#define CONFIG_YAFFS_DISABLE_CHUNK_ERASED_CHECK++/* Default: Selected */+/* Meaning: Cache short names, taking more RAM, but faster look-ups */+#define CONFIG_YAFFS_SHORT_NAMES_IN_RAM++/* Default: 10 */+/* Meaning: set the count of blocks to reserve for checkpointing */+#define CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS 10++/*+Older-style on-NAND data format has a "pageStatus" byte to record+chunk/page state.  This byte is zeroed when the page is discarded.+Choose this option if you have existing on-NAND data in this format+that you need to continue to support.  New data written also uses the+older-style format.+Note: Use of this option generally requires that MTD's oob layout be+adjusted to use the older-style format.  See notes on tags formats and+MTD versions in yaffs_mtdif1.c.+*/+/* Default: Not selected */+/* Meaning: Use older-style on-NAND data format with pageStatus byte */+/* #define CONFIG_YAFFS_9BYTE_TAGS */++#endif /* YAFFS_OUT_OF_TREE */++#endif /* __YAFFS_CONFIG_H__ */diff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_checkptrw.c linux-2.6.30/fs/yaffs2/yaffs_checkptrw.c--- linux-2.6.30.orig/fs/yaffs2/yaffs_checkptrw.c	1970-01-01 01:00:00.000000000 +0100+++ linux-2.6.30/fs/yaffs2/yaffs_checkptrw.c	2009-06-11 09:21:04.000000000 +0200@@ -0,0 +1,394 @@+/*+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.+ *+ * Copyright (C) 2002-2007 Aleph One Ltd.+ *   for Toby Churchill Ltd and Brightstar Engineering+ *+ * Created by Charles Manning <charles@aleph1.co.uk>+ *+ * This program is free software; you can redistribute it and/or modify+ * it under the terms of the GNU General Public License version 2 as+ * published by the Free Software Foundation.+ */++const char *yaffs_checkptrw_c_version =+	"$Id: yaffs_checkptrw.c,v 1.18 2009-03-06 17:20:49 wookey Exp $";+++#include "yaffs_checkptrw.h"+#include "yaffs_getblockinfo.h"++static int yaffs_CheckpointSpaceOk(yaffs_Device *dev)+{+	int blocksAvailable = dev->nErasedBlocks - dev->nReservedBlocks;++	T(YAFFS_TRACE_CHECKPOINT,+		(TSTR("checkpt blocks available = %d" TENDSTR),+		blocksAvailable));++	return (blocksAvailable <= 0) ? 0 : 1;+}+++static int yaffs_CheckpointErase(yaffs_Device *dev)+{+	int i;++	if (!dev->eraseBlockInNAND)+		return 0;+	T(YAFFS_TRACE_CHECKPOINT, (TSTR("checking blocks %d to %d"TENDSTR),+		dev->internalStartBlock, dev->internalEndBlock));++	for (i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) {+		yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, i);+		if (bi->blockState == YAFFS_BLOCK_STATE_CHECKPOINT) {+			T(YAFFS_TRACE_CHECKPOINT, (TSTR("erasing checkpt block %d"TENDSTR), i));+			if (dev->eraseBlockInNAND(dev, i - dev->blockOffset /* realign */)) {+				bi->blockState = YAFFS_BLOCK_STATE_EMPTY;+				dev->nErasedBlocks++;+				dev->nFreeChunks += dev->nChunksPerBlock;+			} else {+				dev->markNANDBlockBad(dev, i);+				bi->blockState = YAFFS_BLOCK_STATE_DEAD;+			}+		}+	}++	dev->blocksInCheckpoint = 0;++	return 1;+}+++static void yaffs_CheckpointFindNextErasedBlock(yaffs_Device *dev)+{+	int  i;+	int blocksAvailable = dev->nErasedBlocks - dev->nReservedBlocks;+	T(YAFFS_TRACE_CHECKPOINT,+		(TSTR("allocating checkpt block: erased %d reserved %d avail %d next %d "TENDSTR),+		dev->nErasedBlocks, dev->nReservedBlocks, blocksAvailable, dev->checkpointNextBlock));++	if (dev->checkpointNextBlock >= 0 &&+			dev->checkpointNextBlock <= dev->internalEndBlock &&+			blocksAvailable > 0) {++		for (i = dev->checkpointNextBlock; i <= dev->internalEndBlock; i++) {+			yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, i);+			if (bi->blockState == YAFFS_BLOCK_STATE_EMPTY) {+				dev->checkpointNextBlock = i + 1;+				dev->checkpointCurrentBlock = i;+				T(YAFFS_TRACE_CHECKPOINT, (TSTR("allocating checkpt block %d"TENDSTR), i));+				return;+			}+		}+	}+	T(YAFFS_TRACE_CHECKPOINT, (TSTR("out of checkpt blocks"TENDSTR)));++	dev->checkpointNextBlock = -1;+	dev->checkpointCurrentBlock = -1;+}++static void yaffs_CheckpointFindNextCheckpointBlock(yaffs_Device *dev)+{+	int  i;+	yaffs_ExtendedTags tags;++	T(YAFFS_TRACE_CHECKPOINT, (TSTR("find next checkpt block: start:  blocks %d next %d" TENDSTR),+		dev->blocksInCheckpoint, dev->checkpointNextBlock));++	if (dev->blocksInCheckpoint < dev->checkpointMaxBlocks)+		for (i = dev->checkpointNextBlock; i <= dev->internalEndBlock; i++) {+			int chunk = i * dev->nChunksPerBlock;+			int realignedChunk = chunk - dev->chunkOffset;++			dev->readChunkWithTagsFromNAND(dev, realignedChunk,+					NULL, &tags);+			T(YAFFS_TRACE_CHECKPOINT, (TSTR("find next checkpt block: search: block %d oid %d seq %d eccr %d" TENDSTR),+				i, tags.objectId, tags.sequenceNumber, tags.eccResult));++			if (tags.sequenceNumber == YAFFS_SEQUENCE_CHECKPOINT_DATA) {+				/* Right kind of block */+				dev->checkpointNextBlock = tags.objectId;+				dev->checkpointCurrentBlock = i;+				dev->checkpointBlockList[dev->blocksInCheckpoint] = i;+				dev->blocksInCheckpoint++;+				T(YAFFS_TRACE_CHECKPOINT, (TSTR("found checkpt block %d"TENDSTR), i));+				return;+			}+		}++	T(YAFFS_TRACE_CHECKPOINT, (TSTR("found no more checkpt blocks"TENDSTR)));++	dev->checkpointNextBlock = -1;+	dev->checkpointCurrentBlock = -1;+}+++int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting)+{++	/* Got the functions we need? */+	if (!dev->writeChunkWithTagsToNAND ||+			!dev->readChunkWithTagsFromNAND ||+			!dev->eraseBlockInNAND ||+			!dev->markNANDBlockBad)+		return 0;++	if (forWriting && !yaffs_CheckpointSpaceOk(dev))+		return 0;++	if (!dev->checkpointBuffer)+		dev->checkpointBuffer = YMALLOC_DMA(dev->totalBytesPerChunk);+	if (!dev->checkpointBuffer)+		return 0;+++	dev->checkpointPageSequence = 0;++	dev->checkpointOpenForWrite = forWriting;++	dev->checkpointByteCount = 0;+	dev->checkpointSum = 0;+	dev->checkpointXor = 0;+	dev->checkpointCurrentBlock = -1;+	dev->checkpointCurrentChunk = -1;+	dev->checkpointNextBlock = dev->internalStartBlock;++	/* Erase all the blocks in the checkpoint area */+	if (forWriting) {+		memset(dev->checkpointBuffer, 0, dev->nDataBytesPerChunk);+		dev->checkpointByteOffset = 0;+		return yaffs_CheckpointErase(dev);+	} else {+		int i;+		/* Set to a value that will kick off a read */+		dev->checkpointByteOffset = dev->nDataBytesPerChunk;+		/* A checkpoint block list of 1 checkpoint block per 16 block is (hopefully)+		 * going to be way more than we need */+		dev->blocksInCheckpoint = 0;+		dev->checkpointMaxBlocks = (dev->internalEndBlock - dev->internalStartBlock)/16 + 2;+		dev->checkpointBlockList = YMALLOC(sizeof(int) * dev->checkpointMaxBlocks);+		for (i = 0; i < dev->checkpointMaxBlocks; i++)+			dev->checkpointBlockList[i] = -1;+	}++	return 1;+}++int yaffs_GetCheckpointSum(yaffs_Device *dev, __u32 *sum)+{+	__u32 compositeSum;+	compositeSum =  (dev->checkpointSum << 8) | (dev->checkpointXor & 0xFF);+	*sum = compositeSum;+	return 1;+}++static int yaffs_CheckpointFlushBuffer(yaffs_Device *dev)+{+	int chunk;+	int realignedChunk;++	yaffs_ExtendedTags tags;++	if (dev->checkpointCurrentBlock < 0) {+		yaffs_CheckpointFindNextErasedBlock(dev);+		dev->checkpointCurrentChunk = 0;+	}++	if (dev->checkpointCurrentBlock < 0)+		return 0;++	tags.chunkDeleted = 0;+	tags.objectId = dev->checkpointNextBlock; /* Hint to next place to look */+	tags.chunkId = dev->checkpointPageSequence + 1;+	tags.sequenceNumber =  YAFFS_SEQUENCE_CHECKPOINT_DATA;+	tags.byteCount = dev->nDataBytesPerChunk;+	if (dev->checkpointCurrentChunk == 0) {+		/* First chunk we write for the block? Set block state to+		   checkpoint */+		yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, dev->checkpointCurrentBlock);+		bi->blockState = YAFFS_BLOCK_STATE_CHECKPOINT;+		dev->blocksInCheckpoint++;+	}++	chunk = dev->checkpointCurrentBlock * dev->nChunksPerBlock + dev->checkpointCurrentChunk;+++	T(YAFFS_TRACE_CHECKPOINT, (TSTR("checkpoint wite buffer nand %d(%d:%d) objid %d chId %d" TENDSTR),+		chunk, dev->checkpointCurrentBlock, dev->checkpointCurrentChunk, tags.objectId, tags.chunkId));++	realignedChunk = chunk - dev->chunkOffset;++	dev->writeChunkWithTagsToNAND(dev, realignedChunk,+			dev->checkpointBuffer, &tags);+	dev->checkpointByteOffset = 0;+	dev->checkpointPageSequence++;+	dev->checkpointCurrentChunk++;+	if (dev->checkpointCurrentChunk >= dev->nChunksPerBlock) {+		dev->checkpointCurrentChunk = 0;+		dev->checkpointCurrentBlock = -1;+	}+	memset(dev->checkpointBuffer, 0, dev->nDataBytesPerChunk);++	return 1;+}+++int yaffs_CheckpointWrite(yaffs_Device *dev, const void *data, int nBytes)+{+	int i = 0;+	int ok = 1;+++	__u8 * dataBytes = (__u8 *)data;++++	if (!dev->checkpointBuffer)+		return 0;++	if (!dev->checkpointOpenForWrite)+		return -1;++	while (i < nBytes && ok) {+		dev->checkpointBuffer[dev->checkpointByteOffset] = *dataBytes;+		dev->checkpointSum += *dataBytes;+		dev->checkpointXor ^= *dataBytes;++		dev->checkpointByteOffset++;+		i++;+		dataBytes++;+		dev->checkpointByteCount++;+++		if (dev->checkpointByteOffset < 0 ||+		   dev->checkpointByteOffset >= dev->nDataBytesPerChunk)+			ok = yaffs_CheckpointFlushBuffer(dev);+	}++	return i;+}++int yaffs_CheckpointRead(yaffs_Device *dev, void *data, int nBytes)+{+	int i = 0;+	int ok = 1;+	yaffs_ExtendedTags tags;+++	int chunk;+	int realignedChunk;++	__u8 *dataBytes = (__u8 *)data;++	if (!dev->checkpointBuffer)+		return 0;++	if (dev->checkpointOpenForWrite)+		return -1;++	while (i < nBytes && ok) {+++		if (dev->checkpointByteOffset < 0 ||+			dev->checkpointByteOffset >= dev->nDataBytesPerChunk) {++			if (dev->checkpointCurrentBlock < 0) {+				yaffs_CheckpointFindNextCheckpointBlock(dev);+				dev->checkpointCurrentChunk = 0;+			}++			if (dev->checkpointCurrentBlock < 0)+				ok = 0;+			else {+				chunk = dev->checkpointCurrentBlock *+					dev->nChunksPerBlock ++					dev->checkpointCurrentChunk;++				realignedChunk = chunk - dev->chunkOffset;++				/* read in the next chunk */+				/* printf("read checkpoint page %d\n",dev->checkpointPage); */+				dev->readChunkWithTagsFromNAND(dev,+						realignedChunk,+						dev->checkpointBuffer,+						&tags);++				if (tags.chunkId != (dev->checkpointPageSequence + 1) ||+					tags.eccResult > YAFFS_ECC_RESULT_FIXED ||+					tags.sequenceNumber != YAFFS_SEQUENCE_CHECKPOINT_DATA)+					ok = 0;++				dev->checkpointByteOffset = 0;+				dev->checkpointPageSequence++;+				dev->checkpointCurrentChunk++;++				if (dev->checkpointCurrentChunk >= dev->nChunksPerBlock)+					dev->checkpointCurrentBlock = -1;+			}+		}++		if (ok) {+			*dataBytes = dev->checkpointBuffer[dev->checkpointByteOffset];+			dev->checkpointSum += *dataBytes;+			dev->checkpointXor ^= *dataBytes;+			dev->checkpointByteOffset++;+			i++;+			dataBytes++;+			dev->checkpointByteCount++;+		}+	}++	return 	i;+}++int yaffs_CheckpointClose(yaffs_Device *dev)+{++	if (dev->checkpointOpenForWrite) {+		if (dev->checkpointByteOffset != 0)+			yaffs_CheckpointFlushBuffer(dev);+	} else {+		int i;+		for (i = 0; i < dev->blocksInCheckpoint && dev->checkpointBlockList[i] >= 0; i++) {+			yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, dev->checkpointBlockList[i]);+			if (bi->blockState == YAFFS_BLOCK_STATE_EMPTY)+				bi->blockState = YAFFS_BLOCK_STATE_CHECKPOINT;+			else {+				/* Todo this looks odd... */+			}+		}+		YFREE(dev->checkpointBlockList);+		dev->checkpointBlockList = NULL;+	}++	dev->nFreeChunks -= dev->blocksInCheckpoint * dev->nChunksPerBlock;+	dev->nErasedBlocks -= dev->blocksInCheckpoint;+++	T(YAFFS_TRACE_CHECKPOINT, (TSTR("checkpoint byte count %d" TENDSTR),+			dev->checkpointByteCount));++	if (dev->checkpointBuffer) {+		/* free the buffer */+		YFREE(dev->checkpointBuffer);+		dev->checkpointBuffer = NULL;+		return 1;+	} else+		return 0;+}++int yaffs_CheckpointInvalidateStream(yaffs_Device *dev)+{+	/* Erase the first checksum block */++	T(YAFFS_TRACE_CHECKPOINT, (TSTR("checkpoint invalidate"TENDSTR)));++	if (!yaffs_CheckpointSpaceOk(dev))+		return 0;++	return yaffs_CheckpointErase(dev);+}+++diff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_checkptrw.h linux-2.6.30/fs/yaffs2/yaffs_checkptrw.h--- linux-2.6.30.orig/fs/yaffs2/yaffs_checkptrw.h	1970-01-01 01:00:00.000000000 +0100+++ linux-2.6.30/fs/yaffs2/yaffs_checkptrw.h	2009-06-11 09:21:04.000000000 +0200@@ -0,0 +1,35 @@+/*+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.+ *+ * Copyright (C) 2002-2007 Aleph One Ltd.+ *   for Toby Churchill Ltd and Brightstar Engineering+ *+ * Created by Charles Manning <charles@aleph1.co.uk>+ *+ * This program is free software; you can redistribute it and/or modify+ * it under the terms of the GNU Lesser General Public License version 2.1 as+ * published by the Free Software Foundation.+ *+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.+ */++#ifndef __YAFFS_CHECKPTRW_H__+#define __YAFFS_CHECKPTRW_H__++#include "yaffs_guts.h"++int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting);++int yaffs_CheckpointWrite(yaffs_Device *dev, const void *data, int nBytes);++int yaffs_CheckpointRead(yaffs_Device *dev, void *data, int nBytes);++int yaffs_GetCheckpointSum(yaffs_Device *dev, __u32 *sum);++int yaffs_CheckpointClose(yaffs_Device *dev);++int yaffs_CheckpointInvalidateStream(yaffs_Device *dev);+++#endif+diff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_ecc.c linux-2.6.30/fs/yaffs2/yaffs_ecc.c--- linux-2.6.30.orig/fs/yaffs2/yaffs_ecc.c	1970-01-01 01:00:00.000000000 +0100+++ linux-2.6.30/fs/yaffs2/yaffs_ecc.c	2009-06-11 09:21:04.000000000 +0200@@ -0,0 +1,326 @@+/*+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.+ *+ * Copyright (C) 2002-2007 Aleph One Ltd.+ *   for Toby Churchill Ltd and Brightstar Engineering+ *+ * Created by Charles Manning <charles@aleph1.co.uk>+ *+ * This program is free software; you can redistribute it and/or modify+ * it under the terms of the GNU General Public License version 2 as+ * published by the Free Software Foundation.+ */++/*+ * This code implements the ECC algorithm used in SmartMedia.+ *+ * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes.+ * The two unused bit are set to 1.+ * The ECC can correct single bit errors in a 256-byte page of data. Thus, two such ECC+ * blocks are used on a 512-byte NAND page.+ *+ */++/* Table generated by gen-ecc.c+ * Using a table means we do not have to calculate p1..p4 and p1'..p4'+ * for each byte of data. These are instead provided in a table in bits7..2.+ * Bit 0 of each entry indicates whether the entry has an odd or even parity, and therefore+ * this bytes influence on the line parity.+ */++const char *yaffs_ecc_c_version =+	"$Id: yaffs_ecc.c,v 1.11 2009-03-06 17:20:50 wookey Exp $";++#include "yportenv.h"++#include "yaffs_ecc.h"++static const unsigned char column_parity_table[] = {+	0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69,+	0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00,+	0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc,+	0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95,+	0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0,+	0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99,+	0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65,+	0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c,+	0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc,+	0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5,+	0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59,+	0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30,+	0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55,+	0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c,+	0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0,+	0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9,+	0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0,+	0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9,+	0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55,+	0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c,+	0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59,+	0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30,+	0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc,+	0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5,+	0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65,+	0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c,+	0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0,+	0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99,+	0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc,+	0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95,+	0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69,+	0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00,+};++/* Count the bits in an unsigned char or a U32 */++static int yaffs_CountBits(unsigned char x)+{+	int r = 0;+	while (x) {+		if (x & 1)+			r++;+		x >>= 1;+	}+	return r;+}++static int yaffs_CountBits32(unsigned x)+{+	int r = 0;+	while (x) {+		if (x & 1)+			r++;+		x >>= 1;+	}+	return r;+}++/* Calculate the ECC for a 256-byte block of data */+void yaffs_ECCCalculate(const unsigned char *data, unsigned char *ecc)+{+	unsigned int i;++	unsigned char col_parity = 0;+	unsigned char line_parity = 0;+	unsigned char line_parity_prime = 0;+	unsigned char t;+	unsigned char b;++	for (i = 0; i < 256; i++) {+		b = column_parity_table[*data++];+		col_parity ^= b;++		if (b & 0x01) {		/* odd number of bits in the byte */+			line_parity ^= i;+			line_parity_prime ^= ~i;+		}+	}++	ecc[2] = (~col_parity) | 0x03;++	t = 0;+	if (line_parity & 0x80)+		t |= 0x80;+	if (line_parity_prime & 0x80)+		t |= 0x40;+	if (line_parity & 0x40)+		t |= 0x20;+	if (line_parity_prime & 0x40)+		t |= 0x10;+	if (line_parity & 0x20)+		t |= 0x08;+	if (line_parity_prime & 0x20)+		t |= 0x04;+	if (line_parity & 0x10)+		t |= 0x02;+	if (line_parity_prime & 0x10)+		t |= 0x01;+	ecc[1] = ~t;++	t = 0;+	if (line_parity & 0x08)+		t |= 0x80;+	if (line_parity_prime & 0x08)+		t |= 0x40;+	if (line_parity & 0x04)+		t |= 0x20;+	if (line_parity_prime & 0x04)+		t |= 0x10;+	if (line_parity & 0x02)+		t |= 0x08;+	if (line_parity_prime & 0x02)+		t |= 0x04;+	if (line_parity & 0x01)+		t |= 0x02;+	if (line_parity_prime & 0x01)+		t |= 0x01;+	ecc[0] = ~t;++#ifdef CONFIG_YAFFS_ECC_WRONG_ORDER+	/* Swap the bytes into the wrong order */+	t = ecc[0];+	ecc[0] = ecc[1];+	ecc[1] = t;+#endif+}+++/* Correct the ECC on a 256 byte block of data */++int yaffs_ECCCorrect(unsigned char *data, unsigned char *read_ecc,+		     const unsigned char *test_ecc)+{+	unsigned char d0, d1, d2;	/* deltas */++	d0 = read_ecc[0] ^ test_ecc[0];+	d1 = read_ecc[1] ^ test_ecc[1];+	d2 = read_ecc[2] ^ test_ecc[2];++	if ((d0 | d1 | d2) == 0)+		return 0; /* no error */++	if (((d0 ^ (d0 >> 1)) & 0x55) == 0x55 &&+	    ((d1 ^ (d1 >> 1)) & 0x55) == 0x55 &&+	    ((d2 ^ (d2 >> 1)) & 0x54) == 0x54) {+		/* Single bit (recoverable) error in data */++		unsigned byte;+		unsigned bit;++#ifdef CONFIG_YAFFS_ECC_WRONG_ORDER+		/* swap the bytes to correct for the wrong order */+		unsigned char t;++		t = d0;+		d0 = d1;+		d1 = t;+#endif++		bit = byte = 0;++		if (d1 & 0x80)+			byte |= 0x80;+		if (d1 & 0x20)+			byte |= 0x40;+		if (d1 & 0x08)+			byte |= 0x20;+		if (d1 & 0x02)+			byte |= 0x10;+		if (d0 & 0x80)+			byte |= 0x08;+		if (d0 & 0x20)+			byte |= 0x04;+		if (d0 & 0x08)+			byte |= 0x02;+		if (d0 & 0x02)+			byte |= 0x01;++		if (d2 & 0x80)+			bit |= 0x04;+		if (d2 & 0x20)+			bit |= 0x02;+		if (d2 & 0x08)+			bit |= 0x01;++		data[byte] ^= (1 << bit);++		return 1; /* Corrected the error */+	}++	if ((yaffs_CountBits(d0) ++	     yaffs_CountBits(d1) ++	     yaffs_CountBits(d2)) ==  1) {+		/* Reccoverable error in ecc */++		read_ecc[0] = test_ecc[0];+		read_ecc[1] = test_ecc[1];+		read_ecc[2] = test_ecc[2];++		return 1; /* Corrected the error */+	}++	/* Unrecoverable error */++	return -1;++}+++/*+ * ECCxxxOther does ECC calcs on arbitrary n bytes of data+ */+void yaffs_ECCCalculateOther(const unsigned char *data, unsigned nBytes,+				yaffs_ECCOther *eccOther)+{+	unsigned int i;++	unsigned char col_parity = 0;+	unsigned line_parity = 0;+	unsigned line_parity_prime = 0;+	unsigned char b;++	for (i = 0; i < nBytes; i++) {+		b = column_parity_table[*data++];+		col_parity ^= b;++		if (b & 0x01)	 {+			/* odd number of bits in the byte */+			line_parity ^= i;+			line_parity_prime ^= ~i;+		}++	}++	eccOther->colParity = (col_parity >> 2) & 0x3f;+	eccOther->lineParity = line_parity;+	eccOther->lineParityPrime = line_parity_prime;+}++int yaffs_ECCCorrectOther(unsigned char *data, unsigned nBytes,+			yaffs_ECCOther *read_ecc,+			const yaffs_ECCOther *test_ecc)+{+	unsigned char cDelta;	/* column parity delta */+	unsigned lDelta;	/* line parity delta */+	unsigned lDeltaPrime;	/* line parity delta */+	unsigned bit;++	cDelta = read_ecc->colParity ^ test_ecc->colParity;+	lDelta = read_ecc->lineParity ^ test_ecc->lineParity;+	lDeltaPrime = read_ecc->lineParityPrime ^ test_ecc->lineParityPrime;++	if ((cDelta | lDelta | lDeltaPrime) == 0)+		return 0; /* no error */++	if (lDelta == ~lDeltaPrime &&+	    (((cDelta ^ (cDelta >> 1)) & 0x15) == 0x15)) {+		/* Single bit (recoverable) error in data */++		bit = 0;++		if (cDelta & 0x20)+			bit |= 0x04;+		if (cDelta & 0x08)+			bit |= 0x02;+		if (cDelta & 0x02)+			bit |= 0x01;++		if (lDelta >= nBytes)+			return -1;++		data[lDelta] ^= (1 << bit);++		return 1; /* corrected */+	}++	if ((yaffs_CountBits32(lDelta) + yaffs_CountBits32(lDeltaPrime) ++			yaffs_CountBits(cDelta)) == 1) {+		/* Reccoverable error in ecc */++		*read_ecc = *test_ecc;+		return 1; /* corrected */+	}++	/* Unrecoverable error */++	return -1;+}diff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_ecc.h linux-2.6.30/fs/yaffs2/yaffs_ecc.h--- linux-2.6.30.orig/fs/yaffs2/yaffs_ecc.h	1970-01-01 01:00:00.000000000 +0100+++ linux-2.6.30/fs/yaffs2/yaffs_ecc.h	2009-06-11 09:21:04.000000000 +0200@@ -0,0 +1,44 @@+/*+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.+ *+ * Copyright (C) 2002-2007 Aleph One Ltd.+ *   for Toby Churchill Ltd and Brightstar Engineering+ *+ * Created by Charles Manning <charles@aleph1.co.uk>+ *+ * This program is free software; you can redistribute it and/or modify+ * it under the terms of the GNU Lesser General Public License version 2.1 as+ * published by the Free Software Foundation.+ *+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.+ */++/*+ * This code implements the ECC algorithm used in SmartMedia.+ *+ * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes.+ * The two unused bit are set to 1.+ * The ECC can correct single bit errors in a 256-byte page of data. Thus, two such ECC+ * blocks are used on a 512-byte NAND page.+ *+ */++#ifndef __YAFFS_ECC_H__+#define __YAFFS_ECC_H__++typedef struct {+	unsigned char colParity;+	unsigned lineParity;+	unsigned lineParityPrime;+} yaffs_ECCOther;++void yaffs_ECCCalculate(const unsigned char *data, unsigned char *ecc);+int yaffs_ECCCorrect(unsigned char *data, unsigned char *read_ecc,+		const unsigned char *test_ecc);++void yaffs_ECCCalculateOther(const unsigned char *data, unsigned nBytes,+			yaffs_ECCOther *ecc);+int yaffs_ECCCorrectOther(unsigned char *data, unsigned nBytes,+			yaffs_ECCOther *read_ecc,+			const yaffs_ECCOther *test_ecc);+#endifdiff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_fs.c linux-2.6.30/fs/yaffs2/yaffs_fs.c--- linux-2.6.30.orig/fs/yaffs2/yaffs_fs.c	1970-01-01 01:00:00.000000000 +0100+++ linux-2.6.30/fs/yaffs2/yaffs_fs.c	2009-06-11 09:21:04.000000000 +0200@@ -0,0 +1,2529 @@+/*+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.+ *+ * Copyright (C) 2002-2009 Aleph One Ltd.+ *   for Toby Churchill Ltd and Brightstar Engineering+ *+ * Created by Charles Manning <charles@aleph1.co.uk>+ * Acknowledgements:+ * Luc van OostenRyck for numerous patches.+ * Nick Bane for numerous patches.+ * Nick Bane for 2.5/2.6 integration.+ * Andras Toth for mknod rdev issue.+ * Michael Fischer for finding the problem with inode inconsistency.+ * Some code bodily lifted from JFFS+ *+ * This program is free software; you can redistribute it and/or modify+ * it under the terms of the GNU General Public License version 2 as+ * published by the Free Software Foundation.+ */++/*+ *+ * This is the file system front-end to YAFFS that hooks it up to+ * the VFS.+ *+ * Special notes:+ * >> 2.4: sb->u.generic_sbp points to the yaffs_Device associated with+ *         this superblock+ * >> 2.6: sb->s_fs_info  points to the yaffs_Device associated with this+ *         superblock+ * >> inode->u.generic_ip points to the associated yaffs_Object.+ */++const char *yaffs_fs_c_version =+    "$Id: yaffs_fs.c,v 1.79 2009-03-17 01:12:00 wookey Exp $";+extern const char *yaffs_guts_c_version;++#include <linux/version.h>+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))+#include <linux/config.h>+#endif+#include <linux/kernel.h>+#include <linux/module.h>+#include <linux/slab.h>+#include <linux/init.h>+#include <linux/fs.h>+#include <linux/proc_fs.h>+#include <linux/smp_lock.h>+#include <linux/pagemap.h>+#include <linux/mtd/mtd.h>+#include <linux/interrupt.h>+#include <linux/string.h>+#include <linux/ctype.h>++#include "asm/div64.h"++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))++#include <linux/statfs.h>	/* Added NCB 15-8-2003 */+#include <linux/statfs.h>+#define UnlockPage(p) unlock_page(p)+#define Page_Uptodate(page)	test_bit(PG_uptodate, &(page)->flags)++/* FIXME: use sb->s_id instead ? */+#define yaffs_devname(sb, buf)	bdevname(sb->s_bdev, buf)++#else++#include <linux/locks.h>+#define	BDEVNAME_SIZE		0+#define	yaffs_devname(sb, buf)	kdevname(sb->s_dev)++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0))+/* added NCB 26/5/2006 for 2.4.25-vrs2-tcl1 kernel */+#define __user+#endif++#endif++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26))+#define YPROC_ROOT  (&proc_root)+#else+#define YPROC_ROOT  NULL+#endif++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))+#define WRITE_SIZE_STR "writesize"+#define WRITE_SIZE(mtd) ((mtd)->writesize)+#else+#define WRITE_SIZE_STR "oobblock"+#define WRITE_SIZE(mtd) ((mtd)->oobblock)+#endif++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 27))+#define YAFFS_USE_WRITE_BEGIN_END 1+#else+#define YAFFS_USE_WRITE_BEGIN_END 0+#endif++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 28))+static uint32_t YCALCBLOCKS(uint64_t partition_size, uint32_t block_size)+{+	uint64_t result = partition_size;+	do_div(result, block_size);+	return (uint32_t)result;+}+#else+#define YCALCBLOCKS(s, b) ((s)/(b))+#endif++#include <linux/uaccess.h>++#include "yportenv.h"+#include "yaffs_guts.h"++#include <linux/mtd/mtd.h>+#include "yaffs_mtdif.h"+#include "yaffs_mtdif1.h"+#include "yaffs_mtdif2.h"++unsigned int yaffs_traceMask = YAFFS_TRACE_BAD_BLOCKS;+unsigned int yaffs_wr_attempts = YAFFS_WR_ATTEMPTS;+unsigned int yaffs_auto_checkpoint = 1;++/* Module Parameters */+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))+module_param(yaffs_traceMask, uint, 0644);+module_param(yaffs_wr_attempts, uint, 0644);+module_param(yaffs_auto_checkpoint, uint, 0644);+#else+MODULE_PARM(yaffs_traceMask, "i");+MODULE_PARM(yaffs_wr_attempts, "i");+MODULE_PARM(yaffs_auto_checkpoint, "i");+#endif++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25))+/* use iget and read_inode */+#define Y_IGET(sb, inum) iget((sb), (inum))+static void yaffs_read_inode(struct inode *inode);++#else+/* Call local equivalent */+#define YAFFS_USE_OWN_IGET+#define Y_IGET(sb, inum) yaffs_iget((sb), (inum))++static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino);+#endif++/*#define T(x) printk x */++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18))+#define yaffs_InodeToObjectLV(iptr) ((iptr)->i_private)+#else+#define yaffs_InodeToObjectLV(iptr) ((iptr)->u.generic_ip)+#endif++#define yaffs_InodeToObject(iptr) ((yaffs_Object *)(yaffs_InodeToObjectLV(iptr)))+#define yaffs_DentryToObject(dptr) yaffs_InodeToObject((dptr)->d_inode)++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))+#define yaffs_SuperToDevice(sb)	((yaffs_Device *)sb->s_fs_info)+#else+#define yaffs_SuperToDevice(sb)	((yaffs_Device *)sb->u.generic_sbp)+#endif++static void yaffs_put_super(struct super_block *sb);++static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,+				loff_t *pos);+static ssize_t yaffs_hold_space(struct file *f);+static void yaffs_release_space(struct file *f);++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))+static int yaffs_file_flush(struct file *file, fl_owner_t id);+#else+static int yaffs_file_flush(struct file *file);+#endif++static int yaffs_sync_object(struct file *file, struct dentry *dentry,+				int datasync);++static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir);++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))+static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode,+			struct nameidata *n);+static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,+					struct nameidata *n);+#else+static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode);+static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry);+#endif+static int yaffs_link(struct dentry *old_dentry, struct inode *dir,+			struct dentry *dentry);+static int yaffs_unlink(struct inode *dir, struct dentry *dentry);+static int yaffs_symlink(struct inode *dir, struct dentry *dentry,+			const char *symname);+static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode);++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))+static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,+			dev_t dev);+#else+static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,+			int dev);+#endif+static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry,+			struct inode *new_dir, struct dentry *new_dentry);+static int yaffs_setattr(struct dentry *dentry, struct iattr *attr);++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))+static int yaffs_sync_fs(struct super_block *sb, int wait);+static void yaffs_write_super(struct super_block *sb);+#else+static int yaffs_sync_fs(struct super_block *sb);+static int yaffs_write_super(struct super_block *sb);+#endif++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))+static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf);+#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))+static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf);+#else+static int yaffs_statfs(struct super_block *sb, struct statfs *buf);+#endif++#ifdef YAFFS_HAS_PUT_INODE+static void yaffs_put_inode(struct inode *inode);+#endif++static void yaffs_delete_inode(struct inode *);+static void yaffs_clear_inode(struct inode *);++static int yaffs_readpage(struct file *file, struct page *page);+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))+static int yaffs_writepage(struct page *page, struct writeback_control *wbc);+#else+static int yaffs_writepage(struct page *page);+#endif+++#if (YAFFS_USE_WRITE_BEGIN_END != 0)+static int yaffs_write_begin(struct file *filp, struct address_space *mapping,+				loff_t pos, unsigned len, unsigned flags,+				struct page **pagep, void **fsdata);+static int yaffs_write_end(struct file *filp, struct address_space *mapping,+				loff_t pos, unsigned len, unsigned copied,+				struct page *pg, void *fsdadata);+#else+static int yaffs_prepare_write(struct file *f, struct page *pg,+				unsigned offset, unsigned to);+static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset,+				unsigned to);++#endif++static int yaffs_readlink(struct dentry *dentry, char __user *buffer,+				int buflen);+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))+static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd);+#else+static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd);+#endif++static struct address_space_operations yaffs_file_address_operations = {+	.readpage = yaffs_readpage,+	.writepage = yaffs_writepage,+#if (YAFFS_USE_WRITE_BEGIN_END > 0)+	.write_begin = yaffs_write_begin,+	.write_end = yaffs_write_end,+#else+	.prepare_write = yaffs_prepare_write,+	.commit_write = yaffs_commit_write,+#endif+};++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22))+static const struct file_operations yaffs_file_operations = {+	.read = do_sync_read,+	.write = do_sync_write,+	.aio_read = generic_file_aio_read,+	.aio_write = generic_file_aio_write,+	.mmap = generic_file_mmap,+	.flush = yaffs_file_flush,+	.fsync = yaffs_sync_object,+	.splice_read = generic_file_splice_read,+	.splice_write = generic_file_splice_write,+	.llseek = generic_file_llseek,+};++#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18))++static const struct file_operations yaffs_file_operations = {+	.read = do_sync_read,+	.write = do_sync_write,+	.aio_read = generic_file_aio_read,+	.aio_write = generic_file_aio_write,+	.mmap = generic_file_mmap,+	.flush = yaffs_file_flush,+	.fsync = yaffs_sync_object,+	.sendfile = generic_file_sendfile,+};++#else++static const struct file_operations yaffs_file_operations = {+	.read = generic_file_read,+	.write = generic_file_write,+	.mmap = generic_file_mmap,+	.flush = yaffs_file_flush,+	.fsync = yaffs_sync_object,+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))+	.sendfile = generic_file_sendfile,+#endif+};+#endif++static const struct inode_operations yaffs_file_inode_operations = {+	.setattr = yaffs_setattr,+};++static const struct inode_operations yaffs_symlink_inode_operations = {+	.readlink = yaffs_readlink,+	.follow_link = yaffs_follow_link,+	.setattr = yaffs_setattr,+};++static const struct inode_operations yaffs_dir_inode_operations = {+	.create = yaffs_create,+	.lookup = yaffs_lookup,+	.link = yaffs_link,+	.unlink = yaffs_unlink,+	.symlink = yaffs_symlink,+	.mkdir = yaffs_mkdir,+	.rmdir = yaffs_unlink,+	.mknod = yaffs_mknod,+	.rename = yaffs_rename,+	.setattr = yaffs_setattr,+};++static const struct file_operations yaffs_dir_operations = {+	.read = generic_read_dir,+	.readdir = yaffs_readdir,+	.fsync = yaffs_sync_object,+};++static const struct super_operations yaffs_super_ops = {+	.statfs = yaffs_statfs,++#ifndef YAFFS_USE_OWN_IGET+	.read_inode = yaffs_read_inode,+#endif+#ifdef YAFFS_HAS_PUT_INODE+	.put_inode = yaffs_put_inode,+#endif+	.put_super = yaffs_put_super,+	.delete_inode = yaffs_delete_inode,+	.clear_inode = yaffs_clear_inode,+	.sync_fs = yaffs_sync_fs,+	.write_super = yaffs_write_super,+};++static void yaffs_GrossLock(yaffs_Device *dev)+{+	T(YAFFS_TRACE_OS, ("yaffs locking %p\n", current));+	down(&dev->grossLock);+	T(YAFFS_TRACE_OS, ("yaffs locked %p\n", current));+}++static void yaffs_GrossUnlock(yaffs_Device *dev)+{+	T(YAFFS_TRACE_OS, ("yaffs unlocking %p\n", current));+	up(&dev->grossLock);+}++static int yaffs_readlink(struct dentry *dentry, char __user *buffer,+			int buflen)+{+	unsigned char *alias;+	int ret;++	yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev;++	yaffs_GrossLock(dev);++	alias = yaffs_GetSymlinkAlias(yaffs_DentryToObject(dentry));++	yaffs_GrossUnlock(dev);++	if (!alias)+		return -ENOMEM;++	ret = vfs_readlink(dentry, buffer, buflen, alias);+	kfree(alias);+	return ret;+}++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))+static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)+#else+static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)+#endif+{+	unsigned char *alias;+	int ret;+	yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev;++	yaffs_GrossLock(dev);++	alias = yaffs_GetSymlinkAlias(yaffs_DentryToObject(dentry));++	yaffs_GrossUnlock(dev);++	if (!alias) {+		ret = -ENOMEM;+		goto out;+	}++	ret = vfs_follow_link(nd, alias);+	kfree(alias);+out:+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))+	return ERR_PTR(ret);+#else+	return ret;+#endif+}++struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev,+				yaffs_Object *obj);++/*+ * Lookup is used to find objects in the fs+ */+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))++static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,+				struct nameidata *n)+#else+static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry)+#endif+{+	yaffs_Object *obj;+	struct inode *inode = NULL;	/* NCB 2.5/2.6 needs NULL here */++	yaffs_Device *dev = yaffs_InodeToObject(dir)->myDev;++	yaffs_GrossLock(dev);++	T(YAFFS_TRACE_OS,+		("yaffs_lookup for %d:%s\n",+		yaffs_InodeToObject(dir)->objectId, dentry->d_name.name));++	obj = yaffs_FindObjectByName(yaffs_InodeToObject(dir),+					dentry->d_name.name);++	obj = yaffs_GetEquivalentObject(obj);	/* in case it was a hardlink */++	/* Can't hold gross lock when calling yaffs_get_inode() */+	yaffs_GrossUnlock(dev);++	if (obj) {+		T(YAFFS_TRACE_OS,+			("yaffs_lookup found %d\n", obj->objectId));++		inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);++		if (inode) {+			T(YAFFS_TRACE_OS,+				("yaffs_loookup dentry \n"));+/* #if 0 asserted by NCB for 2.5/6 compatability - falls through to+ * d_add even if NULL inode */+#if 0+			/*dget(dentry); // try to solve directory bug */+			d_add(dentry, inode);++			/* return dentry; */+			return NULL;+#endif+		}++	} else {+		T(YAFFS_TRACE_OS, ("yaffs_lookup not found\n"));++	}++/* added NCB for 2.5/6 compatability - forces add even if inode is+ * NULL which creates dentry hash */+	d_add(dentry, inode);++	return NULL;+}+++#ifdef YAFFS_HAS_PUT_INODE++/* For now put inode is just for debugging+ * Put inode is called when the inode **structure** is put.+ */+static void yaffs_put_inode(struct inode *inode)+{+	T(YAFFS_TRACE_OS,+		("yaffs_put_inode: ino %d, count %d\n", (int)inode->i_ino,+		atomic_read(&inode->i_count)));++}+#endif++/* clear is called to tell the fs to release any per-inode data it holds */+static void yaffs_clear_inode(struct inode *inode)+{+	yaffs_Object *obj;+	yaffs_Device *dev;++	obj = yaffs_InodeToObject(inode);++	T(YAFFS_TRACE_OS,+		("yaffs_clear_inode: ino %d, count %d %s\n", (int)inode->i_ino,+		atomic_read(&inode->i_count),+		obj ? "object exists" : "null object"));++	if (obj) {+		dev = obj->myDev;+		yaffs_GrossLock(dev);++		/* Clear the association between the inode and+		 * the yaffs_Object.+		 */+		obj->myInode = NULL;+		yaffs_InodeToObjectLV(inode) = NULL;++		/* If the object freeing was deferred, then the real+		 * free happens now.+		 * This should fix the inode inconsistency problem.+		 */++		yaffs_HandleDeferedFree(obj);++		yaffs_GrossUnlock(dev);+	}++}++/* delete is called when the link count is zero and the inode+ * is put (ie. nobody wants to know about it anymore, time to+ * delete the file).+ * NB Must call clear_inode()+ */+static void yaffs_delete_inode(struct inode *inode)+{+	yaffs_Object *obj = yaffs_InodeToObject(inode);+	yaffs_Device *dev;++	T(YAFFS_TRACE_OS,+		("yaffs_delete_inode: ino %d, count %d %s\n", (int)inode->i_ino,+		atomic_read(&inode->i_count),+		obj ? "object exists" : "null object"));++	if (obj) {+		dev = obj->myDev;+		yaffs_GrossLock(dev);+		yaffs_DeleteObject(obj);+		yaffs_GrossUnlock(dev);+	}+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))+	truncate_inode_pages(&inode->i_data, 0);+#endif+	clear_inode(inode);+}++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))+static int yaffs_file_flush(struct file *file, fl_owner_t id)+#else+static int yaffs_file_flush(struct file *file)+#endif+{+	yaffs_Object *obj = yaffs_DentryToObject(file->f_dentry);++	yaffs_Device *dev = obj->myDev;++	T(YAFFS_TRACE_OS,+		("yaffs_file_flush object %d (%s)\n", obj->objectId,+		obj->dirty ? "dirty" : "clean"));++	yaffs_GrossLock(dev);++	yaffs_FlushFile(obj, 1);++	yaffs_GrossUnlock(dev);++	return 0;+}++static int yaffs_readpage_nolock(struct file *f, struct page *pg)+{+	/* Lifted from jffs2 */++	yaffs_Object *obj;+	unsigned char *pg_buf;+	int ret;++	yaffs_Device *dev;++	T(YAFFS_TRACE_OS, ("yaffs_readpage at %08x, size %08x\n",+			(unsigned)(pg->index << PAGE_CACHE_SHIFT),+			(unsigned)PAGE_CACHE_SIZE));++	obj = yaffs_DentryToObject(f->f_dentry);++	dev = obj->myDev;++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))+	BUG_ON(!PageLocked(pg));+#else+	if (!PageLocked(pg))+		PAGE_BUG(pg);+#endif++	pg_buf = kmap(pg);+	/* FIXME: Can kmap fail? */++	yaffs_GrossLock(dev);++	ret = yaffs_ReadDataFromFile(obj, pg_buf,+				pg->index << PAGE_CACHE_SHIFT,+				PAGE_CACHE_SIZE);++	yaffs_GrossUnlock(dev);++	if (ret >= 0)+		ret = 0;++	if (ret) {+		ClearPageUptodate(pg);+		SetPageError(pg);+	} else {+		SetPageUptodate(pg);+		ClearPageError(pg);+	}++	flush_dcache_page(pg);+	kunmap(pg);++	T(YAFFS_TRACE_OS, ("yaffs_readpage done\n"));+	return ret;+}++static int yaffs_readpage_unlock(struct file *f, struct page *pg)+{+	int ret = yaffs_readpage_nolock(f, pg);+	UnlockPage(pg);+	return ret;+}++static int yaffs_readpage(struct file *f, struct page *pg)+{+	return yaffs_readpage_unlock(f, pg);+}++/* writepage inspired by/stolen from smbfs */++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))+static int yaffs_writepage(struct page *page, struct writeback_control *wbc)+#else+static int yaffs_writepage(struct page *page)+#endif+{+	struct address_space *mapping = page->mapping;+	loff_t offset = (loff_t) page->index << PAGE_CACHE_SHIFT;+	struct inode *inode;+	unsigned long end_index;+	char *buffer;+	yaffs_Object *obj;+	int nWritten = 0;+	unsigned nBytes;++	if (!mapping)+		BUG();+	inode = mapping->host;+	if (!inode)+		BUG();++	if (offset > inode->i_size) {+		T(YAFFS_TRACE_OS,+			("yaffs_writepage at %08x, inode size = %08x!!!\n",+			(unsigned)(page->index << PAGE_CACHE_SHIFT),+			(unsigned)inode->i_size));+		T(YAFFS_TRACE_OS,+			("                -> don't care!!\n"));+		unlock_page(page);+		return 0;+	}++	end_index = inode->i_size >> PAGE_CACHE_SHIFT;++	/* easy case */+	if (page->index < end_index)+		nBytes = PAGE_CACHE_SIZE;+	else+		nBytes = inode->i_size & (PAGE_CACHE_SIZE - 1);++	get_page(page);++	buffer = kmap(page);++	obj = yaffs_InodeToObject(inode);+	yaffs_GrossLock(obj->myDev);++	T(YAFFS_TRACE_OS,+		("yaffs_writepage at %08x, size %08x\n",+		(unsigned)(page->index << PAGE_CACHE_SHIFT), nBytes));+	T(YAFFS_TRACE_OS,+		("writepag0: obj = %05x, ino = %05x\n",+		(int)obj->variant.fileVariant.fileSize, (int)inode->i_size));++	nWritten = yaffs_WriteDataToFile(obj, buffer,+			page->index << PAGE_CACHE_SHIFT, nBytes, 0);++	T(YAFFS_TRACE_OS,+		("writepag1: obj = %05x, ino = %05x\n",+		(int)obj->variant.fileVariant.fileSize, (int)inode->i_size));++	yaffs_GrossUnlock(obj->myDev);++	kunmap(page);+	SetPageUptodate(page);+	UnlockPage(page);+	put_page(page);++	return (nWritten == nBytes) ? 0 : -ENOSPC;+}+++#if (YAFFS_USE_WRITE_BEGIN_END > 0)+static int yaffs_write_begin(struct file *filp, struct address_space *mapping,+				loff_t pos, unsigned len, unsigned flags,+				struct page **pagep, void **fsdata)+{+	struct page *pg = NULL;+	pgoff_t index = pos >> PAGE_CACHE_SHIFT;+	uint32_t offset = pos & (PAGE_CACHE_SIZE - 1);+	uint32_t to = offset + len;++	int ret = 0;+	int space_held = 0;++	T(YAFFS_TRACE_OS, ("start yaffs_write_begin\n"));+	/* Get a page */+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 28)+	pg = grab_cache_page_write_begin(mapping, index, flags);+#else+	pg = __grab_cache_page(mapping, index);+#endif++	*pagep = pg;+	if (!pg) {+		ret =  -ENOMEM;+		goto out;+	}+	/* Get fs space */+	space_held = yaffs_hold_space(filp);++	if (!space_held) {+		ret = -ENOSPC;+		goto out;+	}++	/* Update page if required */++	if (!Page_Uptodate(pg) && (offset || to < PAGE_CACHE_SIZE))+		ret = yaffs_readpage_nolock(filp, pg);++	if (ret)+		goto out;++	/* Happy path return */+	T(YAFFS_TRACE_OS, ("end yaffs_write_begin - ok\n"));++	return 0;++out:+	T(YAFFS_TRACE_OS, ("end yaffs_write_begin fail returning %d\n", ret));+	if (space_held)+		yaffs_release_space(filp);+	if (pg) {+		unlock_page(pg);+		page_cache_release(pg);+	}+	return ret;+}++#else++static int yaffs_prepare_write(struct file *f, struct page *pg,+				unsigned offset, unsigned to)+{+	T(YAFFS_TRACE_OS, ("yaffs_prepair_write\n"));++	if (!Page_Uptodate(pg) && (offset || to < PAGE_CACHE_SIZE))+		return yaffs_readpage_nolock(f, pg);+	return 0;+}+#endif++#if (YAFFS_USE_WRITE_BEGIN_END > 0)+static int yaffs_write_end(struct file *filp, struct address_space *mapping,+				loff_t pos, unsigned len, unsigned copied,+				struct page *pg, void *fsdadata)+{+	int ret = 0;+	void *addr, *kva;+	uint32_t offset_into_page = pos & (PAGE_CACHE_SIZE - 1);++	kva = kmap(pg);+	addr = kva + offset_into_page;++	T(YAFFS_TRACE_OS,+		("yaffs_write_end addr %x pos %x nBytes %d\n",+		(unsigned) addr,+		(int)pos, copied));++	ret = yaffs_file_write(filp, addr, copied, &pos);++	if (ret != copied) {+		T(YAFFS_TRACE_OS,+			("yaffs_write_end not same size ret %d  copied %d\n",+			ret, copied));+		SetPageError(pg);+		ClearPageUptodate(pg);+	} else {+		SetPageUptodate(pg);+	}++	kunmap(pg);++	yaffs_release_space(filp);+	unlock_page(pg);+	page_cache_release(pg);+	return ret;+}+#else++static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset,+				unsigned to)+{+	void *addr, *kva;++	loff_t pos = (((loff_t) pg->index) << PAGE_CACHE_SHIFT) + offset;+	int nBytes = to - offset;+	int nWritten;++	unsigned spos = pos;+	unsigned saddr;++	kva = kmap(pg);+	addr = kva + offset;++	saddr = (unsigned) addr;++	T(YAFFS_TRACE_OS,+		("yaffs_commit_write addr %x pos %x nBytes %d\n",+		saddr, spos, nBytes));++	nWritten = yaffs_file_write(f, addr, nBytes, &pos);++	if (nWritten != nBytes) {+		T(YAFFS_TRACE_OS,+			("yaffs_commit_write not same size nWritten %d  nBytes %d\n",+			nWritten, nBytes));+		SetPageError(pg);+		ClearPageUptodate(pg);+	} else {+		SetPageUptodate(pg);+	}++	kunmap(pg);++	T(YAFFS_TRACE_OS,+		("yaffs_commit_write returning %d\n",+		nWritten == nBytes ? 0 : nWritten));++	return nWritten == nBytes ? 0 : nWritten;+}+#endif+++static void yaffs_FillInodeFromObject(struct inode *inode, yaffs_Object *obj)+{+	if (inode && obj) {+++		/* Check mode against the variant type and attempt to repair if broken. */+		__u32 mode = obj->yst_mode;+		switch (obj->variantType) {+		case YAFFS_OBJECT_TYPE_FILE:+			if (!S_ISREG(mode)) {+				obj->yst_mode &= ~S_IFMT;+				obj->yst_mode |= S_IFREG;+			}++			break;+		case YAFFS_OBJECT_TYPE_SYMLINK:+			if (!S_ISLNK(mode)) {+				obj->yst_mode &= ~S_IFMT;+				obj->yst_mode |= S_IFLNK;+			}++			break;+		case YAFFS_OBJECT_TYPE_DIRECTORY:+			if (!S_ISDIR(mode)) {+				obj->yst_mode &= ~S_IFMT;+				obj->yst_mode |= S_IFDIR;+			}++			break;+		case YAFFS_OBJECT_TYPE_UNKNOWN:+		case YAFFS_OBJECT_TYPE_HARDLINK:+		case YAFFS_OBJECT_TYPE_SPECIAL:+		default:+			/* TODO? */+			break;+		}++		inode->i_flags |= S_NOATIME;++		inode->i_ino = obj->objectId;+		inode->i_mode = obj->yst_mode;+		inode->i_uid = obj->yst_uid;+		inode->i_gid = obj->yst_gid;+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))+		inode->i_blksize = inode->i_sb->s_blocksize;+#endif+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))++		inode->i_rdev = old_decode_dev(obj->yst_rdev);+		inode->i_atime.tv_sec = (time_t) (obj->yst_atime);+		inode->i_atime.tv_nsec = 0;+		inode->i_mtime.tv_sec = (time_t) obj->yst_mtime;+		inode->i_mtime.tv_nsec = 0;+		inode->i_ctime.tv_sec = (time_t) obj->yst_ctime;+		inode->i_ctime.tv_nsec = 0;+#else+		inode->i_rdev = obj->yst_rdev;+		inode->i_atime = obj->yst_atime;+		inode->i_mtime = obj->yst_mtime;+		inode->i_ctime = obj->yst_ctime;+#endif+		inode->i_size = yaffs_GetObjectFileLength(obj);+		inode->i_blocks = (inode->i_size + 511) >> 9;++		inode->i_nlink = yaffs_GetObjectLinkCount(obj);++		T(YAFFS_TRACE_OS,+			("yaffs_FillInode mode %x uid %d gid %d size %d count %d\n",+			inode->i_mode, inode->i_uid, inode->i_gid,+			(int)inode->i_size, atomic_read(&inode->i_count)));++		switch (obj->yst_mode & S_IFMT) {+		default:	/* fifo, device or socket */+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))+			init_special_inode(inode, obj->yst_mode,+					old_decode_dev(obj->yst_rdev));+#else+			init_special_inode(inode, obj->yst_mode,+					(dev_t) (obj->yst_rdev));+#endif+			break;+		case S_IFREG:	/* file */+			inode->i_op = &yaffs_file_inode_operations;+			inode->i_fop = &yaffs_file_operations;+			inode->i_mapping->a_ops =+				&yaffs_file_address_operations;+			break;+		case S_IFDIR:	/* directory */+			inode->i_op = &yaffs_dir_inode_operations;+			inode->i_fop = &yaffs_dir_operations;+			break;+		case S_IFLNK:	/* symlink */+			inode->i_op = &yaffs_symlink_inode_operations;+			break;+		}++		yaffs_InodeToObjectLV(inode) = obj;++		obj->myInode = inode;++	} else {+		T(YAFFS_TRACE_OS,+			("yaffs_FileInode invalid parameters\n"));+	}++}++struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev,+				yaffs_Object *obj)+{+	struct inode *inode;++	if (!sb) {+		T(YAFFS_TRACE_OS,+			("yaffs_get_inode for NULL super_block!!\n"));+		return NULL;++	}++	if (!obj) {+		T(YAFFS_TRACE_OS,+			("yaffs_get_inode for NULL object!!\n"));+		return NULL;++	}++	T(YAFFS_TRACE_OS,+		("yaffs_get_inode for object %d\n", obj->objectId));++	inode = Y_IGET(sb, obj->objectId);+	if (IS_ERR(inode))+		return NULL;++	/* NB Side effect: iget calls back to yaffs_read_inode(). */+	/* iget also increments the inode's i_count */+	/* NB You can't be holding grossLock or deadlock will happen! */++	return inode;+}++static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,+				loff_t *pos)+{+	yaffs_Object *obj;+	int nWritten, ipos;+	struct inode *inode;+	yaffs_Device *dev;++	obj = yaffs_DentryToObject(f->f_dentry);++	dev = obj->myDev;++	yaffs_GrossLock(dev);++	inode = f->f_dentry->d_inode;++	if (!S_ISBLK(inode->i_mode) && f->f_flags & O_APPEND)+		ipos = inode->i_size;+	else+		ipos = *pos;++	if (!obj)+		T(YAFFS_TRACE_OS,+			("yaffs_file_write: hey obj is null!\n"));+	else+		T(YAFFS_TRACE_OS,+			("yaffs_file_write about to write writing %zu bytes"+			"to object %d at %d\n",+			n, obj->objectId, ipos));++	nWritten = yaffs_WriteDataToFile(obj, buf, ipos, n, 0);++	T(YAFFS_TRACE_OS,+		("yaffs_file_write writing %zu bytes, %d written at %d\n",+		n, nWritten, ipos));++	if (nWritten > 0) {+		ipos += nWritten;+		*pos = ipos;+		if (ipos > inode->i_size) {+			inode->i_size = ipos;+			inode->i_blocks = (ipos + 511) >> 9;++			T(YAFFS_TRACE_OS,+				("yaffs_file_write size updated to %d bytes, "+				"%d blocks\n",+				ipos, (int)(inode->i_blocks)));+		}++	}+	yaffs_GrossUnlock(dev);+	return nWritten == 0 ? -ENOSPC : nWritten;+}++/* Space holding and freeing is done to ensure we have space available for write_begin/end */+/* For now we just assume few parallel writes and check against a small number. */+/* Todo: need to do this with a counter to handle parallel reads better */++static ssize_t yaffs_hold_space(struct file *f)+{+	yaffs_Object *obj;+	yaffs_Device *dev;++	int nFreeChunks;+++	obj = yaffs_DentryToObject(f->f_dentry);++	dev = obj->myDev;++	yaffs_GrossLock(dev);++	nFreeChunks = yaffs_GetNumberOfFreeChunks(dev);++	yaffs_GrossUnlock(dev);++	return (nFreeChunks > 20) ? 1 : 0;+}++static void yaffs_release_space(struct file *f)+{+	yaffs_Object *obj;+	yaffs_Device *dev;+++	obj = yaffs_DentryToObject(f->f_dentry);++	dev = obj->myDev;++	yaffs_GrossLock(dev);+++	yaffs_GrossUnlock(dev);+}++static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir)+{+	yaffs_Object *obj;+	yaffs_Device *dev;+	struct inode *inode = f->f_dentry->d_inode;+	unsigned long offset, curoffs;+	struct ylist_head *i;+	yaffs_Object *l;++	char name[YAFFS_MAX_NAME_LENGTH + 1];++	obj = yaffs_DentryToObject(f->f_dentry);+	dev = obj->myDev;++	yaffs_GrossLock(dev);++	offset = f->f_pos;++	T(YAFFS_TRACE_OS, ("yaffs_readdir: starting at %d\n", (int)offset));++	if (offset == 0) {+		T(YAFFS_TRACE_OS,+			("yaffs_readdir: entry . ino %d \n",+			(int)inode->i_ino));+		if (filldir(dirent, ".", 1, offset, inode->i_ino, DT_DIR) < 0)+			goto out;+		offset++;+		f->f_pos++;+	}+	if (offset == 1) {+		T(YAFFS_TRACE_OS,+			("yaffs_readdir: entry .. ino %d \n",+			(int)f->f_dentry->d_parent->d_inode->i_ino));+		if (filldir(dirent, "..", 2, offset,+			f->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0)+			goto out;+		offset++;+		f->f_pos++;+	}++	curoffs = 1;++	/* If the directory has changed since the open or last call to+	   readdir, rewind to after the 2 canned entries. */++	if (f->f_version != inode->i_version) {+		offset = 2;+		f->f_pos = offset;+		f->f_version = inode->i_version;+	}++	ylist_for_each(i, &obj->variant.directoryVariant.children) {+		curoffs++;+		if (curoffs >= offset) {+			l = ylist_entry(i, yaffs_Object, siblings);++			yaffs_GetObjectName(l, name,+					    YAFFS_MAX_NAME_LENGTH + 1);+			T(YAFFS_TRACE_OS,+			  ("yaffs_readdir: %s inode %d\n", name,+			   yaffs_GetObjectInode(l)));++			if (filldir(dirent,+					name,+					strlen(name),+					offset,+					yaffs_GetObjectInode(l),+					yaffs_GetObjectType(l)) < 0)+				goto up_and_out;++			offset++;+			f->f_pos++;+		}+	}++up_and_out:+out:+	yaffs_GrossUnlock(dev);++	return 0;+}++/*+ * File creation. Allocate an inode, and we're done..+ */++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)+#define YCRED(x) x+#else+#define YCRED(x) (x->cred)+#endif++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))+static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,+			dev_t rdev)+#else+static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,+			int rdev)+#endif+{+	struct inode *inode;++	yaffs_Object *obj = NULL;+	yaffs_Device *dev;++	yaffs_Object *parent = yaffs_InodeToObject(dir);++	int error = -ENOSPC;+	uid_t uid = YCRED(current)->fsuid;+	gid_t gid = (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid;++	if ((dir->i_mode & S_ISGID) && S_ISDIR(mode))+		mode |= S_ISGID;++	if (parent) {+		T(YAFFS_TRACE_OS,+			("yaffs_mknod: parent object %d type %d\n",+			parent->objectId, parent->variantType));+	} else {+		T(YAFFS_TRACE_OS,+			("yaffs_mknod: could not get parent object\n"));+		return -EPERM;+	}++	T(YAFFS_TRACE_OS, ("yaffs_mknod: making oject for %s, "+			"mode %x dev %x\n",+			dentry->d_name.name, mode, rdev));++	dev = parent->myDev;++	yaffs_GrossLock(dev);++	switch (mode & S_IFMT) {+	default:+		/* Special (socket, fifo, device...) */+		T(YAFFS_TRACE_OS, ("yaffs_mknod: making special\n"));+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))+		obj = yaffs_MknodSpecial(parent, dentry->d_name.name, mode, uid,+				gid, old_encode_dev(rdev));+#else+		obj = yaffs_MknodSpecial(parent, dentry->d_name.name, mode, uid,+				gid, rdev);+#endif+		break;+	case S_IFREG:		/* file          */+		T(YAFFS_TRACE_OS, ("yaffs_mknod: making file\n"));+		obj = yaffs_MknodFile(parent, dentry->d_name.name, mode, uid,+				gid);+		break;+	case S_IFDIR:		/* directory */+		T(YAFFS_TRACE_OS,+			("yaffs_mknod: making directory\n"));+		obj = yaffs_MknodDirectory(parent, dentry->d_name.name, mode,+					uid, gid);+		break;+	case S_IFLNK:		/* symlink */+		T(YAFFS_TRACE_OS, ("yaffs_mknod: making symlink\n"));+		obj = NULL;	/* Do we ever get here? */+		break;+	}++	/* Can not call yaffs_get_inode() with gross lock held */+	yaffs_GrossUnlock(dev);++	if (obj) {+		inode = yaffs_get_inode(dir->i_sb, mode, rdev, obj);+		d_instantiate(dentry, inode);+		T(YAFFS_TRACE_OS,+			("yaffs_mknod created object %d count = %d\n",+			obj->objectId, atomic_read(&inode->i_count)));+		error = 0;+	} else {+		T(YAFFS_TRACE_OS,+			("yaffs_mknod failed making object\n"));+		error = -ENOMEM;+	}++	return error;+}++static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode)+{+	int retVal;+	T(YAFFS_TRACE_OS, ("yaffs_mkdir\n"));+	retVal = yaffs_mknod(dir, dentry, mode | S_IFDIR, 0);+	return retVal;+}++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))+static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode,+			struct nameidata *n)+#else+static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode)+#endif+{+	T(YAFFS_TRACE_OS, ("yaffs_create\n"));+	return yaffs_mknod(dir, dentry, mode | S_IFREG, 0);+}++static int yaffs_unlink(struct inode *dir, struct dentry *dentry)+{+	int retVal;++	yaffs_Device *dev;++	T(YAFFS_TRACE_OS,+		("yaffs_unlink %d:%s\n", (int)(dir->i_ino),+		dentry->d_name.name));++	dev = yaffs_InodeToObject(dir)->myDev;++	yaffs_GrossLock(dev);++	retVal = yaffs_Unlink(yaffs_InodeToObject(dir), dentry->d_name.name);++	if (retVal == YAFFS_OK) {+		dentry->d_inode->i_nlink--;+		dir->i_version++;+		yaffs_GrossUnlock(dev);+		mark_inode_dirty(dentry->d_inode);+		return 0;+	}+	yaffs_GrossUnlock(dev);+	return -ENOTEMPTY;+}++/*+ * Create a link...+ */+static int yaffs_link(struct dentry *old_dentry, struct inode *dir,+			struct dentry *dentry)+{+	struct inode *inode = old_dentry->d_inode;+	yaffs_Object *obj = NULL;+	yaffs_Object *link = NULL;+	yaffs_Device *dev;++	T(YAFFS_TRACE_OS, ("yaffs_link\n"));++	obj = yaffs_InodeToObject(inode);+	dev = obj->myDev;++	yaffs_GrossLock(dev);++	if (!S_ISDIR(inode->i_mode))		/* Don't link directories */+		link = yaffs_Link(yaffs_InodeToObject(dir), dentry->d_name.name,+			obj);++	if (link) {+		old_dentry->d_inode->i_nlink = yaffs_GetObjectLinkCount(obj);+		d_instantiate(dentry, old_dentry->d_inode);+		atomic_inc(&old_dentry->d_inode->i_count);+		T(YAFFS_TRACE_OS,+			("yaffs_link link count %d i_count %d\n",+			old_dentry->d_inode->i_nlink,+			atomic_read(&old_dentry->d_inode->i_count)));+	}++	yaffs_GrossUnlock(dev);++	if (link)+		return 0;++	return -EPERM;+}++static int yaffs_symlink(struct inode *dir, struct dentry *dentry,+				const char *symname)+{+	yaffs_Object *obj;+	yaffs_Device *dev;+	uid_t uid = YCRED(current)->fsuid;+	gid_t gid = (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid;++	T(YAFFS_TRACE_OS, ("yaffs_symlink\n"));++	dev = yaffs_InodeToObject(dir)->myDev;+	yaffs_GrossLock(dev);+	obj = yaffs_MknodSymLink(yaffs_InodeToObject(dir), dentry->d_name.name,+				S_IFLNK | S_IRWXUGO, uid, gid, symname);+	yaffs_GrossUnlock(dev);++	if (obj) {+		struct inode *inode;++		inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);+		d_instantiate(dentry, inode);+		T(YAFFS_TRACE_OS, ("symlink created OK\n"));+		return 0;+	} else {+		T(YAFFS_TRACE_OS, ("symlink not created\n"));+	}++	return -ENOMEM;+}++static int yaffs_sync_object(struct file *file, struct dentry *dentry,+				int datasync)+{++	yaffs_Object *obj;+	yaffs_Device *dev;++	obj = yaffs_DentryToObject(dentry);++	dev = obj->myDev;++	T(YAFFS_TRACE_OS, ("yaffs_sync_object\n"));+	yaffs_GrossLock(dev);+	yaffs_FlushFile(obj, 1);+	yaffs_GrossUnlock(dev);+	return 0;+}++/*+ * The VFS layer already does all the dentry stuff for rename.+ *+ * NB: POSIX says you can rename an object over an old object of the same name+ */+static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry,+			struct inode *new_dir, struct dentry *new_dentry)+{+	yaffs_Device *dev;+	int retVal = YAFFS_FAIL;+	yaffs_Object *target;++	T(YAFFS_TRACE_OS, ("yaffs_rename\n"));+	dev = yaffs_InodeToObject(old_dir)->myDev;++	yaffs_GrossLock(dev);++	/* Check if the target is an existing directory that is not empty. */+	target = yaffs_FindObjectByName(yaffs_InodeToObject(new_dir),+				new_dentry->d_name.name);++++	if (target && target->variantType == YAFFS_OBJECT_TYPE_DIRECTORY &&+		!ylist_empty(&target->variant.directoryVariant.children)) {++		T(YAFFS_TRACE_OS, ("target is non-empty dir\n"));++		retVal = YAFFS_FAIL;+	} else {+		/* Now does unlinking internally using shadowing mechanism */+		T(YAFFS_TRACE_OS, ("calling yaffs_RenameObject\n"));++		retVal = yaffs_RenameObject(yaffs_InodeToObject(old_dir),+				old_dentry->d_name.name,+				yaffs_InodeToObject(new_dir),+				new_dentry->d_name.name);+	}+	yaffs_GrossUnlock(dev);++	if (retVal == YAFFS_OK) {+		if (target) {+			new_dentry->d_inode->i_nlink--;+			mark_inode_dirty(new_dentry->d_inode);+		}++		return 0;+	} else {+		return -ENOTEMPTY;+	}+}++static int yaffs_setattr(struct dentry *dentry, struct iattr *attr)+{+	struct inode *inode = dentry->d_inode;+	int error;+	yaffs_Device *dev;++	T(YAFFS_TRACE_OS,+		("yaffs_setattr of object %d\n",+		yaffs_InodeToObject(inode)->objectId));++	error = inode_change_ok(inode, attr);+	if (error == 0) {+		dev = yaffs_InodeToObject(inode)->myDev;+		yaffs_GrossLock(dev);+		if (yaffs_SetAttributes(yaffs_InodeToObject(inode), attr) ==+				YAFFS_OK) {+			error = 0;+		} else {+			error = -EPERM;+		}+		yaffs_GrossUnlock(dev);+		if (!error)+			error = inode_setattr(inode, attr);+	}+	return error;+}++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))+static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf)+{+	yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev;+	struct super_block *sb = dentry->d_sb;+#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))+static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf)+{+	yaffs_Device *dev = yaffs_SuperToDevice(sb);+#else+static int yaffs_statfs(struct super_block *sb, struct statfs *buf)+{+	yaffs_Device *dev = yaffs_SuperToDevice(sb);+#endif++	T(YAFFS_TRACE_OS, ("yaffs_statfs\n"));++	yaffs_GrossLock(dev);++	buf->f_type = YAFFS_MAGIC;+	buf->f_bsize = sb->s_blocksize;+	buf->f_namelen = 255;++	if (dev->nDataBytesPerChunk & (dev->nDataBytesPerChunk - 1)) {+		/* Do this if chunk size is not a power of 2 */++		uint64_t bytesInDev;+		uint64_t bytesFree;++		bytesInDev = ((uint64_t)((dev->endBlock - dev->startBlock + 1))) *+			((uint64_t)(dev->nChunksPerBlock * dev->nDataBytesPerChunk));++		do_div(bytesInDev, sb->s_blocksize); /* bytesInDev becomes the number of blocks */+		buf->f_blocks = bytesInDev;++		bytesFree  = ((uint64_t)(yaffs_GetNumberOfFreeChunks(dev))) *+			((uint64_t)(dev->nDataBytesPerChunk));++		do_div(bytesFree, sb->s_blocksize);++		buf->f_bfree = bytesFree;++	} else if (sb->s_blocksize > dev->nDataBytesPerChunk) {++		buf->f_blocks =+			(dev->endBlock - dev->startBlock + 1) *+			dev->nChunksPerBlock /+			(sb->s_blocksize / dev->nDataBytesPerChunk);+		buf->f_bfree =+			yaffs_GetNumberOfFreeChunks(dev) /+			(sb->s_blocksize / dev->nDataBytesPerChunk);+	} else {+		buf->f_blocks =+			(dev->endBlock - dev->startBlock + 1) *+			dev->nChunksPerBlock *+			(dev->nDataBytesPerChunk / sb->s_blocksize);++		buf->f_bfree =+			yaffs_GetNumberOfFreeChunks(dev) *+			(dev->nDataBytesPerChunk / sb->s_blocksize);+	}++	buf->f_files = 0;+	buf->f_ffree = 0;+	buf->f_bavail = buf->f_bfree;++	yaffs_GrossUnlock(dev);+	return 0;+}+++static int yaffs_do_sync_fs(struct super_block *sb)+{++	yaffs_Device *dev = yaffs_SuperToDevice(sb);+	T(YAFFS_TRACE_OS, ("yaffs_do_sync_fs\n"));++	if (sb->s_dirt) {+		yaffs_GrossLock(dev);++		if (dev) {+			yaffs_FlushEntireDeviceCache(dev);+			yaffs_CheckpointSave(dev);+		}++		yaffs_GrossUnlock(dev);++		sb->s_dirt = 0;+	}+	return 0;+}+++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))+static void yaffs_write_super(struct super_block *sb)+#else+static int yaffs_write_super(struct super_block *sb)+#endif+{++	T(YAFFS_TRACE_OS, ("yaffs_write_super\n"));+	if (yaffs_auto_checkpoint >= 2)+		yaffs_do_sync_fs(sb);+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18))+	return 0;+#endif+}+++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))+static int yaffs_sync_fs(struct super_block *sb, int wait)+#else+static int yaffs_sync_fs(struct super_block *sb)+#endif+{+	T(YAFFS_TRACE_OS, ("yaffs_sync_fs\n"));++	if (yaffs_auto_checkpoint >= 1)+		yaffs_do_sync_fs(sb);++	return 0;+}++#ifdef YAFFS_USE_OWN_IGET++static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino)+{+	struct inode *inode;+	yaffs_Object *obj;+	yaffs_Device *dev = yaffs_SuperToDevice(sb);++	T(YAFFS_TRACE_OS,+		("yaffs_iget for %lu\n", ino));++	inode = iget_locked(sb, ino);+	if (!inode)+		return ERR_PTR(-ENOMEM);+	if (!(inode->i_state & I_NEW))+		return inode;++	/* NB This is called as a side effect of other functions, but+	 * we had to release the lock to prevent deadlocks, so+	 * need to lock again.+	 */++	yaffs_GrossLock(dev);++	obj = yaffs_FindObjectByNumber(dev, inode->i_ino);++	yaffs_FillInodeFromObject(inode, obj);++	yaffs_GrossUnlock(dev);++	unlock_new_inode(inode);+	return inode;+}++#else++static void yaffs_read_inode(struct inode *inode)+{+	/* NB This is called as a side effect of other functions, but+	 * we had to release the lock to prevent deadlocks, so+	 * need to lock again.+	 */++	yaffs_Object *obj;+	yaffs_Device *dev = yaffs_SuperToDevice(inode->i_sb);++	T(YAFFS_TRACE_OS,+		("yaffs_read_inode for %d\n", (int)inode->i_ino));++	yaffs_GrossLock(dev);++	obj = yaffs_FindObjectByNumber(dev, inode->i_ino);++	yaffs_FillInodeFromObject(inode, obj);++	yaffs_GrossUnlock(dev);+}++#endif++static YLIST_HEAD(yaffs_dev_list);++#if 0 /* not used */+static int yaffs_remount_fs(struct super_block *sb, int *flags, char *data)+{+	yaffs_Device    *dev = yaffs_SuperToDevice(sb);++	if (*flags & MS_RDONLY) {+		struct mtd_info *mtd = yaffs_SuperToDevice(sb)->genericDevice;++		T(YAFFS_TRACE_OS,+			("yaffs_remount_fs: %s: RO\n", dev->name));++		yaffs_GrossLock(dev);++		yaffs_FlushEntireDeviceCache(dev);++		yaffs_CheckpointSave(dev);++		if (mtd->sync)+			mtd->sync(mtd);++		yaffs_GrossUnlock(dev);+	} else {+		T(YAFFS_TRACE_OS,+			("yaffs_remount_fs: %s: RW\n", dev->name));+	}++	return 0;+}+#endif++static void yaffs_put_super(struct super_block *sb)+{+	yaffs_Device *dev = yaffs_SuperToDevice(sb);++	T(YAFFS_TRACE_OS, ("yaffs_put_super\n"));++	yaffs_GrossLock(dev);++	yaffs_FlushEntireDeviceCache(dev);++	yaffs_CheckpointSave(dev);++	if (dev->putSuperFunc)+		dev->putSuperFunc(sb);++	yaffs_Deinitialise(dev);++	yaffs_GrossUnlock(dev);++	/* we assume this is protected by lock_kernel() in mount/umount */+	ylist_del(&dev->devList);++	if (dev->spareBuffer) {+		YFREE(dev->spareBuffer);+		dev->spareBuffer = NULL;+	}++	kfree(dev);+}+++static void yaffs_MTDPutSuper(struct super_block *sb)+{+	struct mtd_info *mtd = yaffs_SuperToDevice(sb)->genericDevice;++	if (mtd->sync)+		mtd->sync(mtd);++	put_mtd_device(mtd);+}+++static void yaffs_MarkSuperBlockDirty(void *vsb)+{+	struct super_block *sb = (struct super_block *)vsb;++	T(YAFFS_TRACE_OS, ("yaffs_MarkSuperBlockDirty() sb = %p\n", sb));+	if (sb)+		sb->s_dirt = 1;+}++typedef struct {+	int inband_tags;+	int skip_checkpoint_read;+	int skip_checkpoint_write;+	int no_cache;+} yaffs_options;++#define MAX_OPT_LEN 20+static int yaffs_parse_options(yaffs_options *options, const char *options_str)+{+	char cur_opt[MAX_OPT_LEN + 1];+	int p;+	int error = 0;++	/* Parse through the options which is a comma seperated list */++	while (options_str && *options_str && !error) {+		memset(cur_opt, 0, MAX_OPT_LEN + 1);+		p = 0;++		while (*options_str && *options_str != ',') {+			if (p < MAX_OPT_LEN) {+				cur_opt[p] = *options_str;+				p++;+			}+			options_str++;+		}++		if (!strcmp(cur_opt, "inband-tags"))+			options->inband_tags = 1;+		else if (!strcmp(cur_opt, "no-cache"))+			options->no_cache = 1;+		else if (!strcmp(cur_opt, "no-checkpoint-read"))+			options->skip_checkpoint_read = 1;+		else if (!strcmp(cur_opt, "no-checkpoint-write"))+			options->skip_checkpoint_write = 1;+		else if (!strcmp(cur_opt, "no-checkpoint")) {+			options->skip_checkpoint_read = 1;+			options->skip_checkpoint_write = 1;+		} else {+			printk(KERN_INFO "yaffs: Bad mount option \"%s\"\n",+					cur_opt);+			error = 1;+		}+	}++	return error;+}++static struct super_block *yaffs_internal_read_super(int yaffsVersion,+						struct super_block *sb,+						void *data, int silent)+{+	int nBlocks;+	struct inode *inode = NULL;+	struct dentry *root;+	yaffs_Device *dev = 0;+	char devname_buf[BDEVNAME_SIZE + 1];+	struct mtd_info *mtd;+	int err;+	char *data_str = (char *)data;++	yaffs_options options;++	sb->s_magic = YAFFS_MAGIC;+	sb->s_op = &yaffs_super_ops;+	sb->s_flags |= MS_NOATIME;++	if (!sb)+		printk(KERN_INFO "yaffs: sb is NULL\n");+	else if (!sb->s_dev)+		printk(KERN_INFO "yaffs: sb->s_dev is NULL\n");+	else if (!yaffs_devname(sb, devname_buf))+		printk(KERN_INFO "yaffs: devname is NULL\n");+	else+		printk(KERN_INFO "yaffs: dev is %d name is \"%s\"\n",+		       sb->s_dev,+		       yaffs_devname(sb, devname_buf));++	if (!data_str)+		data_str = "";++	printk(KERN_INFO "yaffs: passed flags \"%s\"\n", data_str);++	memset(&options, 0, sizeof(options));++	if (yaffs_parse_options(&options, data_str)) {+		/* Option parsing failed */+		return NULL;+	}+++	sb->s_blocksize = PAGE_CACHE_SIZE;+	sb->s_blocksize_bits = PAGE_CACHE_SHIFT;+	T(YAFFS_TRACE_OS, ("yaffs_read_super: Using yaffs%d\n", yaffsVersion));+	T(YAFFS_TRACE_OS,+	  ("yaffs_read_super: block size %d\n", (int)(sb->s_blocksize)));++#ifdef CONFIG_YAFFS_DISABLE_WRITE_VERIFY+	T(YAFFS_TRACE_OS,+	  ("yaffs: Write verification disabled. All guarantees "+	   "null and void\n"));+#endif++	T(YAFFS_TRACE_ALWAYS, ("yaffs: Attempting MTD mount on %u.%u, "+			       "\"%s\"\n",+			       MAJOR(sb->s_dev), MINOR(sb->s_dev),+			       yaffs_devname(sb, devname_buf)));++	/* Check it's an mtd device..... */+	if (MAJOR(sb->s_dev) != MTD_BLOCK_MAJOR)+		return NULL;	/* This isn't an mtd device */++	/* Get the device */+	mtd = get_mtd_device(NULL, MINOR(sb->s_dev));+	if (!mtd) {+		T(YAFFS_TRACE_ALWAYS,+		  ("yaffs: MTD device #%u doesn't appear to exist\n",+		   MINOR(sb->s_dev)));+		return NULL;+	}+	/* Check it's NAND */+	if (mtd->type != MTD_NANDFLASH) {+		T(YAFFS_TRACE_ALWAYS,+		  ("yaffs: MTD device is not NAND it's type %d\n", mtd->type));+		return NULL;+	}++	T(YAFFS_TRACE_OS, (" erase %p\n", mtd->erase));+	T(YAFFS_TRACE_OS, (" read %p\n", mtd->read));+	T(YAFFS_TRACE_OS, (" write %p\n", mtd->write));+	T(YAFFS_TRACE_OS, (" readoob %p\n", mtd->read_oob));+	T(YAFFS_TRACE_OS, (" writeoob %p\n", mtd->write_oob));+	T(YAFFS_TRACE_OS, (" block_isbad %p\n", mtd->block_isbad));+	T(YAFFS_TRACE_OS, (" block_markbad %p\n", mtd->block_markbad));+	T(YAFFS_TRACE_OS, (" %s %d\n", WRITE_SIZE_STR, WRITE_SIZE(mtd)));+	T(YAFFS_TRACE_OS, (" oobsize %d\n", mtd->oobsize));+	T(YAFFS_TRACE_OS, (" erasesize %d\n", mtd->erasesize));+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)+	T(YAFFS_TRACE_OS, (" size %u\n", mtd->size));+#else+	T(YAFFS_TRACE_OS, (" size %lld\n", mtd->size));+#endif++#ifdef CONFIG_YAFFS_AUTO_YAFFS2++	if (yaffsVersion == 1 && WRITE_SIZE(mtd) >= 2048) {+		T(YAFFS_TRACE_ALWAYS, ("yaffs: auto selecting yaffs2\n"));+		yaffsVersion = 2;+	}++	/* Added NCB 26/5/2006 for completeness */+	if (yaffsVersion == 2 && !options.inband_tags && WRITE_SIZE(mtd) == 512) {+		T(YAFFS_TRACE_ALWAYS, ("yaffs: auto selecting yaffs1\n"));+		yaffsVersion = 1;+	}++#endif++	if (yaffsVersion == 2) {+		/* Check for version 2 style functions */+		if (!mtd->erase ||+		    !mtd->block_isbad ||+		    !mtd->block_markbad ||+		    !mtd->read ||+		    !mtd->write ||+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))+		    !mtd->read_oob || !mtd->write_oob) {+#else+		    !mtd->write_ecc ||+		    !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) {+#endif+			T(YAFFS_TRACE_ALWAYS,+			  ("yaffs: MTD device does not support required "+			   "functions\n"));;+			return NULL;+		}++		if ((WRITE_SIZE(mtd) < YAFFS_MIN_YAFFS2_CHUNK_SIZE ||+		    mtd->oobsize < YAFFS_MIN_YAFFS2_SPARE_SIZE) &&+		    !options.inband_tags) {+			T(YAFFS_TRACE_ALWAYS,+			  ("yaffs: MTD device does not have the "+			   "right page sizes\n"));+			return NULL;+		}+	} else {+		/* Check for V1 style functions */+		if (!mtd->erase ||+		    !mtd->read ||+		    !mtd->write ||+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))+		    !mtd->read_oob || !mtd->write_oob) {+#else+		    !mtd->write_ecc ||+		    !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) {+#endif+			T(YAFFS_TRACE_ALWAYS,+			  ("yaffs: MTD device does not support required "+			   "functions\n"));;+			return NULL;+		}++		if (WRITE_SIZE(mtd) < YAFFS_BYTES_PER_CHUNK ||+		    mtd->oobsize != YAFFS_BYTES_PER_SPARE) {+			T(YAFFS_TRACE_ALWAYS,+			  ("yaffs: MTD device does not support have the "+			   "right page sizes\n"));+			return NULL;+		}+	}++	/* OK, so if we got here, we have an MTD that's NAND and looks+	 * like it has the right capabilities+	 * Set the yaffs_Device up for mtd+	 */++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))+	sb->s_fs_info = dev = kmalloc(sizeof(yaffs_Device), GFP_KERNEL);+#else+	sb->u.generic_sbp = dev = kmalloc(sizeof(yaffs_Device), GFP_KERNEL);+#endif+	if (!dev) {+		/* Deep shit could not allocate device structure */+		T(YAFFS_TRACE_ALWAYS,+		  ("yaffs_read_super: Failed trying to allocate "+		   "yaffs_Device. \n"));+		return NULL;+	}++	memset(dev, 0, sizeof(yaffs_Device));+	dev->genericDevice = mtd;+	dev->name = mtd->name;++	/* Set up the memory size parameters.... */++	nBlocks = YCALCBLOCKS(mtd->size, (YAFFS_CHUNKS_PER_BLOCK * YAFFS_BYTES_PER_CHUNK));++	dev->startBlock = 0;+	dev->endBlock = nBlocks - 1;+	dev->nChunksPerBlock = YAFFS_CHUNKS_PER_BLOCK;+	dev->totalBytesPerChunk = YAFFS_BYTES_PER_CHUNK;+	dev->nReservedBlocks = 5;+	dev->nShortOpCaches = (options.no_cache) ? 0 : 10;+	dev->inbandTags = options.inband_tags;++	/* ... and the functions. */+	if (yaffsVersion == 2) {+		dev->writeChunkWithTagsToNAND =+		    nandmtd2_WriteChunkWithTagsToNAND;+		dev->readChunkWithTagsFromNAND =+		    nandmtd2_ReadChunkWithTagsFromNAND;+		dev->markNANDBlockBad = nandmtd2_MarkNANDBlockBad;+		dev->queryNANDBlock = nandmtd2_QueryNANDBlock;+		dev->spareBuffer = YMALLOC(mtd->oobsize);+		dev->isYaffs2 = 1;+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))+		dev->totalBytesPerChunk = mtd->writesize;+		dev->nChunksPerBlock = mtd->erasesize / mtd->writesize;+#else+		dev->totalBytesPerChunk = mtd->oobblock;+		dev->nChunksPerBlock = mtd->erasesize / mtd->oobblock;+#endif+		nBlocks = YCALCBLOCKS(mtd->size, mtd->erasesize);++		dev->startBlock = 0;+		dev->endBlock = nBlocks - 1;+	} else {+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))+		/* use the MTD interface in yaffs_mtdif1.c */+		dev->writeChunkWithTagsToNAND =+			nandmtd1_WriteChunkWithTagsToNAND;+		dev->readChunkWithTagsFromNAND =+			nandmtd1_ReadChunkWithTagsFromNAND;+		dev->markNANDBlockBad = nandmtd1_MarkNANDBlockBad;+		dev->queryNANDBlock = nandmtd1_QueryNANDBlock;+#else+		dev->writeChunkToNAND = nandmtd_WriteChunkToNAND;+		dev->readChunkFromNAND = nandmtd_ReadChunkFromNAND;+#endif+		dev->isYaffs2 = 0;+	}+	/* ... and common functions */+	dev->eraseBlockInNAND = nandmtd_EraseBlockInNAND;+	dev->initialiseNAND = nandmtd_InitialiseNAND;++	dev->putSuperFunc = yaffs_MTDPutSuper;++	dev->superBlock = (void *)sb;+	dev->markSuperBlockDirty = yaffs_MarkSuperBlockDirty;+++#ifndef CONFIG_YAFFS_DOES_ECC+	dev->useNANDECC = 1;+#endif++#ifdef CONFIG_YAFFS_DISABLE_WIDE_TNODES+	dev->wideTnodesDisabled = 1;+#endif++	dev->skipCheckpointRead = options.skip_checkpoint_read;+	dev->skipCheckpointWrite = options.skip_checkpoint_write;++	/* we assume this is protected by lock_kernel() in mount/umount */+	ylist_add_tail(&dev->devList, &yaffs_dev_list);++	init_MUTEX(&dev->grossLock);++	yaffs_GrossLock(dev);++	err = yaffs_GutsInitialise(dev);++	T(YAFFS_TRACE_OS,+	  ("yaffs_read_super: guts initialised %s\n",+	   (err == YAFFS_OK) ? "OK" : "FAILED"));++	/* Release lock before yaffs_get_inode() */+	yaffs_GrossUnlock(dev);++	/* Create root inode */+	if (err == YAFFS_OK)+		inode = yaffs_get_inode(sb, S_IFDIR | 0755, 0,+					yaffs_Root(dev));++	if (!inode)+		return NULL;++	inode->i_op = &yaffs_dir_inode_operations;+	inode->i_fop = &yaffs_dir_operations;++	T(YAFFS_TRACE_OS, ("yaffs_read_super: got root inode\n"));++	root = d_alloc_root(inode);++	T(YAFFS_TRACE_OS, ("yaffs_read_super: d_alloc_root done\n"));++	if (!root) {+		iput(inode);+		return NULL;+	}+	sb->s_root = root;+	sb->s_dirt = !dev->isCheckpointed;+	T(YAFFS_TRACE_ALWAYS,+	  ("yaffs_read_super: isCheckpointed %d\n", dev->isCheckpointed));++	T(YAFFS_TRACE_OS, ("yaffs_read_super: done\n"));+	return sb;+}+++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))+static int yaffs_internal_read_super_mtd(struct super_block *sb, void *data,+					 int silent)+{+	return yaffs_internal_read_super(1, sb, data, silent) ? 0 : -EINVAL;+}++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))+static int yaffs_read_super(struct file_system_type *fs,+			    int flags, const char *dev_name,+			    void *data, struct vfsmount *mnt)+{++	return get_sb_bdev(fs, flags, dev_name, data,+			   yaffs_internal_read_super_mtd, mnt);+}+#else+static struct super_block *yaffs_read_super(struct file_system_type *fs,+					    int flags, const char *dev_name,+					    void *data)+{++	return get_sb_bdev(fs, flags, dev_name, data,+			   yaffs_internal_read_super_mtd);+}+#endif++static struct file_system_type yaffs_fs_type = {+	.owner = THIS_MODULE,+	.name = "yaffs",+	.get_sb = yaffs_read_super,+	.kill_sb = kill_block_super,+	.fs_flags = FS_REQUIRES_DEV,+};+#else+static struct super_block *yaffs_read_super(struct super_block *sb, void *data,+					    int silent)+{+	return yaffs_internal_read_super(1, sb, data, silent);+}++static DECLARE_FSTYPE(yaffs_fs_type, "yaffs", yaffs_read_super,+		      FS_REQUIRES_DEV);+#endif+++#ifdef CONFIG_YAFFS_YAFFS2++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))+static int yaffs2_internal_read_super_mtd(struct super_block *sb, void *data,+					  int silent)+{+	return yaffs_internal_read_super(2, sb, data, silent) ? 0 : -EINVAL;+}++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))+static int yaffs2_read_super(struct file_system_type *fs,+			int flags, const char *dev_name, void *data,+			struct vfsmount *mnt)+{+	return get_sb_bdev(fs, flags, dev_name, data,+			yaffs2_internal_read_super_mtd, mnt);+}+#else+static struct super_block *yaffs2_read_super(struct file_system_type *fs,+					     int flags, const char *dev_name,+					     void *data)+{++	return get_sb_bdev(fs, flags, dev_name, data,+			   yaffs2_internal_read_super_mtd);+}+#endif++static struct file_system_type yaffs2_fs_type = {+	.owner = THIS_MODULE,+	.name = "yaffs2",+	.get_sb = yaffs2_read_super,+	.kill_sb = kill_block_super,+	.fs_flags = FS_REQUIRES_DEV,+};+#else+static struct super_block *yaffs2_read_super(struct super_block *sb,+					     void *data, int silent)+{+	return yaffs_internal_read_super(2, sb, data, silent);+}++static DECLARE_FSTYPE(yaffs2_fs_type, "yaffs2", yaffs2_read_super,+		      FS_REQUIRES_DEV);+#endif++#endif				/* CONFIG_YAFFS_YAFFS2 */++static struct proc_dir_entry *my_proc_entry;++static char *yaffs_dump_dev(char *buf, yaffs_Device * dev)+{+	buf += sprintf(buf, "startBlock......... %d\n", dev->startBlock);+	buf += sprintf(buf, "endBlock........... %d\n", dev->endBlock);+	buf += sprintf(buf, "totalBytesPerChunk. %d\n", dev->totalBytesPerChunk);+	buf += sprintf(buf, "nDataBytesPerChunk. %d\n", dev->nDataBytesPerChunk);+	buf += sprintf(buf, "chunkGroupBits..... %d\n", dev->chunkGroupBits);+	buf += sprintf(buf, "chunkGroupSize..... %d\n", dev->chunkGroupSize);+	buf += sprintf(buf, "nErasedBlocks...... %d\n", dev->nErasedBlocks);+	buf += sprintf(buf, "nReservedBlocks.... %d\n", dev->nReservedBlocks);+	buf += sprintf(buf, "blocksInCheckpoint. %d\n", dev->blocksInCheckpoint);+	buf += sprintf(buf, "nTnodesCreated..... %d\n", dev->nTnodesCreated);+	buf += sprintf(buf, "nFreeTnodes........ %d\n", dev->nFreeTnodes);+	buf += sprintf(buf, "nObjectsCreated.... %d\n", dev->nObjectsCreated);+	buf += sprintf(buf, "nFreeObjects....... %d\n", dev->nFreeObjects);+	buf += sprintf(buf, "nFreeChunks........ %d\n", dev->nFreeChunks);+	buf += sprintf(buf, "nPageWrites........ %d\n", dev->nPageWrites);+	buf += sprintf(buf, "nPageReads......... %d\n", dev->nPageReads);+	buf += sprintf(buf, "nBlockErasures..... %d\n", dev->nBlockErasures);+	buf += sprintf(buf, "nGCCopies.......... %d\n", dev->nGCCopies);+	buf += sprintf(buf, "garbageCollections. %d\n", dev->garbageCollections);+	buf += sprintf(buf, "passiveGCs......... %d\n",+		    dev->passiveGarbageCollections);+	buf += sprintf(buf, "nRetriedWrites..... %d\n", dev->nRetriedWrites);+	buf += sprintf(buf, "nShortOpCaches..... %d\n", dev->nShortOpCaches);+	buf += sprintf(buf, "nRetireBlocks...... %d\n", dev->nRetiredBlocks);+	buf += sprintf(buf, "eccFixed........... %d\n", dev->eccFixed);+	buf += sprintf(buf, "eccUnfixed......... %d\n", dev->eccUnfixed);+	buf += sprintf(buf, "tagsEccFixed....... %d\n", dev->tagsEccFixed);+	buf += sprintf(buf, "tagsEccUnfixed..... %d\n", dev->tagsEccUnfixed);+	buf += sprintf(buf, "cacheHits.......... %d\n", dev->cacheHits);+	buf += sprintf(buf, "nDeletedFiles...... %d\n", dev->nDeletedFiles);+	buf += sprintf(buf, "nUnlinkedFiles..... %d\n", dev->nUnlinkedFiles);+	buf +=+	    sprintf(buf, "nBackgroudDeletions %d\n", dev->nBackgroundDeletions);+	buf += sprintf(buf, "useNANDECC......... %d\n", dev->useNANDECC);+	buf += sprintf(buf, "isYaffs2........... %d\n", dev->isYaffs2);+	buf += sprintf(buf, "inbandTags......... %d\n", dev->inbandTags);++	return buf;+}++static int yaffs_proc_read(char *page,+			   char **start,+			   off_t offset, int count, int *eof, void *data)+{+	struct ylist_head *item;+	char *buf = page;+	int step = offset;+	int n = 0;++	/* Get proc_file_read() to step 'offset' by one on each sucessive call.+	 * We use 'offset' (*ppos) to indicate where we are in devList.+	 * This also assumes the user has posted a read buffer large+	 * enough to hold the complete output; but that's life in /proc.+	 */++	*(int *)start = 1;++	/* Print header first */+	if (step == 0) {+		buf += sprintf(buf, "YAFFS built:" __DATE__ " " __TIME__+			       "\n%s\n%s\n", yaffs_fs_c_version,+			       yaffs_guts_c_version);+	}++	/* hold lock_kernel while traversing yaffs_dev_list */+	lock_kernel();++	/* Locate and print the Nth entry.  Order N-squared but N is small. */+	ylist_for_each(item, &yaffs_dev_list) {+		yaffs_Device *dev = ylist_entry(item, yaffs_Device, devList);+		if (n < step) {+			n++;+			continue;+		}+		buf += sprintf(buf, "\nDevice %d \"%s\"\n", n, dev->name);+		buf = yaffs_dump_dev(buf, dev);+		break;+	}+	unlock_kernel();++	return buf - page < count ? buf - page : count;+}++/**+ * Set the verbosity of the warnings and error messages.+ *+ * Note that the names can only be a..z or _ with the current code.+ */++static struct {+	char *mask_name;+	unsigned mask_bitfield;+} mask_flags[] = {+	{"allocate", YAFFS_TRACE_ALLOCATE},+	{"always", YAFFS_TRACE_ALWAYS},+	{"bad_blocks", YAFFS_TRACE_BAD_BLOCKS},+	{"buffers", YAFFS_TRACE_BUFFERS},+	{"bug", YAFFS_TRACE_BUG},+	{"checkpt", YAFFS_TRACE_CHECKPOINT},+	{"deletion", YAFFS_TRACE_DELETION},+	{"erase", YAFFS_TRACE_ERASE},+	{"error", YAFFS_TRACE_ERROR},+	{"gc_detail", YAFFS_TRACE_GC_DETAIL},+	{"gc", YAFFS_TRACE_GC},+	{"mtd", YAFFS_TRACE_MTD},+	{"nandaccess", YAFFS_TRACE_NANDACCESS},+	{"os", YAFFS_TRACE_OS},+	{"scan_debug", YAFFS_TRACE_SCAN_DEBUG},+	{"scan", YAFFS_TRACE_SCAN},+	{"tracing", YAFFS_TRACE_TRACING},++	{"verify", YAFFS_TRACE_VERIFY},+	{"verify_nand", YAFFS_TRACE_VERIFY_NAND},+	{"verify_full", YAFFS_TRACE_VERIFY_FULL},+	{"verify_all", YAFFS_TRACE_VERIFY_ALL},++	{"write", YAFFS_TRACE_WRITE},+	{"all", 0xffffffff},+	{"none", 0},+	{NULL, 0},+};++#define MAX_MASK_NAME_LENGTH 40+static int yaffs_proc_write(struct file *file, const char *buf,+					 unsigned long count, void *data)+{+	unsigned rg = 0, mask_bitfield;+	char *end;+	char *mask_name;+	const char *x;+	char substring[MAX_MASK_NAME_LENGTH + 1];+	int i;+	int done = 0;+	int add, len = 0;+	int pos = 0;++	rg = yaffs_traceMask;++	while (!done && (pos < count)) {+		done = 1;+		while ((pos < count) && isspace(buf[pos]))+			pos++;++		switch (buf[pos]) {+		case '+':+		case '-':+		case '=':+			add = buf[pos];+			pos++;+			break;++		default:+			add = ' ';+			break;+		}+		mask_name = NULL;++		mask_bitfield = simple_strtoul(buf + pos, &end, 0);++		if (end > buf + pos) {+			mask_name = "numeral";+			len = end - (buf + pos);+			pos += len;+			done = 0;+		} else {+			for (x = buf + pos, i = 0;+			    (*x == '_' || (*x >= 'a' && *x <= 'z')) &&+			    i < MAX_MASK_NAME_LENGTH; x++, i++, pos++)+				substring[i] = *x;+			substring[i] = '\0';++			for (i = 0; mask_flags[i].mask_name != NULL; i++) {+				if (strcmp(substring, mask_flags[i].mask_name) == 0) {+					mask_name = mask_flags[i].mask_name;+					mask_bitfield = mask_flags[i].mask_bitfield;+					done = 0;+					break;+				}+			}+		}++		if (mask_name != NULL) {+			done = 0;+			switch (add) {+			case '-':+				rg &= ~mask_bitfield;+				break;+			case '+':+				rg |= mask_bitfield;+				break;+			case '=':+				rg = mask_bitfield;+				break;+			default:+				rg |= mask_bitfield;+				break;+			}+		}+	}++	yaffs_traceMask = rg | YAFFS_TRACE_ALWAYS;++	printk(KERN_DEBUG "new trace = 0x%08X\n", yaffs_traceMask);++	if (rg & YAFFS_TRACE_ALWAYS) {+		for (i = 0; mask_flags[i].mask_name != NULL; i++) {+			char flag;+			flag = ((rg & mask_flags[i].mask_bitfield) == mask_flags[i].mask_bitfield) ? '+' : '-';+			printk(KERN_DEBUG "%c%s\n", flag, mask_flags[i].mask_name);+		}+	}++	return count;+}++/* Stuff to handle installation of file systems */+struct file_system_to_install {+	struct file_system_type *fst;+	int installed;+};++static struct file_system_to_install fs_to_install[] = {+	{&yaffs_fs_type, 0},+	{&yaffs2_fs_type, 0},+	{NULL, 0}+};++static int __init init_yaffs_fs(void)+{+	int error = 0;+	struct file_system_to_install *fsinst;++	T(YAFFS_TRACE_ALWAYS,+	  ("yaffs " __DATE__ " " __TIME__ " Installing. \n"));++	/* Install the proc_fs entry */+	my_proc_entry = create_proc_entry("yaffs",+					       S_IRUGO | S_IFREG,+					       YPROC_ROOT);++	if (my_proc_entry) {+		my_proc_entry->write_proc = yaffs_proc_write;+		my_proc_entry->read_proc = yaffs_proc_read;+		my_proc_entry->data = NULL;+	} else+		return -ENOMEM;++	/* Now add the file system entries */++	fsinst = fs_to_install;++	while (fsinst->fst && !error) {+		error = register_filesystem(fsinst->fst);+		if (!error)+			fsinst->installed = 1;+		fsinst++;+	}++	/* Any errors? uninstall  */+	if (error) {+		fsinst = fs_to_install;++		while (fsinst->fst) {+			if (fsinst->installed) {+				unregister_filesystem(fsinst->fst);+				fsinst->installed = 0;+			}+			fsinst++;+		}+	}++	return error;+}++static void __exit exit_yaffs_fs(void)+{++	struct file_system_to_install *fsinst;++	T(YAFFS_TRACE_ALWAYS, ("yaffs " __DATE__ " " __TIME__+			       " removing. \n"));++	remove_proc_entry("yaffs", YPROC_ROOT);++	fsinst = fs_to_install;++	while (fsinst->fst) {+		if (fsinst->installed) {+			unregister_filesystem(fsinst->fst);+			fsinst->installed = 0;+		}+		fsinst++;+	}+}++module_init(init_yaffs_fs)+module_exit(exit_yaffs_fs)++MODULE_DESCRIPTION("YAFFS2 - a NAND specific flash file system");+MODULE_AUTHOR("Charles Manning, Aleph One Ltd., 2002-2006");+MODULE_LICENSE("GPL");diff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_getblockinfo.h linux-2.6.30/fs/yaffs2/yaffs_getblockinfo.h--- linux-2.6.30.orig/fs/yaffs2/yaffs_getblockinfo.h	1970-01-01 01:00:00.000000000 +0100+++ linux-2.6.30/fs/yaffs2/yaffs_getblockinfo.h	2009-06-11 09:21:04.000000000 +0200@@ -0,0 +1,34 @@+/*+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.+ *+ * Copyright (C) 2002-2007 Aleph One Ltd.+ *   for Toby Churchill Ltd and Brightstar Engineering+ *+ * Created by Charles Manning <charles@aleph1.co.uk>+ *+ * This program is free software; you can redistribute it and/or modify+ * it under the terms of the GNU Lesser General Public License version 2.1 as+ * published by the Free Software Foundation.+ *+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.+ */++#ifndef __YAFFS_GETBLOCKINFO_H__+#define __YAFFS_GETBLOCKINFO_H__++#include "yaffs_guts.h"++/* Function to manipulate block info */+static Y_INLINE yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device * dev, int blk)+{+	if (blk < dev->internalStartBlock || blk > dev->internalEndBlock) {+		T(YAFFS_TRACE_ERROR,+		  (TSTR+		   ("**>> yaffs: getBlockInfo block %d is not valid" TENDSTR),+		   blk));+		YBUG();+	}+	return &dev->blockInfo[blk - dev->internalStartBlock];+}++#endifdiff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_guts.c linux-2.6.30/fs/yaffs2/yaffs_guts.c--- linux-2.6.30.orig/fs/yaffs2/yaffs_guts.c	1970-01-01 01:00:00.000000000 +0100+++ linux-2.6.30/fs/yaffs2/yaffs_guts.c	2009-06-11 09:21:04.000000000 +0200@@ -0,0 +1,7552 @@+/*+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.+ *+ * Copyright (C) 2002-2007 Aleph One Ltd.+ *   for Toby Churchill Ltd and Brightstar Engineering+ *+ * Created by Charles Manning <charles@aleph1.co.uk>+ *+ * This program is free software; you can redistribute it and/or modify+ * it under the terms of the GNU General Public License version 2 as+ * published by the Free Software Foundation.+ */++const char *yaffs_guts_c_version =+    "$Id: yaffs_guts.c,v 1.82 2009-03-09 04:24:17 charles Exp $";++#include "yportenv.h"++#include "yaffsinterface.h"+#include "yaffs_guts.h"+#include "yaffs_tagsvalidity.h"+#include "yaffs_getblockinfo.h"++#include "yaffs_tagscompat.h"+#ifndef CONFIG_YAFFS_USE_OWN_SORT+#include "yaffs_qsort.h"+#endif+#include "yaffs_nand.h"++#include "yaffs_checkptrw.h"++#include "yaffs_nand.h"+#include "yaffs_packedtags2.h"+++#define YAFFS_PASSIVE_GC_CHUNKS 2++#include "yaffs_ecc.h"+++/* Robustification (if it ever comes about...) */+static void yaffs_RetireBlock(yaffs_Device *dev, int blockInNAND);+static void yaffs_HandleWriteChunkError(yaffs_Device *dev, int chunkInNAND,+		int erasedOk);+static void yaffs_HandleWriteChunkOk(yaffs_Device *dev, int chunkInNAND,+				const __u8 *data,+				const yaffs_ExtendedTags *tags);+static void yaffs_HandleUpdateChunk(yaffs_Device *dev, int chunkInNAND,+				const yaffs_ExtendedTags *tags);++/* Other local prototypes */+static int yaffs_UnlinkObject(yaffs_Object *obj);+static int yaffs_ObjectHasCachedWriteData(yaffs_Object *obj);++static void yaffs_HardlinkFixup(yaffs_Device *dev, yaffs_Object *hardList);++static int yaffs_WriteNewChunkWithTagsToNAND(yaffs_Device *dev,+					const __u8 *buffer,+					yaffs_ExtendedTags *tags,+					int useReserve);+static int yaffs_PutChunkIntoFile(yaffs_Object *in, int chunkInInode,+				int chunkInNAND, int inScan);++static yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev, int number,+					yaffs_ObjectType type);+static void yaffs_AddObjectToDirectory(yaffs_Object *directory,+				yaffs_Object *obj);+static int yaffs_UpdateObjectHeader(yaffs_Object *in, const YCHAR *name,+				int force, int isShrink, int shadows);+static void yaffs_RemoveObjectFromDirectory(yaffs_Object *obj);+static int yaffs_CheckStructures(void);+static int yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level,+			int chunkOffset, int *limit);+static int yaffs_DoGenericObjectDeletion(yaffs_Object *in);++static yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device *dev, int blockNo);+++static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,+				int chunkInNAND);++static int yaffs_UnlinkWorker(yaffs_Object *obj);++static int yaffs_TagsMatch(const yaffs_ExtendedTags *tags, int objectId,+			int chunkInObject);++static int yaffs_AllocateChunk(yaffs_Device *dev, int useReserve,+				yaffs_BlockInfo **blockUsedPtr);++static void yaffs_VerifyFreeChunks(yaffs_Device *dev);++static void yaffs_CheckObjectDetailsLoaded(yaffs_Object *in);++static void yaffs_VerifyDirectory(yaffs_Object *directory);+#ifdef YAFFS_PARANOID+static int yaffs_CheckFileSanity(yaffs_Object *in);+#else+#define yaffs_CheckFileSanity(in)+#endif++static void yaffs_InvalidateWholeChunkCache(yaffs_Object *in);+static void yaffs_InvalidateChunkCache(yaffs_Object *object, int chunkId);++static void yaffs_InvalidateCheckpoint(yaffs_Device *dev);++static int yaffs_FindChunkInFile(yaffs_Object *in, int chunkInInode,+				yaffs_ExtendedTags *tags);++static __u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn,+		unsigned pos);+static yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device *dev,+					yaffs_FileStructure *fStruct,+					__u32 chunkId);+++/* Function to calculate chunk and offset */++static void yaffs_AddrToChunk(yaffs_Device *dev, loff_t addr, int *chunkOut,+		__u32 *offsetOut)+{+	int chunk;+	__u32 offset;++	chunk  = (__u32)(addr >> dev->chunkShift);++	if (dev->chunkDiv == 1) {+		/* easy power of 2 case */+		offset = (__u32)(addr & dev->chunkMask);+	} else {+		/* Non power-of-2 case */++		loff_t chunkBase;++		chunk /= dev->chunkDiv;++		chunkBase = ((loff_t)chunk) * dev->nDataBytesPerChunk;+		offset = (__u32)(addr - chunkBase);+	}++	*chunkOut = chunk;+	*offsetOut = offset;+}++/* Function to return the number of shifts for a power of 2 greater than or+ * equal to the given number+ * Note we don't try to cater for all possible numbers and this does not have to+ * be hellishly efficient.+ */++static __u32 ShiftsGE(__u32 x)+{+	int extraBits;+	int nShifts;++	nShifts = extraBits = 0;++	while (x > 1) {+		if (x & 1)+			extraBits++;+		x >>= 1;+		nShifts++;+	}++	if (extraBits)+		nShifts++;++	return nShifts;+}++/* Function to return the number of shifts to get a 1 in bit 0+ */++static __u32 Shifts(__u32 x)+{+	int nShifts;++	nShifts =  0;++	if (!x)+		return 0;++	while (!(x&1)) {+		x >>= 1;+		nShifts++;+	}++	return nShifts;+}++++/*+ * Temporary buffer manipulations.+ */++static int yaffs_InitialiseTempBuffers(yaffs_Device *dev)+{+	int i;+	__u8 *buf = (__u8 *)1;++	memset(dev->tempBuffer, 0, sizeof(dev->tempBuffer));++	for (i = 0; buf && i < YAFFS_N_TEMP_BUFFERS; i++) {+		dev->tempBuffer[i].line = 0;	/* not in use */+		dev->tempBuffer[i].buffer = buf =+		    YMALLOC_DMA(dev->totalBytesPerChunk);+	}++	return buf ? YAFFS_OK : YAFFS_FAIL;+}++__u8 *yaffs_GetTempBuffer(yaffs_Device *dev, int lineNo)+{+	int i, j;++	dev->tempInUse++;+	if (dev->tempInUse > dev->maxTemp)+		dev->maxTemp = dev->tempInUse;++	for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {+		if (dev->tempBuffer[i].line == 0) {+			dev->tempBuffer[i].line = lineNo;+			if ((i + 1) > dev->maxTemp) {+				dev->maxTemp = i + 1;+				for (j = 0; j <= i; j++)+					dev->tempBuffer[j].maxLine =+					    dev->tempBuffer[j].line;+			}++			return dev->tempBuffer[i].buffer;+		}+	}++	T(YAFFS_TRACE_BUFFERS,+	  (TSTR("Out of temp buffers at line %d, other held by lines:"),+	   lineNo));+	for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++)+		T(YAFFS_TRACE_BUFFERS, (TSTR(" %d "), dev->tempBuffer[i].line));++	T(YAFFS_TRACE_BUFFERS, (TSTR(" " TENDSTR)));++	/*+	 * If we got here then we have to allocate an unmanaged one+	 * This is not good.+	 */++	dev->unmanagedTempAllocations++;+	return YMALLOC(dev->nDataBytesPerChunk);++}++void yaffs_ReleaseTempBuffer(yaffs_Device *dev, __u8 *buffer,+				    int lineNo)+{+	int i;++	dev->tempInUse--;++	for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {+		if (dev->tempBuffer[i].buffer == buffer) {+			dev->tempBuffer[i].line = 0;+			return;+		}+	}++	if (buffer) {+		/* assume it is an unmanaged one. */+		T(YAFFS_TRACE_BUFFERS,+		  (TSTR("Releasing unmanaged temp buffer in line %d" TENDSTR),+		   lineNo));+		YFREE(buffer);+		dev->unmanagedTempDeallocations++;+	}++}++/*+ * Determine if we have a managed buffer.+ */+int yaffs_IsManagedTempBuffer(yaffs_Device *dev, const __u8 *buffer)+{+	int i;++	for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {+		if (dev->tempBuffer[i].buffer == buffer)+			return 1;+	}++	for (i = 0; i < dev->nShortOpCaches; i++) {+		if (dev->srCache[i].data == buffer)+			return 1;+	}++	if (buffer == dev->checkpointBuffer)+		return 1;++	T(YAFFS_TRACE_ALWAYS,+		(TSTR("yaffs: unmaged buffer detected.\n" TENDSTR)));+	return 0;+}++++/*+ * Chunk bitmap manipulations+ */++static Y_INLINE __u8 *yaffs_BlockBits(yaffs_Device *dev, int blk)+{+	if (blk < dev->internalStartBlock || blk > dev->internalEndBlock) {+		T(YAFFS_TRACE_ERROR,+			(TSTR("**>> yaffs: BlockBits block %d is not valid" TENDSTR),+			blk));+		YBUG();+	}+	return dev->chunkBits ++		(dev->chunkBitmapStride * (blk - dev->internalStartBlock));+}++static Y_INLINE void yaffs_VerifyChunkBitId(yaffs_Device *dev, int blk, int chunk)+{+	if (blk < dev->internalStartBlock || blk > dev->internalEndBlock ||+			chunk < 0 || chunk >= dev->nChunksPerBlock) {+		T(YAFFS_TRACE_ERROR,+		(TSTR("**>> yaffs: Chunk Id (%d:%d) invalid"TENDSTR),+			blk, chunk));+		YBUG();+	}+}++static Y_INLINE void yaffs_ClearChunkBits(yaffs_Device *dev, int blk)+{+	__u8 *blkBits = yaffs_BlockBits(dev, blk);++	memset(blkBits, 0, dev->chunkBitmapStride);+}++static Y_INLINE void yaffs_ClearChunkBit(yaffs_Device *dev, int blk, int chunk)+{+	__u8 *blkBits = yaffs_BlockBits(dev, blk);++	yaffs_VerifyChunkBitId(dev, blk, chunk);++	blkBits[chunk / 8] &= ~(1 << (chunk & 7));+}++static Y_INLINE void yaffs_SetChunkBit(yaffs_Device *dev, int blk, int chunk)+{+	__u8 *blkBits = yaffs_BlockBits(dev, blk);++	yaffs_VerifyChunkBitId(dev, blk, chunk);++	blkBits[chunk / 8] |= (1 << (chunk & 7));+}++static Y_INLINE int yaffs_CheckChunkBit(yaffs_Device *dev, int blk, int chunk)+{+	__u8 *blkBits = yaffs_BlockBits(dev, blk);+	yaffs_VerifyChunkBitId(dev, blk, chunk);++	return (blkBits[chunk / 8] & (1 << (chunk & 7))) ? 1 : 0;+}++static Y_INLINE int yaffs_StillSomeChunkBits(yaffs_Device *dev, int blk)+{+	__u8 *blkBits = yaffs_BlockBits(dev, blk);+	int i;+	for (i = 0; i < dev->chunkBitmapStride; i++) {+		if (*blkBits)+			return 1;+		blkBits++;+	}+	return 0;+}++static int yaffs_CountChunkBits(yaffs_Device *dev, int blk)+{+	__u8 *blkBits = yaffs_BlockBits(dev, blk);+	int i;+	int n = 0;+	for (i = 0; i < dev->chunkBitmapStride; i++) {+		__u8 x = *blkBits;+		while (x) {+			if (x & 1)+				n++;+			x >>= 1;+		}++		blkBits++;+	}+	return n;+}++/*+ * Verification code+ */++static int yaffs_SkipVerification(yaffs_Device *dev)+{+	return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY | YAFFS_TRACE_VERIFY_FULL));+}++static int yaffs_SkipFullVerification(yaffs_Device *dev)+{+	return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_FULL));+}++static int yaffs_SkipNANDVerification(yaffs_Device *dev)+{+	return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_NAND));+}++static const char *blockStateName[] = {+"Unknown",+"Needs scanning",+"Scanning",+"Empty",+"Allocating",+"Full",+"Dirty",+"Checkpoint",+"Collecting",+"Dead"+};++static void yaffs_VerifyBlock(yaffs_Device *dev, yaffs_BlockInfo *bi, int n)+{+	int actuallyUsed;+	int inUse;++	if (yaffs_SkipVerification(dev))+		return;++	/* Report illegal runtime states */+	if (bi->blockState >= YAFFS_NUMBER_OF_BLOCK_STATES)+		T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has undefined state %d"TENDSTR), n, bi->blockState));++	switch (bi->blockState) {+	case YAFFS_BLOCK_STATE_UNKNOWN:+	case YAFFS_BLOCK_STATE_SCANNING:+	case YAFFS_BLOCK_STATE_NEEDS_SCANNING:+		T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has bad run-state %s"TENDSTR),+		n, blockStateName[bi->blockState]));+	}++	/* Check pages in use and soft deletions are legal */++	actuallyUsed = bi->pagesInUse - bi->softDeletions;++	if (bi->pagesInUse < 0 || bi->pagesInUse > dev->nChunksPerBlock ||+	   bi->softDeletions < 0 || bi->softDeletions > dev->nChunksPerBlock ||+	   actuallyUsed < 0 || actuallyUsed > dev->nChunksPerBlock)+		T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has illegal values pagesInUsed %d softDeletions %d"TENDSTR),+		n, bi->pagesInUse, bi->softDeletions));+++	/* Check chunk bitmap legal */+	inUse = yaffs_CountChunkBits(dev, n);+	if (inUse != bi->pagesInUse)+		T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has inconsistent values pagesInUse %d counted chunk bits %d"TENDSTR),+			n, bi->pagesInUse, inUse));++	/* Check that the sequence number is valid.+	 * Ten million is legal, but is very unlikely+	 */+	if (dev->isYaffs2 &&+	   (bi->blockState == YAFFS_BLOCK_STATE_ALLOCATING || bi->blockState == YAFFS_BLOCK_STATE_FULL) &&+	   (bi->sequenceNumber < YAFFS_LOWEST_SEQUENCE_NUMBER || bi->sequenceNumber > 10000000))+		T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has suspect sequence number of %d"TENDSTR),+		n, bi->sequenceNumber));+}++static void yaffs_VerifyCollectedBlock(yaffs_Device *dev, yaffs_BlockInfo *bi,+		int n)+{+	yaffs_VerifyBlock(dev, bi, n);++	/* After collection the block should be in the erased state */+	/* This will need to change if we do partial gc */++	if (bi->blockState != YAFFS_BLOCK_STATE_COLLECTING &&+			bi->blockState != YAFFS_BLOCK_STATE_EMPTY) {+		T(YAFFS_TRACE_ERROR, (TSTR("Block %d is in state %d after gc, should be erased"TENDSTR),+			n, bi->blockState));+	}+}++static void yaffs_VerifyBlocks(yaffs_Device *dev)+{+	int i;+	int nBlocksPerState[YAFFS_NUMBER_OF_BLOCK_STATES];+	int nIllegalBlockStates = 0;++	if (yaffs_SkipVerification(dev))+		return;++	memset(nBlocksPerState, 0, sizeof(nBlocksPerState));++	for (i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) {+		yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, i);+		yaffs_VerifyBlock(dev, bi, i);++		if (bi->blockState < YAFFS_NUMBER_OF_BLOCK_STATES)+			nBlocksPerState[bi->blockState]++;+		else+			nIllegalBlockStates++;+	}++	T(YAFFS_TRACE_VERIFY, (TSTR(""TENDSTR)));+	T(YAFFS_TRACE_VERIFY, (TSTR("Block summary"TENDSTR)));++	T(YAFFS_TRACE_VERIFY, (TSTR("%d blocks have illegal states"TENDSTR), nIllegalBlockStates));+	if (nBlocksPerState[YAFFS_BLOCK_STATE_ALLOCATING] > 1)+		T(YAFFS_TRACE_VERIFY, (TSTR("Too many allocating blocks"TENDSTR)));++	for (i = 0; i < YAFFS_NUMBER_OF_BLOCK_STATES; i++)+		T(YAFFS_TRACE_VERIFY,+		  (TSTR("%s %d blocks"TENDSTR),+		  blockStateName[i], nBlocksPerState[i]));++	if (dev->blocksInCheckpoint != nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT])+		T(YAFFS_TRACE_VERIFY,+		 (TSTR("Checkpoint block count wrong dev %d count %d"TENDSTR),+		 dev->blocksInCheckpoint, nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT]));++	if (dev->nErasedBlocks != nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY])+		T(YAFFS_TRACE_VERIFY,+		 (TSTR("Erased block count wrong dev %d count %d"TENDSTR),+		 dev->nErasedBlocks, nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY]));++	if (nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING] > 1)+		T(YAFFS_TRACE_VERIFY,+		 (TSTR("Too many collecting blocks %d (max is 1)"TENDSTR),+		 nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING]));++	T(YAFFS_TRACE_VERIFY, (TSTR(""TENDSTR)));++}++/*+ * Verify the object header. oh must be valid, but obj and tags may be NULL in which+ * case those tests will not be performed.+ */+static void yaffs_VerifyObjectHeader(yaffs_Object *obj, yaffs_ObjectHeader *oh, yaffs_ExtendedTags *tags, int parentCheck)+{+	if (obj && yaffs_SkipVerification(obj->myDev))+		return;++	if (!(tags && obj && oh)) {+		T(YAFFS_TRACE_VERIFY,+				(TSTR("Verifying object header tags %x obj %x oh %x"TENDSTR),+				(__u32)tags, (__u32)obj, (__u32)oh));+		return;+	}++	if (oh->type <= YAFFS_OBJECT_TYPE_UNKNOWN ||+			oh->type > YAFFS_OBJECT_TYPE_MAX)+		T(YAFFS_TRACE_VERIFY,+			(TSTR("Obj %d header type is illegal value 0x%x"TENDSTR),+			tags->objectId, oh->type));++	if (tags->objectId != obj->objectId)+		T(YAFFS_TRACE_VERIFY,+			(TSTR("Obj %d header mismatch objectId %d"TENDSTR),+			tags->objectId, obj->objectId));+++	/*+	 * Check that the object's parent ids match if parentCheck requested.+	 *+	 * Tests do not apply to the root object.+	 */++	if (parentCheck && tags->objectId > 1 && !obj->parent)+		T(YAFFS_TRACE_VERIFY,+			(TSTR("Obj %d header mismatch parentId %d obj->parent is NULL"TENDSTR),+			tags->objectId, oh->parentObjectId));++	if (parentCheck && obj->parent &&+			oh->parentObjectId != obj->parent->objectId &&+			(oh->parentObjectId != YAFFS_OBJECTID_UNLINKED ||+			obj->parent->objectId != YAFFS_OBJECTID_DELETED))+		T(YAFFS_TRACE_VERIFY,+			(TSTR("Obj %d header mismatch parentId %d parentObjectId %d"TENDSTR),+			tags->objectId, oh->parentObjectId, obj->parent->objectId));++	if (tags->objectId > 1 && oh->name[0] == 0) /* Null name */+		T(YAFFS_TRACE_VERIFY,+			(TSTR("Obj %d header name is NULL"TENDSTR),+			obj->objectId));++	if (tags->objectId > 1 && ((__u8)(oh->name[0])) == 0xff) /* Trashed name */+		T(YAFFS_TRACE_VERIFY,+			(TSTR("Obj %d header name is 0xFF"TENDSTR),+			obj->objectId));+}++++static int yaffs_VerifyTnodeWorker(yaffs_Object *obj, yaffs_Tnode *tn,+					__u32 level, int chunkOffset)+{+	int i;+	yaffs_Device *dev = obj->myDev;+	int ok = 1;++	if (tn) {+		if (level > 0) {++			for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) {+				if (tn->internal[i]) {+					ok = yaffs_VerifyTnodeWorker(obj,+							tn->internal[i],+							level - 1,+							(chunkOffset<<YAFFS_TNODES_INTERNAL_BITS) + i);+				}+			}+		} else if (level == 0) {+			yaffs_ExtendedTags tags;+			__u32 objectId = obj->objectId;++			chunkOffset <<=  YAFFS_TNODES_LEVEL0_BITS;++			for (i = 0; i < YAFFS_NTNODES_LEVEL0; i++) {+				__u32 theChunk = yaffs_GetChunkGroupBase(dev, tn, i);++				if (theChunk > 0) {+					/* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),tags.objectId,tags.chunkId,theChunk)); */+					yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL, &tags);+					if (tags.objectId != objectId || tags.chunkId != chunkOffset) {+						T(~0, (TSTR("Object %d chunkId %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR),+							objectId, chunkOffset, theChunk,+							tags.objectId, tags.chunkId));+					}+				}+				chunkOffset++;+			}+		}+	}++	return ok;++}+++static void yaffs_VerifyFile(yaffs_Object *obj)+{+	int requiredTallness;+	int actualTallness;+	__u32 lastChunk;+	__u32 x;+	__u32 i;+	yaffs_Device *dev;+	yaffs_ExtendedTags tags;+	yaffs_Tnode *tn;+	__u32 objectId;++	if (!obj)+		return;++	if (yaffs_SkipVerification(obj->myDev))+		return;++	dev = obj->myDev;+	objectId = obj->objectId;++	/* Check file size is consistent with tnode depth */+	lastChunk =  obj->variant.fileVariant.fileSize / dev->nDataBytesPerChunk + 1;+	x = lastChunk >> YAFFS_TNODES_LEVEL0_BITS;+	requiredTallness = 0;+	while (x > 0) {+		x >>= YAFFS_TNODES_INTERNAL_BITS;+		requiredTallness++;+	}++	actualTallness = obj->variant.fileVariant.topLevel;++	if (requiredTallness > actualTallness)+		T(YAFFS_TRACE_VERIFY,+		(TSTR("Obj %d had tnode tallness %d, needs to be %d"TENDSTR),+		 obj->objectId, actualTallness, requiredTallness));+++	/* Check that the chunks in the tnode tree are all correct.+	 * We do this by scanning through the tnode tree and+	 * checking the tags for every chunk match.+	 */++	if (yaffs_SkipNANDVerification(dev))+		return;++	for (i = 1; i <= lastChunk; i++) {+		tn = yaffs_FindLevel0Tnode(dev, &obj->variant.fileVariant, i);++		if (tn) {+			__u32 theChunk = yaffs_GetChunkGroupBase(dev, tn, i);+			if (theChunk > 0) {+				/* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),objectId,i,theChunk)); */+				yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL, &tags);+				if (tags.objectId != objectId || tags.chunkId != i) {+					T(~0, (TSTR("Object %d chunkId %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR),+						objectId, i, theChunk,+						tags.objectId, tags.chunkId));+				}+			}+		}+	}+}+++static void yaffs_VerifyHardLink(yaffs_Object *obj)+{+	if (obj && yaffs_SkipVerification(obj->myDev))+		return;++	/* Verify sane equivalent object */+}++static void yaffs_VerifySymlink(yaffs_Object *obj)+{+	if (obj && yaffs_SkipVerification(obj->myDev))+		return;++	/* Verify symlink string */+}++static void yaffs_VerifySpecial(yaffs_Object *obj)+{+	if (obj && yaffs_SkipVerification(obj->myDev))+		return;+}++static void yaffs_VerifyObject(yaffs_Object *obj)+{+	yaffs_Device *dev;++	__u32 chunkMin;+	__u32 chunkMax;++	__u32 chunkIdOk;+	__u32 chunkInRange;+	__u32 chunkShouldNotBeDeleted;+	__u32 chunkValid;++	if (!obj)+		return;++	if (obj->beingCreated)+		return;++	dev = obj->myDev;++	if (yaffs_SkipVerification(dev))+		return;++	/* Check sane object header chunk */++	chunkMin = dev->internalStartBlock * dev->nChunksPerBlock;+	chunkMax = (dev->internalEndBlock+1) * dev->nChunksPerBlock - 1;++	chunkInRange = (((unsigned)(obj->hdrChunk)) >= chunkMin && ((unsigned)(obj->hdrChunk)) <= chunkMax);+	chunkIdOk = chunkInRange || obj->hdrChunk == 0;+	chunkValid = chunkInRange &&+			yaffs_CheckChunkBit(dev,+					obj->hdrChunk / dev->nChunksPerBlock,+					obj->hdrChunk % dev->nChunksPerBlock);+	chunkShouldNotBeDeleted = chunkInRange && !chunkValid;++	if (!obj->fake &&+			(!chunkIdOk || chunkShouldNotBeDeleted)) {+		T(YAFFS_TRACE_VERIFY,+			(TSTR("Obj %d has chunkId %d %s %s"TENDSTR),+			obj->objectId, obj->hdrChunk,+			chunkIdOk ? "" : ",out of range",+			chunkShouldNotBeDeleted ? ",marked as deleted" : ""));+	}++	if (chunkValid && !yaffs_SkipNANDVerification(dev)) {+		yaffs_ExtendedTags tags;+		yaffs_ObjectHeader *oh;+		__u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__);++		oh = (yaffs_ObjectHeader *)buffer;++		yaffs_ReadChunkWithTagsFromNAND(dev, obj->hdrChunk, buffer,+				&tags);++		yaffs_VerifyObjectHeader(obj, oh, &tags, 1);++		yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);+	}++	/* Verify it has a parent */+	if (obj && !obj->fake &&+			(!obj->parent || obj->parent->myDev != dev)) {+		T(YAFFS_TRACE_VERIFY,+			(TSTR("Obj %d has parent pointer %p which does not look like an object"TENDSTR),+			obj->objectId, obj->parent));+	}++	/* Verify parent is a directory */+	if (obj->parent && obj->parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {+		T(YAFFS_TRACE_VERIFY,+			(TSTR("Obj %d's parent is not a directory (type %d)"TENDSTR),+			obj->objectId, obj->parent->variantType));+	}++	switch (obj->variantType) {+	case YAFFS_OBJECT_TYPE_FILE:+		yaffs_VerifyFile(obj);+		break;+	case YAFFS_OBJECT_TYPE_SYMLINK:+		yaffs_VerifySymlink(obj);+		break;+	case YAFFS_OBJECT_TYPE_DIRECTORY:+		yaffs_VerifyDirectory(obj);+		break;+	case YAFFS_OBJECT_TYPE_HARDLINK:+		yaffs_VerifyHardLink(obj);+		break;+	case YAFFS_OBJECT_TYPE_SPECIAL:+		yaffs_VerifySpecial(obj);+		break;+	case YAFFS_OBJECT_TYPE_UNKNOWN:+	default:+		T(YAFFS_TRACE_VERIFY,+		(TSTR("Obj %d has illegaltype %d"TENDSTR),+		obj->objectId, obj->variantType));+		break;+	}+}++static void yaffs_VerifyObjects(yaffs_Device *dev)+{+	yaffs_Object *obj;+	int i;+	struct ylist_head *lh;++	if (yaffs_SkipVerification(dev))+		return;++	/* Iterate through the objects in each hash entry */++	for (i = 0; i <  YAFFS_NOBJECT_BUCKETS; i++) {+		ylist_for_each(lh, &dev->objectBucket[i].list) {+			if (lh) {+				obj = ylist_entry(lh, yaffs_Object, hashLink);+				yaffs_VerifyObject(obj);+			}+		}+	}+}+++/*+ *  Simple hash function. Needs to have a reasonable spread+ */++static Y_INLINE int yaffs_HashFunction(int n)+{+	n = abs(n);+	return n % YAFFS_NOBJECT_BUCKETS;+}++/*+ * Access functions to useful fake objects.+ * Note that root might have a presence in NAND if permissions are set.+ */++yaffs_Object *yaffs_Root(yaffs_Device *dev)+{+	return dev->rootDir;+}++yaffs_Object *yaffs_LostNFound(yaffs_Device *dev)+{+	return dev->lostNFoundDir;+}+++/*+ *  Erased NAND checking functions+ */++int yaffs_CheckFF(__u8 *buffer, int nBytes)+{+	/* Horrible, slow implementation */+	while (nBytes--) {+		if (*buffer != 0xFF)+			return 0;+		buffer++;+	}+	return 1;+}++static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,+				int chunkInNAND)+{+	int retval = YAFFS_OK;+	__u8 *data = yaffs_GetTempBuffer(dev, __LINE__);+	yaffs_ExtendedTags tags;+	int result;++	result = yaffs_ReadChunkWithTagsFromNAND(dev, chunkInNAND, data, &tags);++	if (tags.eccResult > YAFFS_ECC_RESULT_NO_ERROR)+		retval = YAFFS_FAIL;++	if (!yaffs_CheckFF(data, dev->nDataBytesPerChunk) || tags.chunkUsed) {+		T(YAFFS_TRACE_NANDACCESS,+		  (TSTR("Chunk %d not erased" TENDSTR), chunkInNAND));+		retval = YAFFS_FAIL;+	}++	yaffs_ReleaseTempBuffer(dev, data, __LINE__);++	return retval;++}++static int yaffs_WriteNewChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev,+					const __u8 *data,+					yaffs_ExtendedTags *tags,+					int useReserve)+{+	int attempts = 0;+	int writeOk = 0;+	int chunk;++	yaffs_InvalidateCheckpoint(dev);++	do {+		yaffs_BlockInfo *bi = 0;+		int erasedOk = 0;++		chunk = yaffs_AllocateChunk(dev, useReserve, &bi);+		if (chunk < 0) {+			/* no space */+			break;+		}++		/* First check this chunk is erased, if it needs+		 * checking.  The checking policy (unless forced+		 * always on) is as follows:+		 *+		 * Check the first page we try to write in a block.+		 * If the check passes then we don't need to check any+		 * more.	If the check fails, we check again...+		 * If the block has been erased, we don't need to check.+		 *+		 * However, if the block has been prioritised for gc,+		 * then we think there might be something odd about+		 * this block and stop using it.+		 *+		 * Rationale: We should only ever see chunks that have+		 * not been erased if there was a partially written+		 * chunk due to power loss.  This checking policy should+		 * catch that case with very few checks and thus save a+		 * lot of checks that are most likely not needed.+		 */+		if (bi->gcPrioritise) {+			yaffs_DeleteChunk(dev, chunk, 1, __LINE__);+			/* try another chunk */+			continue;+		}++		/* let's give it a try */+		attempts++;++#ifdef CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED+		bi->skipErasedCheck = 0;+#endif+		if (!bi->skipErasedCheck) {+			erasedOk = yaffs_CheckChunkErased(dev, chunk);+			if (erasedOk != YAFFS_OK) {+				T(YAFFS_TRACE_ERROR,+				(TSTR("**>> yaffs chunk %d was not erased"+				TENDSTR), chunk));++				/* try another chunk */+				continue;+			}+			bi->skipErasedCheck = 1;+		}++		writeOk = yaffs_WriteChunkWithTagsToNAND(dev, chunk,+				data, tags);+		if (writeOk != YAFFS_OK) {+			yaffs_HandleWriteChunkError(dev, chunk, erasedOk);+			/* try another chunk */+			continue;+		}++		/* Copy the data into the robustification buffer */+		yaffs_HandleWriteChunkOk(dev, chunk, data, tags);++	} while (writeOk != YAFFS_OK &&+		(yaffs_wr_attempts <= 0 || attempts <= yaffs_wr_attempts));++	if (!writeOk)+		chunk = -1;++	if (attempts > 1) {+		T(YAFFS_TRACE_ERROR,+			(TSTR("**>> yaffs write required %d attempts" TENDSTR),+			attempts));++		dev->nRetriedWrites += (attempts - 1);+	}++	return chunk;+}++/*+ * Block retiring for handling a broken block.+ */++static void yaffs_RetireBlock(yaffs_Device *dev, int blockInNAND)+{+	yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockInNAND);++	yaffs_InvalidateCheckpoint(dev);++	if (yaffs_MarkBlockBad(dev, blockInNAND) != YAFFS_OK) {+		if (yaffs_EraseBlockInNAND(dev, blockInNAND) != YAFFS_OK) {+			T(YAFFS_TRACE_ALWAYS, (TSTR(+				"yaffs: Failed to mark bad and erase block %d"+				TENDSTR), blockInNAND));+		} else {+			yaffs_ExtendedTags tags;+			int chunkId = blockInNAND * dev->nChunksPerBlock;++			__u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__);++			memset(buffer, 0xff, dev->nDataBytesPerChunk);+			yaffs_InitialiseTags(&tags);+			tags.sequenceNumber = YAFFS_SEQUENCE_BAD_BLOCK;+			if (dev->writeChunkWithTagsToNAND(dev, chunkId -+				dev->chunkOffset, buffer, &tags) != YAFFS_OK)+				T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: Failed to "+					TCONT("write bad block marker to block %d")+					TENDSTR), blockInNAND));++			yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);+		}+	}++	bi->blockState = YAFFS_BLOCK_STATE_DEAD;+	bi->gcPrioritise = 0;+	bi->needsRetiring = 0;++	dev->nRetiredBlocks++;+}++/*+ * Functions for robustisizing TODO+ *+ */++static void yaffs_HandleWriteChunkOk(yaffs_Device *dev, int chunkInNAND,+				const __u8 *data,+				const yaffs_ExtendedTags *tags)+{+}++static void yaffs_HandleUpdateChunk(yaffs_Device *dev, int chunkInNAND,+				const yaffs_ExtendedTags *tags)+{+}++void yaffs_HandleChunkError(yaffs_Device *dev, yaffs_BlockInfo *bi)+{+	if (!bi->gcPrioritise) {+		bi->gcPrioritise = 1;+		dev->hasPendingPrioritisedGCs = 1;+		bi->chunkErrorStrikes++;++		if (bi->chunkErrorStrikes > 3) {+			bi->needsRetiring = 1; /* Too many stikes, so retire this */+			T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: Block struck out" TENDSTR)));++		}+	}+}++static void yaffs_HandleWriteChunkError(yaffs_Device *dev, int chunkInNAND,+		int erasedOk)+{+	int blockInNAND = chunkInNAND / dev->nChunksPerBlock;+	yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockInNAND);++	yaffs_HandleChunkError(dev, bi);++	if (erasedOk) {+		/* Was an actual write failure, so mark the block for retirement  */+		bi->needsRetiring = 1;+		T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,+		  (TSTR("**>> Block %d needs retiring" TENDSTR), blockInNAND));+	}++	/* Delete the chunk */+	yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__);+}+++/*---------------- Name handling functions ------------*/++static __u16 yaffs_CalcNameSum(const YCHAR *name)+{+	__u16 sum = 0;+	__u16 i = 1;++	const YUCHAR *bname = (const YUCHAR *) name;+	if (bname) {+		while ((*bname) && (i < (YAFFS_MAX_NAME_LENGTH/2))) {++#ifdef CONFIG_YAFFS_CASE_INSENSITIVE+			sum += yaffs_toupper(*bname) * i;+#else+			sum += (*bname) * i;+#endif+			i++;+			bname++;+		}+	}+	return sum;+}++static void yaffs_SetObjectName(yaffs_Object *obj, const YCHAR *name)+{+#ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM+	memset(obj->shortName, 0, sizeof(YCHAR) * (YAFFS_SHORT_NAME_LENGTH+1));+	if (name && yaffs_strlen(name) <= YAFFS_SHORT_NAME_LENGTH)+		yaffs_strcpy(obj->shortName, name);+	else+		obj->shortName[0] = _Y('\0');+#endif+	obj->sum = yaffs_CalcNameSum(name);+}++/*-------------------- TNODES -------------------++ * List of spare tnodes+ * The list is hooked together using the first pointer+ * in the tnode.+ */++/* yaffs_CreateTnodes creates a bunch more tnodes and+ * adds them to the tnode free list.+ * Don't use this function directly+ */++static int yaffs_CreateTnodes(yaffs_Device *dev, int nTnodes)+{+	int i;+	int tnodeSize;+	yaffs_Tnode *newTnodes;+	__u8 *mem;+	yaffs_Tnode *curr;+	yaffs_Tnode *next;+	yaffs_TnodeList *tnl;++	if (nTnodes < 1)+		return YAFFS_OK;++	/* Calculate the tnode size in bytes for variable width tnode support.+	 * Must be a multiple of 32-bits  */+	tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;++	if (tnodeSize < sizeof(yaffs_Tnode))+		tnodeSize = sizeof(yaffs_Tnode);++	/* make these things */++	newTnodes = YMALLOC(nTnodes * tnodeSize);+	mem = (__u8 *)newTnodes;++	if (!newTnodes) {+		T(YAFFS_TRACE_ERROR,+			(TSTR("yaffs: Could not allocate Tnodes" TENDSTR)));+		return YAFFS_FAIL;+	}++	/* Hook them into the free list */+#if 0+	for (i = 0; i < nTnodes - 1; i++) {+		newTnodes[i].internal[0] = &newTnodes[i + 1];+#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG+		newTnodes[i].internal[YAFFS_NTNODES_INTERNAL] = (void *)1;+#endif+	}++	newTnodes[nTnodes - 1].internal[0] = dev->freeTnodes;+#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG+	newTnodes[nTnodes - 1].internal[YAFFS_NTNODES_INTERNAL] = (void *)1;+#endif+	dev->freeTnodes = newTnodes;+#else+	/* New hookup for wide tnodes */+	for (i = 0; i < nTnodes - 1; i++) {+		curr = (yaffs_Tnode *) &mem[i * tnodeSize];+		next = (yaffs_Tnode *) &mem[(i+1) * tnodeSize];+		curr->internal[0] = next;+	}++	curr = (yaffs_Tnode *) &mem[(nTnodes - 1) * tnodeSize];+	curr->internal[0] = dev->freeTnodes;+	dev->freeTnodes = (yaffs_Tnode *)mem;++#endif+++	dev->nFreeTnodes += nTnodes;+	dev->nTnodesCreated += nTnodes;++	/* Now add this bunch of tnodes to a list for freeing up.+	 * NB If we can't add this to the management list it isn't fatal+	 * but it just means we can't free this bunch of tnodes later.+	 */++	tnl = YMALLOC(sizeof(yaffs_TnodeList));+	if (!tnl) {+		T(YAFFS_TRACE_ERROR,+		  (TSTR+		   ("yaffs: Could not add tnodes to management list" TENDSTR)));+		   return YAFFS_FAIL;+	} else {+		tnl->tnodes = newTnodes;+		tnl->next = dev->allocatedTnodeList;+		dev->allocatedTnodeList = tnl;+	}++	T(YAFFS_TRACE_ALLOCATE, (TSTR("yaffs: Tnodes added" TENDSTR)));++	return YAFFS_OK;+}++/* GetTnode gets us a clean tnode. Tries to make allocate more if we run out */++static yaffs_Tnode *yaffs_GetTnodeRaw(yaffs_Device *dev)+{+	yaffs_Tnode *tn = NULL;++	/* If there are none left make more */+	if (!dev->freeTnodes)+		yaffs_CreateTnodes(dev, YAFFS_ALLOCATION_NTNODES);++	if (dev->freeTnodes) {+		tn = dev->freeTnodes;+#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG+		if (tn->internal[YAFFS_NTNODES_INTERNAL] != (void *)1) {+			/* Hoosterman, this thing looks like it isn't in the list */+			T(YAFFS_TRACE_ALWAYS,+			  (TSTR("yaffs: Tnode list bug 1" TENDSTR)));+		}+#endif+		dev->freeTnodes = dev->freeTnodes->internal[0];+		dev->nFreeTnodes--;+	}++	dev->nCheckpointBlocksRequired = 0; /* force recalculation*/++	return tn;+}++static yaffs_Tnode *yaffs_GetTnode(yaffs_Device *dev)+{+	yaffs_Tnode *tn = yaffs_GetTnodeRaw(dev);+	int tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;++	if (tnodeSize < sizeof(yaffs_Tnode))+		tnodeSize = sizeof(yaffs_Tnode);++	if (tn)+		memset(tn, 0, tnodeSize);++	return tn;+}++/* FreeTnode frees up a tnode and puts it back on the free list */+static void yaffs_FreeTnode(yaffs_Device *dev, yaffs_Tnode *tn)+{+	if (tn) {+#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG+		if (tn->internal[YAFFS_NTNODES_INTERNAL] != 0) {+			/* Hoosterman, this thing looks like it is already in the list */+			T(YAFFS_TRACE_ALWAYS,+			  (TSTR("yaffs: Tnode list bug 2" TENDSTR)));+		}+		tn->internal[YAFFS_NTNODES_INTERNAL] = (void *)1;+#endif+		tn->internal[0] = dev->freeTnodes;+		dev->freeTnodes = tn;+		dev->nFreeTnodes++;+	}+	dev->nCheckpointBlocksRequired = 0; /* force recalculation*/+}++static void yaffs_DeinitialiseTnodes(yaffs_Device *dev)+{+	/* Free the list of allocated tnodes */+	yaffs_TnodeList *tmp;++	while (dev->allocatedTnodeList) {+		tmp = dev->allocatedTnodeList->next;++		YFREE(dev->allocatedTnodeList->tnodes);+		YFREE(dev->allocatedTnodeList);+		dev->allocatedTnodeList = tmp;++	}++	dev->freeTnodes = NULL;+	dev->nFreeTnodes = 0;+}++static void yaffs_InitialiseTnodes(yaffs_Device *dev)+{+	dev->allocatedTnodeList = NULL;+	dev->freeTnodes = NULL;+	dev->nFreeTnodes = 0;+	dev->nTnodesCreated = 0;+}+++void yaffs_PutLevel0Tnode(yaffs_Device *dev, yaffs_Tnode *tn, unsigned pos,+		unsigned val)+{+	__u32 *map = (__u32 *)tn;+	__u32 bitInMap;+	__u32 bitInWord;+	__u32 wordInMap;+	__u32 mask;++	pos &= YAFFS_TNODES_LEVEL0_MASK;+	val >>= dev->chunkGroupBits;++	bitInMap = pos * dev->tnodeWidth;+	wordInMap = bitInMap / 32;+	bitInWord = bitInMap & (32 - 1);++	mask = dev->tnodeMask << bitInWord;++	map[wordInMap] &= ~mask;+	map[wordInMap] |= (mask & (val << bitInWord));++	if (dev->tnodeWidth > (32 - bitInWord)) {+		bitInWord = (32 - bitInWord);+		wordInMap++;;+		mask = dev->tnodeMask >> (/*dev->tnodeWidth -*/ bitInWord);+		map[wordInMap] &= ~mask;+		map[wordInMap] |= (mask & (val >> bitInWord));+	}+}++static __u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn,+		unsigned pos)+{+	__u32 *map = (__u32 *)tn;+	__u32 bitInMap;+	__u32 bitInWord;+	__u32 wordInMap;+	__u32 val;++	pos &= YAFFS_TNODES_LEVEL0_MASK;++	bitInMap = pos * dev->tnodeWidth;+	wordInMap = bitInMap / 32;+	bitInWord = bitInMap & (32 - 1);++	val = map[wordInMap] >> bitInWord;++	if	(dev->tnodeWidth > (32 - bitInWord)) {+		bitInWord = (32 - bitInWord);+		wordInMap++;;+		val |= (map[wordInMap] << bitInWord);+	}++	val &= dev->tnodeMask;+	val <<= dev->chunkGroupBits;++	return val;+}++/* ------------------- End of individual tnode manipulation -----------------*/++/* ---------Functions to manipulate the look-up tree (made up of tnodes) ------+ * The look up tree is represented by the top tnode and the number of topLevel+ * in the tree. 0 means only the level 0 tnode is in the tree.+ */++/* FindLevel0Tnode finds the level 0 tnode, if one exists. */+static yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device *dev,+					yaffs_FileStructure *fStruct,+					__u32 chunkId)+{+	yaffs_Tnode *tn = fStruct->top;+	__u32 i;+	int requiredTallness;+	int level = fStruct->topLevel;++	/* Check sane level and chunk Id */+	if (level < 0 || level > YAFFS_TNODES_MAX_LEVEL)+		return NULL;++	if (chunkId > YAFFS_MAX_CHUNK_ID)+		return NULL;++	/* First check we're tall enough (ie enough topLevel) */++	i = chunkId >> YAFFS_TNODES_LEVEL0_BITS;+	requiredTallness = 0;+	while (i) {+		i >>= YAFFS_TNODES_INTERNAL_BITS;+		requiredTallness++;+	}++	if (requiredTallness > fStruct->topLevel)+		return NULL; /* Not tall enough, so we can't find it */++	/* Traverse down to level 0 */+	while (level > 0 && tn) {+		tn = tn->internal[(chunkId >>+			(YAFFS_TNODES_LEVEL0_BITS ++				(level - 1) *+				YAFFS_TNODES_INTERNAL_BITS)) &+			YAFFS_TNODES_INTERNAL_MASK];+		level--;+	}++	return tn;+}++/* AddOrFindLevel0Tnode finds the level 0 tnode if it exists, otherwise first expands the tree.+ * This happens in two steps:+ *  1. If the tree isn't tall enough, then make it taller.+ *  2. Scan down the tree towards the level 0 tnode adding tnodes if required.+ *+ * Used when modifying the tree.+ *+ *  If the tn argument is NULL, then a fresh tnode will be added otherwise the specified tn will+ *  be plugged into the ttree.+ */++static yaffs_Tnode *yaffs_AddOrFindLevel0Tnode(yaffs_Device *dev,+					yaffs_FileStructure *fStruct,+					__u32 chunkId,+					yaffs_Tnode *passedTn)+{+	int requiredTallness;+	int i;+	int l;+	yaffs_Tnode *tn;++	__u32 x;+++	/* Check sane level and page Id */+	if (fStruct->topLevel < 0 || fStruct->topLevel > YAFFS_TNODES_MAX_LEVEL)+		return NULL;++	if (chunkId > YAFFS_MAX_CHUNK_ID)+		return NULL;++	/* First check we're tall enough (ie enough topLevel) */++	x = chunkId >> YAFFS_TNODES_LEVEL0_BITS;+	requiredTallness = 0;+	while (x) {+		x >>= YAFFS_TNODES_INTERNAL_BITS;+		requiredTallness++;+	}+++	if (requiredTallness > fStruct->topLevel) {+		/* Not tall enough, gotta make the tree taller */+		for (i = fStruct->topLevel; i < requiredTallness; i++) {++			tn = yaffs_GetTnode(dev);++			if (tn) {+				tn->internal[0] = fStruct->top;+				fStruct->top = tn;+			} else {+				T(YAFFS_TRACE_ERROR,+				  (TSTR("yaffs: no more tnodes" TENDSTR)));+			}+		}++		fStruct->topLevel = requiredTallness;+	}++	/* Traverse down to level 0, adding anything we need */++	l = fStruct->topLevel;+	tn = fStruct->top;++	if (l > 0) {+		while (l > 0 && tn) {+			x = (chunkId >>+			     (YAFFS_TNODES_LEVEL0_BITS ++			      (l - 1) * YAFFS_TNODES_INTERNAL_BITS)) &+			    YAFFS_TNODES_INTERNAL_MASK;+++			if ((l > 1) && !tn->internal[x]) {+				/* Add missing non-level-zero tnode */+				tn->internal[x] = yaffs_GetTnode(dev);++			} else if (l == 1) {+				/* Looking from level 1 at level 0 */+				if (passedTn) {+					/* If we already have one, then release it.*/+					if (tn->internal[x])+						yaffs_FreeTnode(dev, tn->internal[x]);+					tn->internal[x] = passedTn;++				} else if (!tn->internal[x]) {+					/* Don't have one, none passed in */+					tn->internal[x] = yaffs_GetTnode(dev);+				}+			}++			tn = tn->internal[x];+			l--;+		}+	} else {+		/* top is level 0 */+		if (passedTn) {+			memcpy(tn, passedTn, (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8);+			yaffs_FreeTnode(dev, passedTn);+		}+	}++	return tn;+}++static int yaffs_FindChunkInGroup(yaffs_Device *dev, int theChunk,+				yaffs_ExtendedTags *tags, int objectId,+				int chunkInInode)+{+	int j;++	for (j = 0; theChunk && j < dev->chunkGroupSize; j++) {+		if (yaffs_CheckChunkBit(dev, theChunk / dev->nChunksPerBlock,+				theChunk % dev->nChunksPerBlock)) {+			yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL,+							tags);+			if (yaffs_TagsMatch(tags, objectId, chunkInInode)) {+				/* found it; */+				return theChunk;+			}+		}+		theChunk++;+	}+	return -1;+}+++/* DeleteWorker scans backwards through the tnode tree and deletes all the+ * chunks and tnodes in the file+ * Returns 1 if the tree was deleted.+ * Returns 0 if it stopped early due to hitting the limit and the delete is incomplete.+ */++static int yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level,+			      int chunkOffset, int *limit)+{+	int i;+	int chunkInInode;+	int theChunk;+	yaffs_ExtendedTags tags;+	int foundChunk;+	yaffs_Device *dev = in->myDev;++	int allDone = 1;++	if (tn) {+		if (level > 0) {+			for (i = YAFFS_NTNODES_INTERNAL - 1; allDone && i >= 0;+			     i--) {+				if (tn->internal[i]) {+					if (limit && (*limit) < 0) {+						allDone = 0;+					} else {+						allDone =+							yaffs_DeleteWorker(in,+								tn->+								internal+								[i],+								level -+								1,+								(chunkOffset+									<<+									YAFFS_TNODES_INTERNAL_BITS)+								+ i,+								limit);+					}+					if (allDone) {+						yaffs_FreeTnode(dev,+								tn->+								internal[i]);+						tn->internal[i] = NULL;+					}+				}+			}+			return (allDone) ? 1 : 0;+		} else if (level == 0) {+			int hitLimit = 0;++			for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0 && !hitLimit;+					i--) {+				theChunk = yaffs_GetChunkGroupBase(dev, tn, i);+				if (theChunk) {++					chunkInInode = (chunkOffset <<+						YAFFS_TNODES_LEVEL0_BITS) + i;++					foundChunk =+						yaffs_FindChunkInGroup(dev,+								theChunk,+								&tags,+								in->objectId,+								chunkInInode);++					if (foundChunk > 0) {+						yaffs_DeleteChunk(dev,+								  foundChunk, 1,+								  __LINE__);+						in->nDataChunks--;+						if (limit) {+							*limit = *limit - 1;+							if (*limit <= 0)+								hitLimit = 1;+						}++					}++					yaffs_PutLevel0Tnode(dev, tn, i, 0);+				}++			}+			return (i < 0) ? 1 : 0;++		}++	}++	return 1;++}++static void yaffs_SoftDeleteChunk(yaffs_Device *dev, int chunk)+{+	yaffs_BlockInfo *theBlock;++	T(YAFFS_TRACE_DELETION, (TSTR("soft delete chunk %d" TENDSTR), chunk));++	theBlock = yaffs_GetBlockInfo(dev, chunk / dev->nChunksPerBlock);+	if (theBlock) {+		theBlock->softDeletions++;+		dev->nFreeChunks++;+	}+}++/* SoftDeleteWorker scans backwards through the tnode tree and soft deletes all the chunks in the file.+ * All soft deleting does is increment the block's softdelete count and pulls the chunk out+ * of the tnode.+ * Thus, essentially this is the same as DeleteWorker except that the chunks are soft deleted.+ */++static int yaffs_SoftDeleteWorker(yaffs_Object *in, yaffs_Tnode *tn,+				  __u32 level, int chunkOffset)+{+	int i;+	int theChunk;+	int allDone = 1;+	yaffs_Device *dev = in->myDev;++	if (tn) {+		if (level > 0) {++			for (i = YAFFS_NTNODES_INTERNAL - 1; allDone && i >= 0;+			     i--) {+				if (tn->internal[i]) {+					allDone =+					    yaffs_SoftDeleteWorker(in,+								   tn->+								   internal[i],+								   level - 1,+								   (chunkOffset+								    <<+								    YAFFS_TNODES_INTERNAL_BITS)+								   + i);+					if (allDone) {+						yaffs_FreeTnode(dev,+								tn->+								internal[i]);+						tn->internal[i] = NULL;+					} else {+						/* Hoosterman... how could this happen? */+					}+				}+			}+			return (allDone) ? 1 : 0;+		} else if (level == 0) {++			for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0; i--) {+				theChunk = yaffs_GetChunkGroupBase(dev, tn, i);+				if (theChunk) {+					/* Note this does not find the real chunk, only the chunk group.+					 * We make an assumption that a chunk group is not larger than+					 * a block.+					 */+					yaffs_SoftDeleteChunk(dev, theChunk);+					yaffs_PutLevel0Tnode(dev, tn, i, 0);+				}++			}+			return 1;++		}++	}++	return 1;++}++static void yaffs_SoftDeleteFile(yaffs_Object *obj)+{+	if (obj->deleted &&+	    obj->variantType == YAFFS_OBJECT_TYPE_FILE && !obj->softDeleted) {+		if (obj->nDataChunks <= 0) {+			/* Empty file with no duplicate object headers, just delete it immediately */+			yaffs_FreeTnode(obj->myDev,+					obj->variant.fileVariant.top);+			obj->variant.fileVariant.top = NULL;+			T(YAFFS_TRACE_TRACING,+			  (TSTR("yaffs: Deleting empty file %d" TENDSTR),+			   obj->objectId));+			yaffs_DoGenericObjectDeletion(obj);+		} else {+			yaffs_SoftDeleteWorker(obj,+					       obj->variant.fileVariant.top,+					       obj->variant.fileVariant.+					       topLevel, 0);+			obj->softDeleted = 1;+		}+	}+}++/* Pruning removes any part of the file structure tree that is beyond the+ * bounds of the file (ie that does not point to chunks).+ *+ * A file should only get pruned when its size is reduced.+ *+ * Before pruning, the chunks must be pulled from the tree and the+ * level 0 tnode entries must be zeroed out.+ * Could also use this for file deletion, but that's probably better handled+ * by a special case.+ */++static yaffs_Tnode *yaffs_PruneWorker(yaffs_Device *dev, yaffs_Tnode *tn,+				__u32 level, int del0)+{+	int i;+	int hasData;++	if (tn) {+		hasData = 0;++		for (i = 0; i < YAFFS_NTNODES_INTERNAL; i++) {+			if (tn->internal[i] && level > 0) {+				tn->internal[i] =+				    yaffs_PruneWorker(dev, tn->internal[i],+						      level - 1,+						      (i == 0) ? del0 : 1);+			}++			if (tn->internal[i])+				hasData++;+		}++		if (hasData == 0 && del0) {+			/* Free and return NULL */++			yaffs_FreeTnode(dev, tn);+			tn = NULL;+		}++	}++	return tn;++}++static int yaffs_PruneFileStructure(yaffs_Device *dev,+				yaffs_FileStructure *fStruct)+{+	int i;+	int hasData;+	int done = 0;+	yaffs_Tnode *tn;++	if (fStruct->topLevel > 0) {+		fStruct->top =+		    yaffs_PruneWorker(dev, fStruct->top, fStruct->topLevel, 0);++		/* Now we have a tree with all the non-zero branches NULL but the height+		 * is the same as it was.+		 * Let's see if we can trim internal tnodes to shorten the tree.+		 * We can do this if only the 0th element in the tnode is in use+		 * (ie all the non-zero are NULL)+		 */++		while (fStruct->topLevel && !done) {+			tn = fStruct->top;++			hasData = 0;+			for (i = 1; i < YAFFS_NTNODES_INTERNAL; i++) {+				if (tn->internal[i])+					hasData++;+			}++			if (!hasData) {+				fStruct->top = tn->internal[0];+				fStruct->topLevel--;+				yaffs_FreeTnode(dev, tn);+			} else {+				done = 1;+			}+		}+	}++	return YAFFS_OK;+}++/*-------------------- End of File Structure functions.-------------------*/++/* yaffs_CreateFreeObjects creates a bunch more objects and+ * adds them to the object free list.+ */+static int yaffs_CreateFreeObjects(yaffs_Device *dev, int nObjects)+{+	int i;+	yaffs_Object *newObjects;+	yaffs_ObjectList *list;++	if (nObjects < 1)+		return YAFFS_OK;++	/* make these things */+	newObjects = YMALLOC(nObjects * sizeof(yaffs_Object));+	list = YMALLOC(sizeof(yaffs_ObjectList));++	if (!newObjects || !list) {+		if (newObjects)+			YFREE(newObjects);+		if (list)+			YFREE(list);+		T(YAFFS_TRACE_ALLOCATE,+		  (TSTR("yaffs: Could not allocate more objects" TENDSTR)));+		return YAFFS_FAIL;+	}++	/* Hook them into the free list */+	for (i = 0; i < nObjects - 1; i++) {+		newObjects[i].siblings.next =+				(struct ylist_head *)(&newObjects[i + 1]);+	}++	newObjects[nObjects - 1].siblings.next = (void *)dev->freeObjects;+	dev->freeObjects = newObjects;+	dev->nFreeObjects += nObjects;+	dev->nObjectsCreated += nObjects;++	/* Now add this bunch of Objects to a list for freeing up. */++	list->objects = newObjects;+	list->next = dev->allocatedObjectList;+	dev->allocatedObjectList = list;++	return YAFFS_OK;+}+++/* AllocateEmptyObject gets us a clean Object. Tries to make allocate more if we run out */+static yaffs_Object *yaffs_AllocateEmptyObject(yaffs_Device *dev)+{+	yaffs_Object *tn = NULL;++#ifdef VALGRIND_TEST+	tn = YMALLOC(sizeof(yaffs_Object));+#else+	/* If there are none left make more */+	if (!dev->freeObjects)+		yaffs_CreateFreeObjects(dev, YAFFS_ALLOCATION_NOBJECTS);++	if (dev->freeObjects) {+		tn = dev->freeObjects;+		dev->freeObjects =+			(yaffs_Object *) (dev->freeObjects->siblings.next);+		dev->nFreeObjects--;+	}+#endif+	if (tn) {+		/* Now sweeten it up... */++		memset(tn, 0, sizeof(yaffs_Object));+		tn->beingCreated = 1;++		tn->myDev = dev;+		tn->hdrChunk = 0;+		tn->variantType = YAFFS_OBJECT_TYPE_UNKNOWN;+		YINIT_LIST_HEAD(&(tn->hardLinks));+		YINIT_LIST_HEAD(&(tn->hashLink));+		YINIT_LIST_HEAD(&tn->siblings);+++		/* Now make the directory sane */+		if (dev->rootDir) {+			tn->parent = dev->rootDir;+			ylist_add(&(tn->siblings), &dev->rootDir->variant.directoryVariant.children);+		}++		/* Add it to the lost and found directory.+		 * NB Can't put root or lostNFound in lostNFound so+		 * check if lostNFound exists first+		 */+		if (dev->lostNFoundDir)+			yaffs_AddObjectToDirectory(dev->lostNFoundDir, tn);++		tn->beingCreated = 0;+	}++	dev->nCheckpointBlocksRequired = 0; /* force recalculation*/++	return tn;+}++static yaffs_Object *yaffs_CreateFakeDirectory(yaffs_Device *dev, int number,+					       __u32 mode)+{++	yaffs_Object *obj =+	    yaffs_CreateNewObject(dev, number, YAFFS_OBJECT_TYPE_DIRECTORY);+	if (obj) {+		obj->fake = 1;		/* it is fake so it might have no NAND presence... */+		obj->renameAllowed = 0;	/* ... and we're not allowed to rename it... */+		obj->unlinkAllowed = 0;	/* ... or unlink it */+		obj->deleted = 0;+		obj->unlinked = 0;+		obj->yst_mode = mode;+		obj->myDev = dev;+		obj->hdrChunk = 0;	/* Not a valid chunk. */+	}++	return obj;++}++static void yaffs_UnhashObject(yaffs_Object *tn)+{+	int bucket;+	yaffs_Device *dev = tn->myDev;++	/* If it is still linked into the bucket list, free from the list */+	if (!ylist_empty(&tn->hashLink)) {+		ylist_del_init(&tn->hashLink);+		bucket = yaffs_HashFunction(tn->objectId);+		dev->objectBucket[bucket].count--;+	}+}++/*  FreeObject frees up a Object and puts it back on the free list */+static void yaffs_FreeObject(yaffs_Object *tn)+{+	yaffs_Device *dev = tn->myDev;++#ifdef __KERNEL__+	T(YAFFS_TRACE_OS, (TSTR("FreeObject %p inode %p"TENDSTR), tn, tn->myInode));+#endif++	if (tn->parent)+		YBUG();+	if (!ylist_empty(&tn->siblings))+		YBUG();+++#ifdef __KERNEL__+	if (tn->myInode) {+		/* We're still hooked up to a cached inode.+		 * Don't delete now, but mark for later deletion+		 */+		tn->deferedFree = 1;+		return;+	}+#endif++	yaffs_UnhashObject(tn);++#ifdef VALGRIND_TEST+	YFREE(tn);+#else+	/* Link into the free list. */+	tn->siblings.next = (struct ylist_head *)(dev->freeObjects);+	dev->freeObjects = tn;+	dev->nFreeObjects++;+#endif+	dev->nCheckpointBlocksRequired = 0; /* force recalculation*/+}++#ifdef __KERNEL__++void yaffs_HandleDeferedFree(yaffs_Object *obj)+{+	if (obj->deferedFree)+		yaffs_FreeObject(obj);+}++#endif++static void yaffs_DeinitialiseObjects(yaffs_Device *dev)+{+	/* Free the list of allocated Objects */++	yaffs_ObjectList *tmp;++	while (dev->allocatedObjectList) {+		tmp = dev->allocatedObjectList->next;+		YFREE(dev->allocatedObjectList->objects);+		YFREE(dev->allocatedObjectList);++		dev->allocatedObjectList = tmp;+	}++	dev->freeObjects = NULL;+	dev->nFreeObjects = 0;+}++static void yaffs_InitialiseObjects(yaffs_Device *dev)+{+	int i;++	dev->allocatedObjectList = NULL;+	dev->freeObjects = NULL;+	dev->nFreeObjects = 0;++	for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {+		YINIT_LIST_HEAD(&dev->objectBucket[i].list);+		dev->objectBucket[i].count = 0;+	}+}++static int yaffs_FindNiceObjectBucket(yaffs_Device *dev)+{+	static int x;+	int i;+	int l = 999;+	int lowest = 999999;++	/* First let's see if we can find one that's empty. */++	for (i = 0; i < 10 && lowest > 0; i++) {+		x++;+		x %= YAFFS_NOBJECT_BUCKETS;+		if (dev->objectBucket[x].count < lowest) {+			lowest = dev->objectBucket[x].count;+			l = x;+		}++	}++	/* If we didn't find an empty list, then try+	 * looking a bit further for a short one+	 */++	for (i = 0; i < 10 && lowest > 3; i++) {+		x++;+		x %= YAFFS_NOBJECT_BUCKETS;+		if (dev->objectBucket[x].count < lowest) {+			lowest = dev->objectBucket[x].count;+			l = x;+		}++	}++	return l;+}++static int yaffs_CreateNewObjectNumber(yaffs_Device *dev)+{+	int bucket = yaffs_FindNiceObjectBucket(dev);++	/* Now find an object value that has not already been taken+	 * by scanning the list.+	 */++	int found = 0;+	struct ylist_head *i;++	__u32 n = (__u32) bucket;++	/* yaffs_CheckObjectHashSanity();  */++	while (!found) {+		found = 1;+		n += YAFFS_NOBJECT_BUCKETS;+		if (1 || dev->objectBucket[bucket].count > 0) {+			ylist_for_each(i, &dev->objectBucket[bucket].list) {+				/* If there is already one in the list */+				if (i && ylist_entry(i, yaffs_Object,+						hashLink)->objectId == n) {+					found = 0;+				}+			}+		}+	}++	return n;+}++static void yaffs_HashObject(yaffs_Object *in)+{+	int bucket = yaffs_HashFunction(in->objectId);+	yaffs_Device *dev = in->myDev;++	ylist_add(&in->hashLink, &dev->objectBucket[bucket].list);+	dev->objectBucket[bucket].count++;+}++yaffs_Object *yaffs_FindObjectByNumber(yaffs_Device *dev, __u32 number)+{+	int bucket = yaffs_HashFunction(number);+	struct ylist_head *i;+	yaffs_Object *in;++	ylist_for_each(i, &dev->objectBucket[bucket].list) {+		/* Look if it is in the list */+		if (i) {+			in = ylist_entry(i, yaffs_Object, hashLink);+			if (in->objectId == number) {+#ifdef __KERNEL__+				/* Don't tell the VFS about this one if it is defered free */+				if (in->deferedFree)+					return NULL;+#endif++				return in;+			}+		}+	}++	return NULL;+}++yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev, int number,+				    yaffs_ObjectType type)+{+	yaffs_Object *theObject;+	yaffs_Tnode *tn = NULL;++	if (number < 0)+		number = yaffs_CreateNewObjectNumber(dev);++	theObject = yaffs_AllocateEmptyObject(dev);+	if (!theObject)+		return NULL;++	if (type == YAFFS_OBJECT_TYPE_FILE) {+		tn = yaffs_GetTnode(dev);+		if (!tn) {+			yaffs_FreeObject(theObject);+			return NULL;+		}+	}++	if (theObject) {+		theObject->fake = 0;+		theObject->renameAllowed = 1;+		theObject->unlinkAllowed = 1;+		theObject->objectId = number;+		yaffs_HashObject(theObject);+		theObject->variantType = type;+#ifdef CONFIG_YAFFS_WINCE+		yfsd_WinFileTimeNow(theObject->win_atime);+		theObject->win_ctime[0] = theObject->win_mtime[0] =+		    theObject->win_atime[0];+		theObject->win_ctime[1] = theObject->win_mtime[1] =+		    theObject->win_atime[1];++#else++		theObject->yst_atime = theObject->yst_mtime =+		    theObject->yst_ctime = Y_CURRENT_TIME;+#endif+		switch (type) {+		case YAFFS_OBJECT_TYPE_FILE:+			theObject->variant.fileVariant.fileSize = 0;+			theObject->variant.fileVariant.scannedFileSize = 0;+			theObject->variant.fileVariant.shrinkSize = 0xFFFFFFFF;	/* max __u32 */+			theObject->variant.fileVariant.topLevel = 0;+			theObject->variant.fileVariant.top = tn;+			break;+		case YAFFS_OBJECT_TYPE_DIRECTORY:+			YINIT_LIST_HEAD(&theObject->variant.directoryVariant.+					children);+			break;+		case YAFFS_OBJECT_TYPE_SYMLINK:+		case YAFFS_OBJECT_TYPE_HARDLINK:+		case YAFFS_OBJECT_TYPE_SPECIAL:+			/* No action required */+			break;+		case YAFFS_OBJECT_TYPE_UNKNOWN:+			/* todo this should not happen */+			break;+		}+	}++	return theObject;+}++static yaffs_Object *yaffs_FindOrCreateObjectByNumber(yaffs_Device *dev,+						      int number,+						      yaffs_ObjectType type)+{+	yaffs_Object *theObject = NULL;++	if (number > 0)+		theObject = yaffs_FindObjectByNumber(dev, number);++	if (!theObject)+		theObject = yaffs_CreateNewObject(dev, number, type);++	return theObject;++}+++static YCHAR *yaffs_CloneString(const YCHAR *str)+{+	YCHAR *newStr = NULL;++	if (str && *str) {+		newStr = YMALLOC((yaffs_strlen(str) + 1) * sizeof(YCHAR));+		if (newStr)+			yaffs_strcpy(newStr, str);+	}++	return newStr;++}++/*+ * Mknod (create) a new object.+ * equivalentObject only has meaning for a hard link;+ * aliasString only has meaning for a sumlink.+ * rdev only has meaning for devices (a subset of special objects)+ */++static yaffs_Object *yaffs_MknodObject(yaffs_ObjectType type,+				       yaffs_Object *parent,+				       const YCHAR *name,+				       __u32 mode,+				       __u32 uid,+				       __u32 gid,+				       yaffs_Object *equivalentObject,+				       const YCHAR *aliasString, __u32 rdev)+{+	yaffs_Object *in;+	YCHAR *str = NULL;++	yaffs_Device *dev = parent->myDev;++	/* Check if the entry exists. If it does then fail the call since we don't want a dup.*/+	if (yaffs_FindObjectByName(parent, name))+		return NULL;++	in = yaffs_CreateNewObject(dev, -1, type);++	if (!in)+		return YAFFS_FAIL;++	if (type == YAFFS_OBJECT_TYPE_SYMLINK) {+		str = yaffs_CloneString(aliasString);+		if (!str) {+			yaffs_FreeObject(in);+			return NULL;+		}+	}++++	if (in) {+		in->hdrChunk = 0;+		in->valid = 1;+		in->variantType = type;++		in->yst_mode = mode;++#ifdef CONFIG_YAFFS_WINCE+		yfsd_WinFileTimeNow(in->win_atime);+		in->win_ctime[0] = in->win_mtime[0] = in->win_atime[0];+		in->win_ctime[1] = in->win_mtime[1] = in->win_atime[1];++#else+		in->yst_atime = in->yst_mtime = in->yst_ctime = Y_CURRENT_TIME;++		in->yst_rdev = rdev;+		in->yst_uid = uid;+		in->yst_gid = gid;+#endif+		in->nDataChunks = 0;++		yaffs_SetObjectName(in, name);+		in->dirty = 1;++		yaffs_AddObjectToDirectory(parent, in);++		in->myDev = parent->myDev;++		switch (type) {+		case YAFFS_OBJECT_TYPE_SYMLINK:+			in->variant.symLinkVariant.alias = str;+			break;+		case YAFFS_OBJECT_TYPE_HARDLINK:+			in->variant.hardLinkVariant.equivalentObject =+				equivalentObject;+			in->variant.hardLinkVariant.equivalentObjectId =+				equivalentObject->objectId;+			ylist_add(&in->hardLinks, &equivalentObject->hardLinks);+			break;+		case YAFFS_OBJECT_TYPE_FILE:+		case YAFFS_OBJECT_TYPE_DIRECTORY:+		case YAFFS_OBJECT_TYPE_SPECIAL:+		case YAFFS_OBJECT_TYPE_UNKNOWN:+			/* do nothing */+			break;+		}++		if (yaffs_UpdateObjectHeader(in, name, 0, 0, 0) < 0) {+			/* Could not create the object header, fail the creation */+			yaffs_DeleteObject(in);+			in = NULL;+		}++	}++	return in;+}++yaffs_Object *yaffs_MknodFile(yaffs_Object *parent, const YCHAR *name,+			__u32 mode, __u32 uid, __u32 gid)+{+	return yaffs_MknodObject(YAFFS_OBJECT_TYPE_FILE, parent, name, mode,+				uid, gid, NULL, NULL, 0);+}++yaffs_Object *yaffs_MknodDirectory(yaffs_Object *parent, const YCHAR *name,+				__u32 mode, __u32 uid, __u32 gid)+{+	return yaffs_MknodObject(YAFFS_OBJECT_TYPE_DIRECTORY, parent, name,+				 mode, uid, gid, NULL, NULL, 0);+}++yaffs_Object *yaffs_MknodSpecial(yaffs_Object *parent, const YCHAR *name,+				__u32 mode, __u32 uid, __u32 gid, __u32 rdev)+{+	return yaffs_MknodObject(YAFFS_OBJECT_TYPE_SPECIAL, parent, name, mode,+				 uid, gid, NULL, NULL, rdev);+}++yaffs_Object *yaffs_MknodSymLink(yaffs_Object *parent, const YCHAR *name,+				__u32 mode, __u32 uid, __u32 gid,+				const YCHAR *alias)+{+	return yaffs_MknodObject(YAFFS_OBJECT_TYPE_SYMLINK, parent, name, mode,+				uid, gid, NULL, alias, 0);+}++/* yaffs_Link returns the object id of the equivalent object.*/+yaffs_Object *yaffs_Link(yaffs_Object *parent, const YCHAR *name,+			yaffs_Object *equivalentObject)+{+	/* Get the real object in case we were fed a hard link as an equivalent object */+	equivalentObject = yaffs_GetEquivalentObject(equivalentObject);++	if (yaffs_MknodObject+	    (YAFFS_OBJECT_TYPE_HARDLINK, parent, name, 0, 0, 0,+	     equivalentObject, NULL, 0)) {+		return equivalentObject;+	} else {+		return NULL;+	}++}++static int yaffs_ChangeObjectName(yaffs_Object *obj, yaffs_Object *newDir,+				const YCHAR *newName, int force, int shadows)+{+	int unlinkOp;+	int deleteOp;++	yaffs_Object *existingTarget;++	if (newDir == NULL)+		newDir = obj->parent;	/* use the old directory */++	if (newDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {+		T(YAFFS_TRACE_ALWAYS,+		  (TSTR+		   ("tragedy: yaffs_ChangeObjectName: newDir is not a directory"+		    TENDSTR)));+		YBUG();+	}++	/* TODO: Do we need this different handling for YAFFS2 and YAFFS1?? */+	if (obj->myDev->isYaffs2)+		unlinkOp = (newDir == obj->myDev->unlinkedDir);+	else+		unlinkOp = (newDir == obj->myDev->unlinkedDir+			    && obj->variantType == YAFFS_OBJECT_TYPE_FILE);++	deleteOp = (newDir == obj->myDev->deletedDir);++	existingTarget = yaffs_FindObjectByName(newDir, newName);++	/* If the object is a file going into the unlinked directory,+	 *   then it is OK to just stuff it in since duplicate names are allowed.+	 *   else only proceed if the new name does not exist and if we're putting+	 *   it into a directory.+	 */+	if ((unlinkOp ||+	     deleteOp ||+	     force ||+	     (shadows > 0) ||+	     !existingTarget) &&+	    newDir->variantType == YAFFS_OBJECT_TYPE_DIRECTORY) {+		yaffs_SetObjectName(obj, newName);+		obj->dirty = 1;++		yaffs_AddObjectToDirectory(newDir, obj);++		if (unlinkOp)+			obj->unlinked = 1;++		/* If it is a deletion then we mark it as a shrink for gc purposes. */+		if (yaffs_UpdateObjectHeader(obj, newName, 0, deleteOp, shadows) >= 0)+			return YAFFS_OK;+	}++	return YAFFS_FAIL;+}++int yaffs_RenameObject(yaffs_Object *oldDir, const YCHAR *oldName,+		yaffs_Object *newDir, const YCHAR *newName)+{+	yaffs_Object *obj = NULL;+	yaffs_Object *existingTarget = NULL;+	int force = 0;+++	if (!oldDir || oldDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)+		YBUG();+	if (!newDir || newDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)+		YBUG();++#ifdef CONFIG_YAFFS_CASE_INSENSITIVE+	/* Special case for case insemsitive systems (eg. WinCE).+	 * While look-up is case insensitive, the name isn't.+	 * Therefore we might want to change x.txt to X.txt+	*/+	if (oldDir == newDir && yaffs_strcmp(oldName, newName) == 0)+		force = 1;+#endif++	else if (yaffs_strlen(newName) > YAFFS_MAX_NAME_LENGTH)+		/* ENAMETOOLONG */+		return YAFFS_FAIL;++	obj = yaffs_FindObjectByName(oldDir, oldName);++	if (obj && obj->renameAllowed) {++		/* Now do the handling for an existing target, if there is one */++		existingTarget = yaffs_FindObjectByName(newDir, newName);+		if (existingTarget &&+			existingTarget->variantType == YAFFS_OBJECT_TYPE_DIRECTORY &&+			!ylist_empty(&existingTarget->variant.directoryVariant.children)) {+			/* There is a target that is a non-empty directory, so we fail */+			return YAFFS_FAIL;	/* EEXIST or ENOTEMPTY */+		} else if (existingTarget && existingTarget != obj) {+			/* Nuke the target first, using shadowing,+			 * but only if it isn't the same object+			 */+			yaffs_ChangeObjectName(obj, newDir, newName, force,+						existingTarget->objectId);+			yaffs_UnlinkObject(existingTarget);+		}++		return yaffs_ChangeObjectName(obj, newDir, newName, 1, 0);+	}+	return YAFFS_FAIL;+}++/*------------------------- Block Management and Page Allocation ----------------*/++static int yaffs_InitialiseBlocks(yaffs_Device *dev)+{+	int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1;++	dev->blockInfo = NULL;+	dev->chunkBits = NULL;++	dev->allocationBlock = -1;	/* force it to get a new one */++	/* If the first allocation strategy fails, thry the alternate one */+	dev->blockInfo = YMALLOC(nBlocks * sizeof(yaffs_BlockInfo));+	if (!dev->blockInfo) {+		dev->blockInfo = YMALLOC_ALT(nBlocks * sizeof(yaffs_BlockInfo));+		dev->blockInfoAlt = 1;+	} else+		dev->blockInfoAlt = 0;++	if (dev->blockInfo) {+		/* Set up dynamic blockinfo stuff. */+		dev->chunkBitmapStride = (dev->nChunksPerBlock + 7) / 8; /* round up bytes */+		dev->chunkBits = YMALLOC(dev->chunkBitmapStride * nBlocks);+		if (!dev->chunkBits) {+			dev->chunkBits = YMALLOC_ALT(dev->chunkBitmapStride * nBlocks);+			dev->chunkBitsAlt = 1;+		} else+			dev->chunkBitsAlt = 0;+	}++	if (dev->blockInfo && dev->chunkBits) {+		memset(dev->blockInfo, 0, nBlocks * sizeof(yaffs_BlockInfo));+		memset(dev->chunkBits, 0, dev->chunkBitmapStride * nBlocks);+		return YAFFS_OK;+	}++	return YAFFS_FAIL;+}++static void yaffs_DeinitialiseBlocks(yaffs_Device *dev)+{+	if (dev->blockInfoAlt && dev->blockInfo)+		YFREE_ALT(dev->blockInfo);+	else if (dev->blockInfo)+		YFREE(dev->blockInfo);++	dev->blockInfoAlt = 0;++	dev->blockInfo = NULL;++	if (dev->chunkBitsAlt && dev->chunkBits)+		YFREE_ALT(dev->chunkBits);+	else if (dev->chunkBits)+		YFREE(dev->chunkBits);+	dev->chunkBitsAlt = 0;+	dev->chunkBits = NULL;+}++static int yaffs_BlockNotDisqualifiedFromGC(yaffs_Device *dev,+					yaffs_BlockInfo *bi)+{+	int i;+	__u32 seq;+	yaffs_BlockInfo *b;++	if (!dev->isYaffs2)+		return 1;	/* disqualification only applies to yaffs2. */++	if (!bi->hasShrinkHeader)+		return 1;	/* can gc */++	/* Find the oldest dirty sequence number if we don't know it and save it+	 * so we don't have to keep recomputing it.+	 */+	if (!dev->oldestDirtySequence) {+		seq = dev->sequenceNumber;++		for (i = dev->internalStartBlock; i <= dev->internalEndBlock;+				i++) {+			b = yaffs_GetBlockInfo(dev, i);+			if (b->blockState == YAFFS_BLOCK_STATE_FULL &&+			    (b->pagesInUse - b->softDeletions) <+			    dev->nChunksPerBlock && b->sequenceNumber < seq) {+				seq = b->sequenceNumber;+			}+		}+		dev->oldestDirtySequence = seq;+	}++	/* Can't do gc of this block if there are any blocks older than this one that have+	 * discarded pages.+	 */+	return (bi->sequenceNumber <= dev->oldestDirtySequence);+}++/* FindDiretiestBlock is used to select the dirtiest block (or close enough)+ * for garbage collection.+ */++static int yaffs_FindBlockForGarbageCollection(yaffs_Device *dev,+					int aggressive)+{+	int b = dev->currentDirtyChecker;++	int i;+	int iterations;+	int dirtiest = -1;+	int pagesInUse = 0;+	int prioritised = 0;+	yaffs_BlockInfo *bi;+	int pendingPrioritisedExist = 0;++	/* First let's see if we need to grab a prioritised block */+	if (dev->hasPendingPrioritisedGCs) {+		for (i = dev->internalStartBlock; i < dev->internalEndBlock && !prioritised; i++) {++			bi = yaffs_GetBlockInfo(dev, i);+			/* yaffs_VerifyBlock(dev,bi,i); */++			if (bi->gcPrioritise) {+				pendingPrioritisedExist = 1;+				if (bi->blockState == YAFFS_BLOCK_STATE_FULL &&+				   yaffs_BlockNotDisqualifiedFromGC(dev, bi)) {+					pagesInUse = (bi->pagesInUse - bi->softDeletions);+					dirtiest = i;+					prioritised = 1;+					aggressive = 1; /* Fool the non-aggressive skip logiv below */+				}+			}+		}++		if (!pendingPrioritisedExist) /* None found, so we can clear this */+			dev->hasPendingPrioritisedGCs = 0;+	}++	/* If we're doing aggressive GC then we are happy to take a less-dirty block, and+	 * search harder.+	 * else (we're doing a leasurely gc), then we only bother to do this if the+	 * block has only a few pages in use.+	 */++	dev->nonAggressiveSkip--;++	if (!aggressive && (dev->nonAggressiveSkip > 0))+		return -1;++	if (!prioritised)+		pagesInUse =+			(aggressive) ? dev->nChunksPerBlock : YAFFS_PASSIVE_GC_CHUNKS + 1;++	if (aggressive)+		iterations =+		    dev->internalEndBlock - dev->internalStartBlock + 1;+	else {+		iterations =+		    dev->internalEndBlock - dev->internalStartBlock + 1;+		iterations = iterations / 16;+		if (iterations > 200)+			iterations = 200;+	}++	for (i = 0; i <= iterations && pagesInUse > 0 && !prioritised; i++) {+		b++;+		if (b < dev->internalStartBlock || b > dev->internalEndBlock)+			b = dev->internalStartBlock;++		if (b < dev->internalStartBlock || b > dev->internalEndBlock) {+			T(YAFFS_TRACE_ERROR,+			  (TSTR("**>> Block %d is not valid" TENDSTR), b));+			YBUG();+		}++		bi = yaffs_GetBlockInfo(dev, b);++		if (bi->blockState == YAFFS_BLOCK_STATE_FULL &&+			(bi->pagesInUse - bi->softDeletions) < pagesInUse &&+				yaffs_BlockNotDisqualifiedFromGC(dev, bi)) {+			dirtiest = b;+			pagesInUse = (bi->pagesInUse - bi->softDeletions);+		}+	}++	dev->currentDirtyChecker = b;++	if (dirtiest > 0) {+		T(YAFFS_TRACE_GC,+		  (TSTR("GC Selected block %d with %d free, prioritised:%d" TENDSTR), dirtiest,+		   dev->nChunksPerBlock - pagesInUse, prioritised));+	}++	dev->oldestDirtySequence = 0;++	if (dirtiest > 0)+		dev->nonAggressiveSkip = 4;++	return dirtiest;+}++static void yaffs_BlockBecameDirty(yaffs_Device *dev, int blockNo)+{+	yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockNo);++	int erasedOk = 0;++	/* If the block is still healthy erase it and mark as clean.+	 * If the block has had a data failure, then retire it.+	 */++	T(YAFFS_TRACE_GC | YAFFS_TRACE_ERASE,+		(TSTR("yaffs_BlockBecameDirty block %d state %d %s"TENDSTR),+		blockNo, bi->blockState, (bi->needsRetiring) ? "needs retiring" : ""));++	bi->blockState = YAFFS_BLOCK_STATE_DIRTY;++	if (!bi->needsRetiring) {+		yaffs_InvalidateCheckpoint(dev);+		erasedOk = yaffs_EraseBlockInNAND(dev, blockNo);+		if (!erasedOk) {+			dev->nErasureFailures++;+			T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,+			  (TSTR("**>> Erasure failed %d" TENDSTR), blockNo));+		}+	}++	if (erasedOk &&+	    ((yaffs_traceMask & YAFFS_TRACE_ERASE) || !yaffs_SkipVerification(dev))) {+		int i;+		for (i = 0; i < dev->nChunksPerBlock; i++) {+			if (!yaffs_CheckChunkErased+			    (dev, blockNo * dev->nChunksPerBlock + i)) {+				T(YAFFS_TRACE_ERROR,+				  (TSTR+				   (">>Block %d erasure supposedly OK, but chunk %d not erased"+				    TENDSTR), blockNo, i));+			}+		}+	}++	if (erasedOk) {+		/* Clean it up... */+		bi->blockState = YAFFS_BLOCK_STATE_EMPTY;+		dev->nErasedBlocks++;+		bi->pagesInUse = 0;+		bi->softDeletions = 0;+		bi->hasShrinkHeader = 0;+		bi->skipErasedCheck = 1;  /* This is clean, so no need to check */+		bi->gcPrioritise = 0;+		yaffs_ClearChunkBits(dev, blockNo);++		T(YAFFS_TRACE_ERASE,+		  (TSTR("Erased block %d" TENDSTR), blockNo));+	} else {+		dev->nFreeChunks -= dev->nChunksPerBlock;	/* We lost a block of free space */++		yaffs_RetireBlock(dev, blockNo);+		T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,+		  (TSTR("**>> Block %d retired" TENDSTR), blockNo));+	}+}++static int yaffs_FindBlockForAllocation(yaffs_Device *dev)+{+	int i;++	yaffs_BlockInfo *bi;++	if (dev->nErasedBlocks < 1) {+		/* Hoosterman we've got a problem.+		 * Can't get space to gc+		 */+		T(YAFFS_TRACE_ERROR,+		  (TSTR("yaffs tragedy: no more erased blocks" TENDSTR)));++		return -1;+	}++	/* Find an empty block. */++	for (i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) {+		dev->allocationBlockFinder++;+		if (dev->allocationBlockFinder < dev->internalStartBlock+		    || dev->allocationBlockFinder > dev->internalEndBlock) {+			dev->allocationBlockFinder = dev->internalStartBlock;+		}++		bi = yaffs_GetBlockInfo(dev, dev->allocationBlockFinder);++		if (bi->blockState == YAFFS_BLOCK_STATE_EMPTY) {+			bi->blockState = YAFFS_BLOCK_STATE_ALLOCATING;+			dev->sequenceNumber++;+			bi->sequenceNumber = dev->sequenceNumber;+			dev->nErasedBlocks--;+			T(YAFFS_TRACE_ALLOCATE,+			  (TSTR("Allocated block %d, seq  %d, %d left" TENDSTR),+			   dev->allocationBlockFinder, dev->sequenceNumber,+			   dev->nErasedBlocks));+			return dev->allocationBlockFinder;+		}+	}++	T(YAFFS_TRACE_ALWAYS,+	  (TSTR+	   ("yaffs tragedy: no more erased blocks, but there should have been %d"+	    TENDSTR), dev->nErasedBlocks));++	return -1;+}++++static int yaffs_CalcCheckpointBlocksRequired(yaffs_Device *dev)+{+	if (!dev->nCheckpointBlocksRequired &&+	   dev->isYaffs2) {+		/* Not a valid value so recalculate */+		int nBytes = 0;+		int nBlocks;+		int devBlocks = (dev->endBlock - dev->startBlock + 1);+		int tnodeSize;++		tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;++		if (tnodeSize < sizeof(yaffs_Tnode))+			tnodeSize = sizeof(yaffs_Tnode);++		nBytes += sizeof(yaffs_CheckpointValidity);+		nBytes += sizeof(yaffs_CheckpointDevice);+		nBytes += devBlocks * sizeof(yaffs_BlockInfo);+		nBytes += devBlocks * dev->chunkBitmapStride;+		nBytes += (sizeof(yaffs_CheckpointObject) + sizeof(__u32)) * (dev->nObjectsCreated - dev->nFreeObjects);+		nBytes += (tnodeSize + sizeof(__u32)) * (dev->nTnodesCreated - dev->nFreeTnodes);+		nBytes += sizeof(yaffs_CheckpointValidity);+		nBytes += sizeof(__u32); /* checksum*/++		/* Round up and add 2 blocks to allow for some bad blocks, so add 3 */++		nBlocks = (nBytes/(dev->nDataBytesPerChunk * dev->nChunksPerBlock)) + 3;++		dev->nCheckpointBlocksRequired = nBlocks;+	}++	return dev->nCheckpointBlocksRequired;+}++/*+ * Check if there's space to allocate...+ * Thinks.... do we need top make this ths same as yaffs_GetFreeChunks()?+ */+static int yaffs_CheckSpaceForAllocation(yaffs_Device *dev)+{+	int reservedChunks;+	int reservedBlocks = dev->nReservedBlocks;+	int checkpointBlocks;++	if (dev->isYaffs2) {+		checkpointBlocks =  yaffs_CalcCheckpointBlocksRequired(dev) -+				    dev->blocksInCheckpoint;+		if (checkpointBlocks < 0)+			checkpointBlocks = 0;+	} else {+		checkpointBlocks = 0;+	}++	reservedChunks = ((reservedBlocks + checkpointBlocks) * dev->nChunksPerBlock);++	return (dev->nFreeChunks > reservedChunks);+}++static int yaffs_AllocateChunk(yaffs_Device *dev, int useReserve,+		yaffs_BlockInfo **blockUsedPtr)+{+	int retVal;+	yaffs_BlockInfo *bi;++	if (dev->allocationBlock < 0) {+		/* Get next block to allocate off */+		dev->allocationBlock = yaffs_FindBlockForAllocation(dev);+		dev->allocationPage = 0;+	}++	if (!useReserve && !yaffs_CheckSpaceForAllocation(dev)) {+		/* Not enough space to allocate unless we're allowed to use the reserve. */+		return -1;+	}++	if (dev->nErasedBlocks < dev->nReservedBlocks+			&& dev->allocationPage == 0) {+		T(YAFFS_TRACE_ALLOCATE, (TSTR("Allocating reserve" TENDSTR)));+	}++	/* Next page please.... */+	if (dev->allocationBlock >= 0) {+		bi = yaffs_GetBlockInfo(dev, dev->allocationBlock);++		retVal = (dev->allocationBlock * dev->nChunksPerBlock) ++			dev->allocationPage;+		bi->pagesInUse++;+		yaffs_SetChunkBit(dev, dev->allocationBlock,+				dev->allocationPage);++		dev->allocationPage++;++		dev->nFreeChunks--;++		/* If the block is full set the state to full */+		if (dev->allocationPage >= dev->nChunksPerBlock) {+			bi->blockState = YAFFS_BLOCK_STATE_FULL;+			dev->allocationBlock = -1;+		}++		if (blockUsedPtr)+			*blockUsedPtr = bi;++		return retVal;+	}++	T(YAFFS_TRACE_ERROR,+			(TSTR("!!!!!!!!! Allocator out !!!!!!!!!!!!!!!!!" TENDSTR)));++	return -1;+}++static int yaffs_GetErasedChunks(yaffs_Device *dev)+{+	int n;++	n = dev->nErasedBlocks * dev->nChunksPerBlock;++	if (dev->allocationBlock > 0)+		n += (dev->nChunksPerBlock - dev->allocationPage);++	return n;++}++static int yaffs_GarbageCollectBlock(yaffs_Device *dev, int block,+		int wholeBlock)+{+	int oldChunk;+	int newChunk;+	int markNAND;+	int retVal = YAFFS_OK;+	int cleanups = 0;+	int i;+	int isCheckpointBlock;+	int matchingChunk;+	int maxCopies;++	int chunksBefore = yaffs_GetErasedChunks(dev);+	int chunksAfter;++	yaffs_ExtendedTags tags;++	yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, block);++	yaffs_Object *object;++	isCheckpointBlock = (bi->blockState == YAFFS_BLOCK_STATE_CHECKPOINT);++	bi->blockState = YAFFS_BLOCK_STATE_COLLECTING;++	T(YAFFS_TRACE_TRACING,+			(TSTR("Collecting block %d, in use %d, shrink %d, wholeBlock %d" TENDSTR),+			 block,+			 bi->pagesInUse,+			 bi->hasShrinkHeader,+			 wholeBlock));++	/*yaffs_VerifyFreeChunks(dev); */++	bi->hasShrinkHeader = 0;	/* clear the flag so that the block can erase */++	/* Take off the number of soft deleted entries because+	 * they're going to get really deleted during GC.+	 */+	dev->nFreeChunks -= bi->softDeletions;++	dev->isDoingGC = 1;++	if (isCheckpointBlock ||+			!yaffs_StillSomeChunkBits(dev, block)) {+		T(YAFFS_TRACE_TRACING,+				(TSTR+				 ("Collecting block %d that has no chunks in use" TENDSTR),+				 block));+		yaffs_BlockBecameDirty(dev, block);+	} else {++		__u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__);++		yaffs_VerifyBlock(dev, bi, block);++		maxCopies = (wholeBlock) ? dev->nChunksPerBlock : 10;+		oldChunk = block * dev->nChunksPerBlock + dev->gcChunk;++		for (/* init already done */;+		     retVal == YAFFS_OK &&+		     dev->gcChunk < dev->nChunksPerBlock &&+		     (bi->blockState == YAFFS_BLOCK_STATE_COLLECTING) &&+		     maxCopies > 0;+		     dev->gcChunk++, oldChunk++) {+			if (yaffs_CheckChunkBit(dev, block, dev->gcChunk)) {++				/* This page is in use and might need to be copied off */++				maxCopies--;++				markNAND = 1;++				yaffs_InitialiseTags(&tags);++				yaffs_ReadChunkWithTagsFromNAND(dev, oldChunk,+								buffer, &tags);++				object =+				    yaffs_FindObjectByNumber(dev,+							     tags.objectId);++				T(YAFFS_TRACE_GC_DETAIL,+				  (TSTR+				   ("Collecting chunk in block %d, %d %d %d " TENDSTR),+				   dev->gcChunk, tags.objectId, tags.chunkId,+				   tags.byteCount));++				if (object && !yaffs_SkipVerification(dev)) {+					if (tags.chunkId == 0)+						matchingChunk = object->hdrChunk;+					else if (object->softDeleted)+						matchingChunk = oldChunk; /* Defeat the test */+					else+						matchingChunk = yaffs_FindChunkInFile(object, tags.chunkId, NULL);++					if (oldChunk != matchingChunk)+						T(YAFFS_TRACE_ERROR,+						  (TSTR("gc: page in gc mismatch: %d %d %d %d"TENDSTR),+						  oldChunk, matchingChunk, tags.objectId, tags.chunkId));++				}++				if (!object) {+					T(YAFFS_TRACE_ERROR,+					  (TSTR+					   ("page %d in gc has no object: %d %d %d "+					    TENDSTR), oldChunk,+					    tags.objectId, tags.chunkId, tags.byteCount));+				}++				if (object &&+				    object->deleted &&+				    object->softDeleted &&+				    tags.chunkId != 0) {+					/* Data chunk in a soft deleted file, throw it away+					 * It's a soft deleted data chunk,+					 * No need to copy this, just forget about it and+					 * fix up the object.+					 */++					object->nDataChunks--;++					if (object->nDataChunks <= 0) {+						/* remeber to clean up the object */+						dev->gcCleanupList[cleanups] =+						    tags.objectId;+						cleanups++;+					}+					markNAND = 0;+				} else if (0) {+					/* Todo object && object->deleted && object->nDataChunks == 0 */+					/* Deleted object header with no data chunks.+					 * Can be discarded and the file deleted.+					 */+					object->hdrChunk = 0;+					yaffs_FreeTnode(object->myDev,+							object->variant.+							fileVariant.top);+					object->variant.fileVariant.top = NULL;+					yaffs_DoGenericObjectDeletion(object);++				} else if (object) {+					/* It's either a data chunk in a live file or+					 * an ObjectHeader, so we're interested in it.+					 * NB Need to keep the ObjectHeaders of deleted files+					 * until the whole file has been deleted off+					 */+					tags.serialNumber++;++					dev->nGCCopies++;++					if (tags.chunkId == 0) {+						/* It is an object Id,+						 * We need to nuke the shrinkheader flags first+						 * We no longer want the shrinkHeader flag since its work is done+						 * and if it is left in place it will mess up scanning.+						 */++						yaffs_ObjectHeader *oh;+						oh = (yaffs_ObjectHeader *)buffer;+						oh->isShrink = 0;+						tags.extraIsShrinkHeader = 0;++						yaffs_VerifyObjectHeader(object, oh, &tags, 1);+					}++					newChunk =+					    yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &tags, 1);++					if (newChunk < 0) {+						retVal = YAFFS_FAIL;+					} else {++						/* Ok, now fix up the Tnodes etc. */++						if (tags.chunkId == 0) {+							/* It's a header */+							object->hdrChunk =  newChunk;+							object->serial =   tags.serialNumber;+						} else {+							/* It's a data chunk */+							yaffs_PutChunkIntoFile+							    (object,+							     tags.chunkId,+							     newChunk, 0);+						}+					}+				}++				if (retVal == YAFFS_OK)+					yaffs_DeleteChunk(dev, oldChunk, markNAND, __LINE__);++			}+		}++		yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);+++		/* Do any required cleanups */+		for (i = 0; i < cleanups; i++) {+			/* Time to delete the file too */+			object =+			    yaffs_FindObjectByNumber(dev,+						     dev->gcCleanupList[i]);+			if (object) {+				yaffs_FreeTnode(dev,+						object->variant.fileVariant.+						top);+				object->variant.fileVariant.top = NULL;+				T(YAFFS_TRACE_GC,+				  (TSTR+				   ("yaffs: About to finally delete object %d"+				    TENDSTR), object->objectId));+				yaffs_DoGenericObjectDeletion(object);+				object->myDev->nDeletedFiles--;+			}++		}++	}++	yaffs_VerifyCollectedBlock(dev, bi, block);++	chunksAfter = yaffs_GetErasedChunks(dev);+	if (chunksBefore >= chunksAfter) {+		T(YAFFS_TRACE_GC,+		  (TSTR+		   ("gc did not increase free chunks before %d after %d"+		    TENDSTR), chunksBefore, chunksAfter));+	}++	/* If the gc completed then clear the current gcBlock so that we find another. */+	if (bi->blockState != YAFFS_BLOCK_STATE_COLLECTING) {+		dev->gcBlock = -1;+		dev->gcChunk = 0;+	}++	dev->isDoingGC = 0;++	return retVal;+}++/* New garbage collector+ * If we're very low on erased blocks then we do aggressive garbage collection+ * otherwise we do "leasurely" garbage collection.+ * Aggressive gc looks further (whole array) and will accept less dirty blocks.+ * Passive gc only inspects smaller areas and will only accept more dirty blocks.+ *+ * The idea is to help clear out space in a more spread-out manner.+ * Dunno if it really does anything useful.+ */+static int yaffs_CheckGarbageCollection(yaffs_Device *dev)+{+	int block;+	int aggressive;+	int gcOk = YAFFS_OK;+	int maxTries = 0;++	int checkpointBlockAdjust;++	if (dev->isDoingGC) {+		/* Bail out so we don't get recursive gc */+		return YAFFS_OK;+	}++	/* This loop should pass the first time.+	 * We'll only see looping here if the erase of the collected block fails.+	 */++	do {+		maxTries++;++		checkpointBlockAdjust = yaffs_CalcCheckpointBlocksRequired(dev) - dev->blocksInCheckpoint;+		if (checkpointBlockAdjust < 0)+			checkpointBlockAdjust = 0;++		if (dev->nErasedBlocks < (dev->nReservedBlocks + checkpointBlockAdjust + 2)) {+			/* We need a block soon...*/+			aggressive = 1;+		} else {+			/* We're in no hurry */+			aggressive = 0;+		}++		if (dev->gcBlock <= 0) {+			dev->gcBlock = yaffs_FindBlockForGarbageCollection(dev, aggressive);+			dev->gcChunk = 0;+		}++		block = dev->gcBlock;++		if (block > 0) {+			dev->garbageCollections++;+			if (!aggressive)+				dev->passiveGarbageCollections++;++			T(YAFFS_TRACE_GC,+			  (TSTR+			   ("yaffs: GC erasedBlocks %d aggressive %d" TENDSTR),+			   dev->nErasedBlocks, aggressive));++			gcOk = yaffs_GarbageCollectBlock(dev, block, aggressive);+		}++		if (dev->nErasedBlocks < (dev->nReservedBlocks) && block > 0) {+			T(YAFFS_TRACE_GC,+			  (TSTR+			   ("yaffs: GC !!!no reclaim!!! erasedBlocks %d after try %d block %d"+			    TENDSTR), dev->nErasedBlocks, maxTries, block));+		}+	} while ((dev->nErasedBlocks < dev->nReservedBlocks) &&+		 (block > 0) &&+		 (maxTries < 2));++	return aggressive ? gcOk : YAFFS_OK;+}++/*-------------------------  TAGS --------------------------------*/++static int yaffs_TagsMatch(const yaffs_ExtendedTags *tags, int objectId,+			   int chunkInObject)+{+	return (tags->chunkId == chunkInObject &&+		tags->objectId == objectId && !tags->chunkDeleted) ? 1 : 0;++}+++/*-------------------- Data file manipulation -----------------*/++static int yaffs_FindChunkInFile(yaffs_Object *in, int chunkInInode,+				 yaffs_ExtendedTags *tags)+{+	/*Get the Tnode, then get the level 0 offset chunk offset */+	yaffs_Tnode *tn;+	int theChunk = -1;+	yaffs_ExtendedTags localTags;+	int retVal = -1;++	yaffs_Device *dev = in->myDev;++	if (!tags) {+		/* Passed a NULL, so use our own tags space */+		tags = &localTags;+	}++	tn = yaffs_FindLevel0Tnode(dev, &in->variant.fileVariant, chunkInInode);++	if (tn) {+		theChunk = yaffs_GetChunkGroupBase(dev, tn, chunkInInode);++		retVal =+		    yaffs_FindChunkInGroup(dev, theChunk, tags, in->objectId,+					   chunkInInode);+	}+	return retVal;+}++static int yaffs_FindAndDeleteChunkInFile(yaffs_Object *in, int chunkInInode,+					  yaffs_ExtendedTags *tags)+{+	/* Get the Tnode, then get the level 0 offset chunk offset */+	yaffs_Tnode *tn;+	int theChunk = -1;+	yaffs_ExtendedTags localTags;++	yaffs_Device *dev = in->myDev;+	int retVal = -1;++	if (!tags) {+		/* Passed a NULL, so use our own tags space */+		tags = &localTags;+	}++	tn = yaffs_FindLevel0Tnode(dev, &in->variant.fileVariant, chunkInInode);++	if (tn) {++		theChunk = yaffs_GetChunkGroupBase(dev, tn, chunkInInode);++		retVal =+		    yaffs_FindChunkInGroup(dev, theChunk, tags, in->objectId,+					   chunkInInode);++		/* Delete the entry in the filestructure (if found) */+		if (retVal != -1)+			yaffs_PutLevel0Tnode(dev, tn, chunkInInode, 0);+	}++	return retVal;+}++#ifdef YAFFS_PARANOID++static int yaffs_CheckFileSanity(yaffs_Object *in)+{+	int chunk;+	int nChunks;+	int fSize;+	int failed = 0;+	int objId;+	yaffs_Tnode *tn;+	yaffs_Tags localTags;+	yaffs_Tags *tags = &localTags;+	int theChunk;+	int chunkDeleted;++	if (in->variantType != YAFFS_OBJECT_TYPE_FILE)+		return YAFFS_FAIL;++	objId = in->objectId;+	fSize = in->variant.fileVariant.fileSize;+	nChunks =+	    (fSize + in->myDev->nDataBytesPerChunk - 1) / in->myDev->nDataBytesPerChunk;++	for (chunk = 1; chunk <= nChunks; chunk++) {+		tn = yaffs_FindLevel0Tnode(in->myDev, &in->variant.fileVariant,+					   chunk);++		if (tn) {++			theChunk = yaffs_GetChunkGroupBase(dev, tn, chunk);++			if (yaffs_CheckChunkBits+			    (dev, theChunk / dev->nChunksPerBlock,+			     theChunk % dev->nChunksPerBlock)) {++				yaffs_ReadChunkTagsFromNAND(in->myDev, theChunk,+							    tags,+							    &chunkDeleted);+				if (yaffs_TagsMatch+				    (tags, in->objectId, chunk, chunkDeleted)) {+					/* found it; */++				}+			} else {++				failed = 1;+			}++		} else {+			/* T(("No level 0 found for %d\n", chunk)); */+		}+	}++	return failed ? YAFFS_FAIL : YAFFS_OK;+}++#endif++static int yaffs_PutChunkIntoFile(yaffs_Object *in, int chunkInInode,+				  int chunkInNAND, int inScan)+{+	/* NB inScan is zero unless scanning.+	 * For forward scanning, inScan is > 0;+	 * for backward scanning inScan is < 0+	 */++	yaffs_Tnode *tn;+	yaffs_Device *dev = in->myDev;+	int existingChunk;+	yaffs_ExtendedTags existingTags;+	yaffs_ExtendedTags newTags;+	unsigned existingSerial, newSerial;++	if (in->variantType != YAFFS_OBJECT_TYPE_FILE) {+		/* Just ignore an attempt at putting a chunk into a non-file during scanning+		 * If it is not during Scanning then something went wrong!+		 */+		if (!inScan) {+			T(YAFFS_TRACE_ERROR,+			  (TSTR+			   ("yaffs tragedy:attempt to put data chunk into a non-file"+			    TENDSTR)));+			YBUG();+		}++		yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__);+		return YAFFS_OK;+	}++	tn = yaffs_AddOrFindLevel0Tnode(dev,+					&in->variant.fileVariant,+					chunkInInode,+					NULL);+	if (!tn)+		return YAFFS_FAIL;++	existingChunk = yaffs_GetChunkGroupBase(dev, tn, chunkInInode);++	if (inScan != 0) {+		/* If we're scanning then we need to test for duplicates+		 * NB This does not need to be efficient since it should only ever+		 * happen when the power fails during a write, then only one+		 * chunk should ever be affected.+		 *+		 * Correction for YAFFS2: This could happen quite a lot and we need to think about efficiency! TODO+		 * Update: For backward scanning we don't need to re-read tags so this is quite cheap.+		 */++		if (existingChunk > 0) {+			/* NB Right now existing chunk will not be real chunkId if the device >= 32MB+			 *    thus we have to do a FindChunkInFile to get the real chunk id.+			 *+			 * We have a duplicate now we need to decide which one to use:+			 *+			 * Backwards scanning YAFFS2: The old one is what we use, dump the new one.+			 * Forward scanning YAFFS2: The new one is what we use, dump the old one.+			 * YAFFS1: Get both sets of tags and compare serial numbers.+			 */++			if (inScan > 0) {+				/* Only do this for forward scanning */+				yaffs_ReadChunkWithTagsFromNAND(dev,+								chunkInNAND,+								NULL, &newTags);++				/* Do a proper find */+				existingChunk =+				    yaffs_FindChunkInFile(in, chunkInInode,+							  &existingTags);+			}++			if (existingChunk <= 0) {+				/*Hoosterman - how did this happen? */++				T(YAFFS_TRACE_ERROR,+				  (TSTR+				   ("yaffs tragedy: existing chunk < 0 in scan"+				    TENDSTR)));++			}++			/* NB The deleted flags should be false, otherwise the chunks will+			 * not be loaded during a scan+			 */++			if (inScan > 0) {+				newSerial = newTags.serialNumber;+				existingSerial = existingTags.serialNumber;+			}++			if ((inScan > 0) &&+			    (in->myDev->isYaffs2 ||+			     existingChunk <= 0 ||+			     ((existingSerial + 1) & 3) == newSerial)) {+				/* Forward scanning.+				 * Use new+				 * Delete the old one and drop through to update the tnode+				 */+				yaffs_DeleteChunk(dev, existingChunk, 1,+						  __LINE__);+			} else {+				/* Backward scanning or we want to use the existing one+				 * Use existing.+				 * Delete the new one and return early so that the tnode isn't changed+				 */+				yaffs_DeleteChunk(dev, chunkInNAND, 1,+						  __LINE__);+				return YAFFS_OK;+			}+		}++	}++	if (existingChunk == 0)+		in->nDataChunks++;++	yaffs_PutLevel0Tnode(dev, tn, chunkInInode, chunkInNAND);++	return YAFFS_OK;+}++static int yaffs_ReadChunkDataFromObject(yaffs_Object *in, int chunkInInode,+					__u8 *buffer)+{+	int chunkInNAND = yaffs_FindChunkInFile(in, chunkInInode, NULL);++	if (chunkInNAND >= 0)+		return yaffs_ReadChunkWithTagsFromNAND(in->myDev, chunkInNAND,+						buffer, NULL);+	else {+		T(YAFFS_TRACE_NANDACCESS,+		  (TSTR("Chunk %d not found zero instead" TENDSTR),+		   chunkInNAND));+		/* get sane (zero) data if you read a hole */+		memset(buffer, 0, in->myDev->nDataBytesPerChunk);+		return 0;+	}++}++void yaffs_DeleteChunk(yaffs_Device *dev, int chunkId, int markNAND, int lyn)+{+	int block;+	int page;+	yaffs_ExtendedTags tags;+	yaffs_BlockInfo *bi;++	if (chunkId <= 0)+		return;++	dev->nDeletions++;+	block = chunkId / dev->nChunksPerBlock;+	page = chunkId % dev->nChunksPerBlock;+++	if (!yaffs_CheckChunkBit(dev, block, page))+		T(YAFFS_TRACE_VERIFY,+			(TSTR("Deleting invalid chunk %d"TENDSTR),+			 chunkId));++	bi = yaffs_GetBlockInfo(dev, block);++	T(YAFFS_TRACE_DELETION,+	  (TSTR("line %d delete of chunk %d" TENDSTR), lyn, chunkId));++	if (markNAND &&+	    bi->blockState != YAFFS_BLOCK_STATE_COLLECTING && !dev->isYaffs2) {++		yaffs_InitialiseTags(&tags);++		tags.chunkDeleted = 1;++		yaffs_WriteChunkWithTagsToNAND(dev, chunkId, NULL, &tags);+		yaffs_HandleUpdateChunk(dev, chunkId, &tags);+	} else {+		dev->nUnmarkedDeletions++;+	}++	/* Pull out of the management area.+	 * If the whole block became dirty, this will kick off an erasure.+	 */+	if (bi->blockState == YAFFS_BLOCK_STATE_ALLOCATING ||+	    bi->blockState == YAFFS_BLOCK_STATE_FULL ||+	    bi->blockState == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||+	    bi->blockState == YAFFS_BLOCK_STATE_COLLECTING) {+		dev->nFreeChunks++;++		yaffs_ClearChunkBit(dev, block, page);++		bi->pagesInUse--;++		if (bi->pagesInUse == 0 &&+		    !bi->hasShrinkHeader &&+		    bi->blockState != YAFFS_BLOCK_STATE_ALLOCATING &&+		    bi->blockState != YAFFS_BLOCK_STATE_NEEDS_SCANNING) {+			yaffs_BlockBecameDirty(dev, block);+		}++	}++}++static int yaffs_WriteChunkDataToObject(yaffs_Object *in, int chunkInInode,+					const __u8 *buffer, int nBytes,+					int useReserve)+{+	/* Find old chunk Need to do this to get serial number+	 * Write new one and patch into tree.+	 * Invalidate old tags.+	 */++	int prevChunkId;+	yaffs_ExtendedTags prevTags;++	int newChunkId;+	yaffs_ExtendedTags newTags;++	yaffs_Device *dev = in->myDev;++	yaffs_CheckGarbageCollection(dev);++	/* Get the previous chunk at this location in the file if it exists */+	prevChunkId = yaffs_FindChunkInFile(in, chunkInInode, &prevTags);++	/* Set up new tags */+	yaffs_InitialiseTags(&newTags);++	newTags.chunkId = chunkInInode;+	newTags.objectId = in->objectId;+	newTags.serialNumber =+	    (prevChunkId >= 0) ? prevTags.serialNumber + 1 : 1;+	newTags.byteCount = nBytes;++	if (nBytes < 1 || nBytes > dev->totalBytesPerChunk) {+		T(YAFFS_TRACE_ERROR,+		(TSTR("Writing %d bytes to chunk!!!!!!!!!" TENDSTR), nBytes));+		YBUG();+	}++	newChunkId =+	    yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &newTags,+					      useReserve);++	if (newChunkId >= 0) {+		yaffs_PutChunkIntoFile(in, chunkInInode, newChunkId, 0);++		if (prevChunkId >= 0)+			yaffs_DeleteChunk(dev, prevChunkId, 1, __LINE__);++		yaffs_CheckFileSanity(in);+	}+	return newChunkId;++}++/* UpdateObjectHeader updates the header on NAND for an object.+ * If name is not NULL, then that new name is used.+ */+int yaffs_UpdateObjectHeader(yaffs_Object *in, const YCHAR *name, int force,+			     int isShrink, int shadows)+{++	yaffs_BlockInfo *bi;++	yaffs_Device *dev = in->myDev;++	int prevChunkId;+	int retVal = 0;+	int result = 0;++	int newChunkId;+	yaffs_ExtendedTags newTags;+	yaffs_ExtendedTags oldTags;++	__u8 *buffer = NULL;+	YCHAR oldName[YAFFS_MAX_NAME_LENGTH + 1];++	yaffs_ObjectHeader *oh = NULL;++	yaffs_strcpy(oldName, _Y("silly old name"));+++	if (!in->fake ||+		in == dev->rootDir || /* The rootDir should also be saved */+		force) {++		yaffs_CheckGarbageCollection(dev);+		yaffs_CheckObjectDetailsLoaded(in);++		buffer = yaffs_GetTempBuffer(in->myDev, __LINE__);+		oh = (yaffs_ObjectHeader *) buffer;++		prevChunkId = in->hdrChunk;++		if (prevChunkId > 0) {+			result = yaffs_ReadChunkWithTagsFromNAND(dev, prevChunkId,+							buffer, &oldTags);++			yaffs_VerifyObjectHeader(in, oh, &oldTags, 0);++			memcpy(oldName, oh->name, sizeof(oh->name));+		}++		memset(buffer, 0xFF, dev->nDataBytesPerChunk);++		oh->type = in->variantType;+		oh->yst_mode = in->yst_mode;+		oh->shadowsObject = oh->inbandShadowsObject = shadows;++#ifdef CONFIG_YAFFS_WINCE+		oh->win_atime[0] = in->win_atime[0];+		oh->win_ctime[0] = in->win_ctime[0];+		oh->win_mtime[0] = in->win_mtime[0];+		oh->win_atime[1] = in->win_atime[1];+		oh->win_ctime[1] = in->win_ctime[1];+		oh->win_mtime[1] = in->win_mtime[1];+#else+		oh->yst_uid = in->yst_uid;+		oh->yst_gid = in->yst_gid;+		oh->yst_atime = in->yst_atime;+		oh->yst_mtime = in->yst_mtime;+		oh->yst_ctime = in->yst_ctime;+		oh->yst_rdev = in->yst_rdev;+#endif+		if (in->parent)+			oh->parentObjectId = in->parent->objectId;+		else+			oh->parentObjectId = 0;++		if (name && *name) {+			memset(oh->name, 0, sizeof(oh->name));+			yaffs_strncpy(oh->name, name, YAFFS_MAX_NAME_LENGTH);+		} else if (prevChunkId >= 0)+			memcpy(oh->name, oldName, sizeof(oh->name));+		else+			memset(oh->name, 0, sizeof(oh->name));++		oh->isShrink = isShrink;++		switch (in->variantType) {+		case YAFFS_OBJECT_TYPE_UNKNOWN:+			/* Should not happen */+			break;+		case YAFFS_OBJECT_TYPE_FILE:+			oh->fileSize =+			    (oh->parentObjectId == YAFFS_OBJECTID_DELETED+			     || oh->parentObjectId ==+			     YAFFS_OBJECTID_UNLINKED) ? 0 : in->variant.+			    fileVariant.fileSize;+			break;+		case YAFFS_OBJECT_TYPE_HARDLINK:+			oh->equivalentObjectId =+			    in->variant.hardLinkVariant.equivalentObjectId;+			break;+		case YAFFS_OBJECT_TYPE_SPECIAL:+			/* Do nothing */+			break;+		case YAFFS_OBJECT_TYPE_DIRECTORY:+			/* Do nothing */+			break;+		case YAFFS_OBJECT_TYPE_SYMLINK:+			yaffs_strncpy(oh->alias,+				      in->variant.symLinkVariant.alias,+				      YAFFS_MAX_ALIAS_LENGTH);+			oh->alias[YAFFS_MAX_ALIAS_LENGTH] = 0;+			break;+		}++		/* Tags */+		yaffs_InitialiseTags(&newTags);+		in->serial++;+		newTags.chunkId = 0;+		newTags.objectId = in->objectId;+		newTags.serialNumber = in->serial;++		/* Add extra info for file header */++		newTags.extraHeaderInfoAvailable = 1;+		newTags.extraParentObjectId = oh->parentObjectId;+		newTags.extraFileLength = oh->fileSize;+		newTags.extraIsShrinkHeader = oh->isShrink;+		newTags.extraEquivalentObjectId = oh->equivalentObjectId;+		newTags.extraShadows = (oh->shadowsObject > 0) ? 1 : 0;+		newTags.extraObjectType = in->variantType;++		yaffs_VerifyObjectHeader(in, oh, &newTags, 1);++		/* Create new chunk in NAND */+		newChunkId =+		    yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &newTags,+						      (prevChunkId >= 0) ? 1 : 0);++		if (newChunkId >= 0) {++			in->hdrChunk = newChunkId;++			if (prevChunkId >= 0) {+				yaffs_DeleteChunk(dev, prevChunkId, 1,+						  __LINE__);+			}++			if (!yaffs_ObjectHasCachedWriteData(in))+				in->dirty = 0;++			/* If this was a shrink, then mark the block that the chunk lives on */+			if (isShrink) {+				bi = yaffs_GetBlockInfo(in->myDev,+					newChunkId / in->myDev->nChunksPerBlock);+				bi->hasShrinkHeader = 1;+			}++		}++		retVal = newChunkId;++	}++	if (buffer)+		yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);++	return retVal;+}++/*------------------------ Short Operations Cache ----------------------------------------+ *   In many situations where there is no high level buffering (eg WinCE) a lot of+ *   reads might be short sequential reads, and a lot of writes may be short+ *   sequential writes. eg. scanning/writing a jpeg file.+ *   In these cases, a short read/write cache can provide a huge perfomance benefit+ *   with dumb-as-a-rock code.+ *   In Linux, the page cache provides read buffering aand the short op cache provides write+ *   buffering.+ *+ *   There are a limited number (~10) of cache chunks per device so that we don't+ *   need a very intelligent search.+ */++static int yaffs_ObjectHasCachedWriteData(yaffs_Object *obj)+{+	yaffs_Device *dev = obj->myDev;+	int i;+	yaffs_ChunkCache *cache;+	int nCaches = obj->myDev->nShortOpCaches;++	for (i = 0; i < nCaches; i++) {+		cache = &dev->srCache[i];+		if (cache->object == obj &&+		    cache->dirty)+			return 1;+	}++	return 0;+}+++static void yaffs_FlushFilesChunkCache(yaffs_Object *obj)+{+	yaffs_Device *dev = obj->myDev;+	int lowest = -99;	/* Stop compiler whining. */+	int i;+	yaffs_ChunkCache *cache;+	int chunkWritten = 0;+	int nCaches = obj->myDev->nShortOpCaches;++	if (nCaches > 0) {+		do {+			cache = NULL;++			/* Find the dirty cache for this object with the lowest chunk id. */+			for (i = 0; i < nCaches; i++) {+				if (dev->srCache[i].object == obj &&+				    dev->srCache[i].dirty) {+					if (!cache+					    || dev->srCache[i].chunkId <+					    lowest) {+						cache = &dev->srCache[i];+						lowest = cache->chunkId;+					}+				}+			}++			if (cache && !cache->locked) {+				/* Write it out and free it up */++				chunkWritten =+				    yaffs_WriteChunkDataToObject(cache->object,+								 cache->chunkId,+								 cache->data,+								 cache->nBytes,+								 1);+				cache->dirty = 0;+				cache->object = NULL;+			}++		} while (cache && chunkWritten > 0);++		if (cache) {+			/* Hoosterman, disk full while writing cache out. */+			T(YAFFS_TRACE_ERROR,+			  (TSTR("yaffs tragedy: no space during cache write" TENDSTR)));++		}+	}++}++/*yaffs_FlushEntireDeviceCache(dev)+ *+ *+ */++void yaffs_FlushEntireDeviceCache(yaffs_Device *dev)+{+	yaffs_Object *obj;+	int nCaches = dev->nShortOpCaches;+	int i;++	/* Find a dirty object in the cache and flush it...+	 * until there are no further dirty objects.+	 */+	do {+		obj = NULL;+		for (i = 0; i < nCaches && !obj; i++) {+			if (dev->srCache[i].object &&+			    dev->srCache[i].dirty)+				obj = dev->srCache[i].object;++		}+		if (obj)+			yaffs_FlushFilesChunkCache(obj);++	} while (obj);++}+++/* Grab us a cache chunk for use.+ * First look for an empty one.+ * Then look for the least recently used non-dirty one.+ * Then look for the least recently used dirty one...., flush and look again.+ */+static yaffs_ChunkCache *yaffs_GrabChunkCacheWorker(yaffs_Device *dev)+{+	int i;++	if (dev->nShortOpCaches > 0) {+		for (i = 0; i < dev->nShortOpCaches; i++) {+			if (!dev->srCache[i].object)+				return &dev->srCache[i];+		}+	}++	return NULL;+}++static yaffs_ChunkCache *yaffs_GrabChunkCache(yaffs_Device *dev)+{+	yaffs_ChunkCache *cache;+	yaffs_Object *theObj;+	int usage;+	int i;+	int pushout;++	if (dev->nShortOpCaches > 0) {+		/* Try find a non-dirty one... */++		cache = yaffs_GrabChunkCacheWorker(dev);++		if (!cache) {+			/* They were all dirty, find the last recently used object and flush+			 * its cache, then  find again.+			 * NB what's here is not very accurate, we actually flush the object+			 * the last recently used page.+			 */++			/* With locking we can't assume we can use entry zero */++			theObj = NULL;+			usage = -1;+			cache = NULL;+			pushout = -1;++			for (i = 0; i < dev->nShortOpCaches; i++) {+				if (dev->srCache[i].object &&+				    !dev->srCache[i].locked &&+				    (dev->srCache[i].lastUse < usage || !cache)) {+					usage = dev->srCache[i].lastUse;+					theObj = dev->srCache[i].object;+					cache = &dev->srCache[i];+					pushout = i;+				}+			}++			if (!cache || cache->dirty) {+				/* Flush and try again */+				yaffs_FlushFilesChunkCache(theObj);+				cache = yaffs_GrabChunkCacheWorker(dev);+			}++		}+		return cache;+	} else+		return NULL;++}++/* Find a cached chunk */+static yaffs_ChunkCache *yaffs_FindChunkCache(const yaffs_Object *obj,+					      int chunkId)+{+	yaffs_Device *dev = obj->myDev;+	int i;+	if (dev->nShortOpCaches > 0) {+		for (i = 0; i < dev->nShortOpCaches; i++) {+			if (dev->srCache[i].object == obj &&+			    dev->srCache[i].chunkId == chunkId) {+				dev->cacheHits++;++				return &dev->srCache[i];+			}+		}+	}+	return NULL;+}++/* Mark the chunk for the least recently used algorithym */+static void yaffs_UseChunkCache(yaffs_Device *dev, yaffs_ChunkCache *cache,+				int isAWrite)+{++	if (dev->nShortOpCaches > 0) {+		if (dev->srLastUse < 0 || dev->srLastUse > 100000000) {+			/* Reset the cache usages */+			int i;+			for (i = 1; i < dev->nShortOpCaches; i++)+				dev->srCache[i].lastUse = 0;++			dev->srLastUse = 0;+		}++		dev->srLastUse++;++		cache->lastUse = dev->srLastUse;++		if (isAWrite)+			cache->dirty = 1;+	}+}++/* Invalidate a single cache page.+ * Do this when a whole page gets written,+ * ie the short cache for this page is no longer valid.+ */+static void yaffs_InvalidateChunkCache(yaffs_Object *object, int chunkId)+{+	if (object->myDev->nShortOpCaches > 0) {+		yaffs_ChunkCache *cache = yaffs_FindChunkCache(object, chunkId);++		if (cache)+			cache->object = NULL;+	}+}++/* Invalidate all the cache pages associated with this object+ * Do this whenever ther file is deleted or resized.+ */+static void yaffs_InvalidateWholeChunkCache(yaffs_Object *in)+{+	int i;+	yaffs_Device *dev = in->myDev;++	if (dev->nShortOpCaches > 0) {+		/* Invalidate it. */+		for (i = 0; i < dev->nShortOpCaches; i++) {+			if (dev->srCache[i].object == in)+				dev->srCache[i].object = NULL;+		}+	}+}++/*--------------------- Checkpointing --------------------*/+++static int yaffs_WriteCheckpointValidityMarker(yaffs_Device *dev, int head)+{+	yaffs_CheckpointValidity cp;++	memset(&cp, 0, sizeof(cp));++	cp.structType = sizeof(cp);+	cp.magic = YAFFS_MAGIC;+	cp.version = YAFFS_CHECKPOINT_VERSION;+	cp.head = (head) ? 1 : 0;++	return (yaffs_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp)) ?+		1 : 0;+}++static int yaffs_ReadCheckpointValidityMarker(yaffs_Device *dev, int head)+{+	yaffs_CheckpointValidity cp;+	int ok;++	ok = (yaffs_CheckpointRead(dev, &cp, sizeof(cp)) == sizeof(cp));++	if (ok)+		ok = (cp.structType == sizeof(cp)) &&+		     (cp.magic == YAFFS_MAGIC) &&+		     (cp.version == YAFFS_CHECKPOINT_VERSION) &&+		     (cp.head == ((head) ? 1 : 0));+	return ok ? 1 : 0;+}++static void yaffs_DeviceToCheckpointDevice(yaffs_CheckpointDevice *cp,+					   yaffs_Device *dev)+{+	cp->nErasedBlocks = dev->nErasedBlocks;+	cp->allocationBlock = dev->allocationBlock;+	cp->allocationPage = dev->allocationPage;+	cp->nFreeChunks = dev->nFreeChunks;++	cp->nDeletedFiles = dev->nDeletedFiles;+	cp->nUnlinkedFiles = dev->nUnlinkedFiles;+	cp->nBackgroundDeletions = dev->nBackgroundDeletions;+	cp->sequenceNumber = dev->sequenceNumber;+	cp->oldestDirtySequence = dev->oldestDirtySequence;++}++static void yaffs_CheckpointDeviceToDevice(yaffs_Device *dev,+					   yaffs_CheckpointDevice *cp)+{+	dev->nErasedBlocks = cp->nErasedBlocks;+	dev->allocationBlock = cp->allocationBlock;+	dev->allocationPage = cp->allocationPage;+	dev->nFreeChunks = cp->nFreeChunks;++	dev->nDeletedFiles = cp->nDeletedFiles;+	dev->nUnlinkedFiles = cp->nUnlinkedFiles;+	dev->nBackgroundDeletions = cp->nBackgroundDeletions;+	dev->sequenceNumber = cp->sequenceNumber;+	dev->oldestDirtySequence = cp->oldestDirtySequence;+}+++static int yaffs_WriteCheckpointDevice(yaffs_Device *dev)+{+	yaffs_CheckpointDevice cp;+	__u32 nBytes;+	__u32 nBlocks = (dev->internalEndBlock - dev->internalStartBlock + 1);++	int ok;++	/* Write device runtime values*/+	yaffs_DeviceToCheckpointDevice(&cp, dev);+	cp.structType = sizeof(cp);++	ok = (yaffs_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp));++	/* Write block info */+	if (ok) {+		nBytes = nBlocks * sizeof(yaffs_BlockInfo);+		ok = (yaffs_CheckpointWrite(dev, dev->blockInfo, nBytes) == nBytes);+	}++	/* Write chunk bits */+	if (ok) {+		nBytes = nBlocks * dev->chunkBitmapStride;+		ok = (yaffs_CheckpointWrite(dev, dev->chunkBits, nBytes) == nBytes);+	}+	return	 ok ? 1 : 0;++}++static int yaffs_ReadCheckpointDevice(yaffs_Device *dev)+{+	yaffs_CheckpointDevice cp;+	__u32 nBytes;+	__u32 nBlocks = (dev->internalEndBlock - dev->internalStartBlock + 1);++	int ok;++	ok = (yaffs_CheckpointRead(dev, &cp, sizeof(cp)) == sizeof(cp));+	if (!ok)+		return 0;++	if (cp.structType != sizeof(cp))+		return 0;+++	yaffs_CheckpointDeviceToDevice(dev, &cp);++	nBytes = nBlocks * sizeof(yaffs_BlockInfo);++	ok = (yaffs_CheckpointRead(dev, dev->blockInfo, nBytes) == nBytes);++	if (!ok)+		return 0;+	nBytes = nBlocks * dev->chunkBitmapStride;++	ok = (yaffs_CheckpointRead(dev, dev->chunkBits, nBytes) == nBytes);++	return ok ? 1 : 0;+}++static void yaffs_ObjectToCheckpointObject(yaffs_CheckpointObject *cp,+					   yaffs_Object *obj)+{++	cp->objectId = obj->objectId;+	cp->parentId = (obj->parent) ? obj->parent->objectId : 0;+	cp->hdrChunk = obj->hdrChunk;+	cp->variantType = obj->variantType;+	cp->deleted = obj->deleted;+	cp->softDeleted = obj->softDeleted;+	cp->unlinked = obj->unlinked;+	cp->fake = obj->fake;+	cp->renameAllowed = obj->renameAllowed;+	cp->unlinkAllowed = obj->unlinkAllowed;+	cp->serial = obj->serial;+	cp->nDataChunks = obj->nDataChunks;++	if (obj->variantType == YAFFS_OBJECT_TYPE_FILE)+		cp->fileSizeOrEquivalentObjectId = obj->variant.fileVariant.fileSize;+	else if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK)+		cp->fileSizeOrEquivalentObjectId = obj->variant.hardLinkVariant.equivalentObjectId;+}++static int yaffs_CheckpointObjectToObject(yaffs_Object *obj, yaffs_CheckpointObject *cp)+{++	yaffs_Object *parent;++	if (obj->variantType != cp->variantType) {+		T(YAFFS_TRACE_ERROR, (TSTR("Checkpoint read object %d type %d "+			TCONT("chunk %d does not match existing object type %d")+			TENDSTR), cp->objectId, cp->variantType, cp->hdrChunk,+			obj->variantType));+		return 0;+	}++	obj->objectId = cp->objectId;++	if (cp->parentId)+		parent = yaffs_FindOrCreateObjectByNumber(+					obj->myDev,+					cp->parentId,+					YAFFS_OBJECT_TYPE_DIRECTORY);+	else+		parent = NULL;++	if (parent) {+		if (parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {+			T(YAFFS_TRACE_ALWAYS, (TSTR("Checkpoint read object %d parent %d type %d"+				TCONT(" chunk %d Parent type, %d, not directory")+				TENDSTR),+				cp->objectId, cp->parentId, cp->variantType,+				cp->hdrChunk, parent->variantType));+			return 0;+		}+		yaffs_AddObjectToDirectory(parent, obj);+	}++	obj->hdrChunk = cp->hdrChunk;+	obj->variantType = cp->variantType;+	obj->deleted = cp->deleted;+	obj->softDeleted = cp->softDeleted;+	obj->unlinked = cp->unlinked;+	obj->fake = cp->fake;+	obj->renameAllowed = cp->renameAllowed;+	obj->unlinkAllowed = cp->unlinkAllowed;+	obj->serial = cp->serial;+	obj->nDataChunks = cp->nDataChunks;++	if (obj->variantType == YAFFS_OBJECT_TYPE_FILE)+		obj->variant.fileVariant.fileSize = cp->fileSizeOrEquivalentObjectId;+	else if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK)+		obj->variant.hardLinkVariant.equivalentObjectId = cp->fileSizeOrEquivalentObjectId;++	if (obj->hdrChunk > 0)+		obj->lazyLoaded = 1;+	return 1;+}++++static int yaffs_CheckpointTnodeWorker(yaffs_Object *in, yaffs_Tnode *tn,+					__u32 level, int chunkOffset)+{+	int i;+	yaffs_Device *dev = in->myDev;+	int ok = 1;+	int tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;++	if (tnodeSize < sizeof(yaffs_Tnode))+		tnodeSize = sizeof(yaffs_Tnode);+++	if (tn) {+		if (level > 0) {++			for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) {+				if (tn->internal[i]) {+					ok = yaffs_CheckpointTnodeWorker(in,+							tn->internal[i],+							level - 1,+							(chunkOffset<<YAFFS_TNODES_INTERNAL_BITS) + i);+				}+			}+		} else if (level == 0) {+			__u32 baseOffset = chunkOffset <<  YAFFS_TNODES_LEVEL0_BITS;+			ok = (yaffs_CheckpointWrite(dev, &baseOffset, sizeof(baseOffset)) == sizeof(baseOffset));+			if (ok)+				ok = (yaffs_CheckpointWrite(dev, tn, tnodeSize) == tnodeSize);+		}+	}++	return ok;++}++static int yaffs_WriteCheckpointTnodes(yaffs_Object *obj)+{+	__u32 endMarker = ~0;+	int ok = 1;++	if (obj->variantType == YAFFS_OBJECT_TYPE_FILE) {+		ok = yaffs_CheckpointTnodeWorker(obj,+					    obj->variant.fileVariant.top,+					    obj->variant.fileVariant.topLevel,+					    0);+		if (ok)+			ok = (yaffs_CheckpointWrite(obj->myDev, &endMarker, sizeof(endMarker)) ==+				sizeof(endMarker));+	}++	return ok ? 1 : 0;+}++static int yaffs_ReadCheckpointTnodes(yaffs_Object *obj)+{+	__u32 baseChunk;+	int ok = 1;+	yaffs_Device *dev = obj->myDev;+	yaffs_FileStructure *fileStructPtr = &obj->variant.fileVariant;+	yaffs_Tnode *tn;+	int nread = 0;+	int tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;++	if (tnodeSize < sizeof(yaffs_Tnode))+		tnodeSize = sizeof(yaffs_Tnode);++	ok = (yaffs_CheckpointRead(dev, &baseChunk, sizeof(baseChunk)) == sizeof(baseChunk));++	while (ok && (~baseChunk)) {+		nread++;+		/* Read level 0 tnode */+++		tn = yaffs_GetTnodeRaw(dev);+		if (tn)+			ok = (yaffs_CheckpointRead(dev, tn, tnodeSize) == tnodeSize);+		else+			ok = 0;++		if (tn && ok)+			ok = yaffs_AddOrFindLevel0Tnode(dev,+							fileStructPtr,+							baseChunk,+							tn) ? 1 : 0;++		if (ok)+			ok = (yaffs_CheckpointRead(dev, &baseChunk, sizeof(baseChunk)) == sizeof(baseChunk));++	}++	T(YAFFS_TRACE_CHECKPOINT, (+		TSTR("Checkpoint read tnodes %d records, last %d. ok %d" TENDSTR),+		nread, baseChunk, ok));++	return ok ? 1 : 0;+}+++static int yaffs_WriteCheckpointObjects(yaffs_Device *dev)+{+	yaffs_Object *obj;+	yaffs_CheckpointObject cp;+	int i;+	int ok = 1;+	struct ylist_head *lh;+++	/* Iterate through the objects in each hash entry,+	 * dumping them to the checkpointing stream.+	 */++	for (i = 0; ok &&  i <  YAFFS_NOBJECT_BUCKETS; i++) {+		ylist_for_each(lh, &dev->objectBucket[i].list) {+			if (lh) {+				obj = ylist_entry(lh, yaffs_Object, hashLink);+				if (!obj->deferedFree) {+					yaffs_ObjectToCheckpointObject(&cp, obj);+					cp.structType = sizeof(cp);++					T(YAFFS_TRACE_CHECKPOINT, (+						TSTR("Checkpoint write object %d parent %d type %d chunk %d obj addr %x" TENDSTR),+						cp.objectId, cp.parentId, cp.variantType, cp.hdrChunk, (unsigned) obj));++					ok = (yaffs_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp));++					if (ok && obj->variantType == YAFFS_OBJECT_TYPE_FILE)+						ok = yaffs_WriteCheckpointTnodes(obj);+				}+			}+		}+	}++	/* Dump end of list */+	memset(&cp, 0xFF, sizeof(yaffs_CheckpointObject));+	cp.structType = sizeof(cp);++	if (ok)+		ok = (yaffs_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp));++	return ok ? 1 : 0;+}++static int yaffs_ReadCheckpointObjects(yaffs_Device *dev)+{+	yaffs_Object *obj;+	yaffs_CheckpointObject cp;+	int ok = 1;+	int done = 0;+	yaffs_Object *hardList = NULL;++	while (ok && !done) {+		ok = (yaffs_CheckpointRead(dev, &cp, sizeof(cp)) == sizeof(cp));+		if (cp.structType != sizeof(cp)) {+			T(YAFFS_TRACE_CHECKPOINT, (TSTR("struct size %d instead of %d ok %d"TENDSTR),+				cp.structType, sizeof(cp), ok));+			ok = 0;+		}++		T(YAFFS_TRACE_CHECKPOINT, (TSTR("Checkpoint read object %d parent %d type %d chunk %d " TENDSTR),+			cp.objectId, cp.parentId, cp.variantType, cp.hdrChunk));++		if (ok && cp.objectId == ~0)+			done = 1;+		else if (ok) {+			obj = yaffs_FindOrCreateObjectByNumber(dev, cp.objectId, cp.variantType);+			if (obj) {+				ok = yaffs_CheckpointObjectToObject(obj, &cp);+				if (!ok)+					break;+				if (obj->variantType == YAFFS_OBJECT_TYPE_FILE) {+					ok = yaffs_ReadCheckpointTnodes(obj);+				} else if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) {+					obj->hardLinks.next =+						(struct ylist_head *) hardList;+					hardList = obj;+				}+			} else+				ok = 0;+		}+	}++	if (ok)+		yaffs_HardlinkFixup(dev, hardList);++	return ok ? 1 : 0;+}++static int yaffs_WriteCheckpointSum(yaffs_Device *dev)+{+	__u32 checkpointSum;+	int ok;++	yaffs_GetCheckpointSum(dev, &checkpointSum);++	ok = (yaffs_CheckpointWrite(dev, &checkpointSum, sizeof(checkpointSum)) == sizeof(checkpointSum));++	if (!ok)+		return 0;++	return 1;+}++static int yaffs_ReadCheckpointSum(yaffs_Device *dev)+{+	__u32 checkpointSum0;+	__u32 checkpointSum1;+	int ok;++	yaffs_GetCheckpointSum(dev, &checkpointSum0);++	ok = (yaffs_CheckpointRead(dev, &checkpointSum1, sizeof(checkpointSum1)) == sizeof(checkpointSum1));++	if (!ok)+		return 0;++	if (checkpointSum0 != checkpointSum1)+		return 0;++	return 1;+}+++static int yaffs_WriteCheckpointData(yaffs_Device *dev)+{+	int ok = 1;++	if (dev->skipCheckpointWrite || !dev->isYaffs2) {+		T(YAFFS_TRACE_CHECKPOINT, (TSTR("skipping checkpoint write" TENDSTR)));+		ok = 0;+	}++	if (ok)+		ok = yaffs_CheckpointOpen(dev, 1);++	if (ok) {+		T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint validity" TENDSTR)));+		ok = yaffs_WriteCheckpointValidityMarker(dev, 1);+	}+	if (ok) {+		T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint device" TENDSTR)));+		ok = yaffs_WriteCheckpointDevice(dev);+	}+	if (ok) {+		T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint objects" TENDSTR)));+		ok = yaffs_WriteCheckpointObjects(dev);+	}+	if (ok) {+		T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint validity" TENDSTR)));+		ok = yaffs_WriteCheckpointValidityMarker(dev, 0);+	}++	if (ok)+		ok = yaffs_WriteCheckpointSum(dev);++	if (!yaffs_CheckpointClose(dev))+		ok = 0;++	if (ok)+		dev->isCheckpointed = 1;+	else+		dev->isCheckpointed = 0;++	return dev->isCheckpointed;+}++static int yaffs_ReadCheckpointData(yaffs_Device *dev)+{+	int ok = 1;++	if (dev->skipCheckpointRead || !dev->isYaffs2) {+		T(YAFFS_TRACE_CHECKPOINT, (TSTR("skipping checkpoint read" TENDSTR)));+		ok = 0;+	}++	if (ok)+		ok = yaffs_CheckpointOpen(dev, 0); /* open for read */++	if (ok) {+		T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint validity" TENDSTR)));+		ok = yaffs_ReadCheckpointValidityMarker(dev, 1);+	}+	if (ok) {+		T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint device" TENDSTR)));+		ok = yaffs_ReadCheckpointDevice(dev);+	}+	if (ok) {+		T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint objects" TENDSTR)));+		ok = yaffs_ReadCheckpointObjects(dev);+	}+	if (ok) {+		T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint validity" TENDSTR)));+		ok = yaffs_ReadCheckpointValidityMarker(dev, 0);+	}++	if (ok) {+		ok = yaffs_ReadCheckpointSum(dev);+		T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint checksum %d" TENDSTR), ok));+	}++	if (!yaffs_CheckpointClose(dev))+		ok = 0;++	if (ok)+		dev->isCheckpointed = 1;+	else+		dev->isCheckpointed = 0;++	return ok ? 1 : 0;++}++static void yaffs_InvalidateCheckpoint(yaffs_Device *dev)+{+	if (dev->isCheckpointed ||+			dev->blocksInCheckpoint > 0) {+		dev->isCheckpointed = 0;+		yaffs_CheckpointInvalidateStream(dev);+		if (dev->superBlock && dev->markSuperBlockDirty)+			dev->markSuperBlockDirty(dev->superBlock);+	}+}+++int yaffs_CheckpointSave(yaffs_Device *dev)+{++	T(YAFFS_TRACE_CHECKPOINT, (TSTR("save entry: isCheckpointed %d"TENDSTR), dev->isCheckpointed));++	yaffs_VerifyObjects(dev);+	yaffs_VerifyBlocks(dev);+	yaffs_VerifyFreeChunks(dev);++	if (!dev->isCheckpointed) {+		yaffs_InvalidateCheckpoint(dev);+		yaffs_WriteCheckpointData(dev);+	}++	T(YAFFS_TRACE_ALWAYS, (TSTR("save exit: isCheckpointed %d"TENDSTR), dev->isCheckpointed));++	return dev->isCheckpointed;+}++int yaffs_CheckpointRestore(yaffs_Device *dev)+{+	int retval;+	T(YAFFS_TRACE_CHECKPOINT, (TSTR("restore entry: isCheckpointed %d"TENDSTR), dev->isCheckpointed));++	retval = yaffs_ReadCheckpointData(dev);++	if (dev->isCheckpointed) {+		yaffs_VerifyObjects(dev);+		yaffs_VerifyBlocks(dev);+		yaffs_VerifyFreeChunks(dev);+	}++	T(YAFFS_TRACE_CHECKPOINT, (TSTR("restore exit: isCheckpointed %d"TENDSTR), dev->isCheckpointed));++	return retval;+}++/*--------------------- File read/write ------------------------+ * Read and write have very similar structures.+ * In general the read/write has three parts to it+ * An incomplete chunk to start with (if the read/write is not chunk-aligned)+ * Some complete chunks+ * An incomplete chunk to end off with+ *+ * Curve-balls: the first chunk might also be the last chunk.+ */++int yaffs_ReadDataFromFile(yaffs_Object *in, __u8 *buffer, loff_t offset,+			int nBytes)+{++	int chunk;+	__u32 start;+	int nToCopy;+	int n = nBytes;+	int nDone = 0;+	yaffs_ChunkCache *cache;++	yaffs_Device *dev;++	dev = in->myDev;++	while (n > 0) {+		/* chunk = offset / dev->nDataBytesPerChunk + 1; */+		/* start = offset % dev->nDataBytesPerChunk; */+		yaffs_AddrToChunk(dev, offset, &chunk, &start);+		chunk++;++		/* OK now check for the curveball where the start and end are in+		 * the same chunk.+		 */+		if ((start + n) < dev->nDataBytesPerChunk)+			nToCopy = n;+		else+			nToCopy = dev->nDataBytesPerChunk - start;++		cache = yaffs_FindChunkCache(in, chunk);++		/* If the chunk is already in the cache or it is less than a whole chunk+		 * or we're using inband tags then use the cache (if there is caching)+		 * else bypass the cache.+		 */+		if (cache || nToCopy != dev->nDataBytesPerChunk || dev->inbandTags) {+			if (dev->nShortOpCaches > 0) {++				/* If we can't find the data in the cache, then load it up. */++				if (!cache) {+					cache = yaffs_GrabChunkCache(in->myDev);+					cache->object = in;+					cache->chunkId = chunk;+					cache->dirty = 0;+					cache->locked = 0;+					yaffs_ReadChunkDataFromObject(in, chunk,+								      cache->+								      data);+					cache->nBytes = 0;+				}++				yaffs_UseChunkCache(dev, cache, 0);++				cache->locked = 1;+++				memcpy(buffer, &cache->data[start], nToCopy);++				cache->locked = 0;+			} else {+				/* Read into the local buffer then copy..*/++				__u8 *localBuffer =+				    yaffs_GetTempBuffer(dev, __LINE__);+				yaffs_ReadChunkDataFromObject(in, chunk,+							      localBuffer);++				memcpy(buffer, &localBuffer[start], nToCopy);+++				yaffs_ReleaseTempBuffer(dev, localBuffer,+							__LINE__);+			}++		} else {++			/* A full chunk. Read directly into the supplied buffer. */+			yaffs_ReadChunkDataFromObject(in, chunk, buffer);++		}++		n -= nToCopy;+		offset += nToCopy;+		buffer += nToCopy;+		nDone += nToCopy;++	}++	return nDone;+}++int yaffs_WriteDataToFile(yaffs_Object *in, const __u8 *buffer, loff_t offset,+			int nBytes, int writeThrough)+{++	int chunk;+	__u32 start;+	int nToCopy;+	int n = nBytes;+	int nDone = 0;+	int nToWriteBack;+	int startOfWrite = offset;+	int chunkWritten = 0;+	__u32 nBytesRead;+	__u32 chunkStart;++	yaffs_Device *dev;++	dev = in->myDev;++	while (n > 0 && chunkWritten >= 0) {+		/* chunk = offset / dev->nDataBytesPerChunk + 1; */+		/* start = offset % dev->nDataBytesPerChunk; */+		yaffs_AddrToChunk(dev, offset, &chunk, &start);++		if (chunk * dev->nDataBytesPerChunk + start != offset ||+				start >= dev->nDataBytesPerChunk) {+			T(YAFFS_TRACE_ERROR, (+			   TSTR("AddrToChunk of offset %d gives chunk %d start %d"+			   TENDSTR),+			   (int)offset, chunk, start));+		}+		chunk++;++		/* OK now check for the curveball where the start and end are in+		 * the same chunk.+		 */++		if ((start + n) < dev->nDataBytesPerChunk) {+			nToCopy = n;++			/* Now folks, to calculate how many bytes to write back....+			 * If we're overwriting and not writing to then end of file then+			 * we need to write back as much as was there before.+			 */++			chunkStart = ((chunk - 1) * dev->nDataBytesPerChunk);++			if (chunkStart > in->variant.fileVariant.fileSize)+				nBytesRead = 0; /* Past end of file */+			else+				nBytesRead = in->variant.fileVariant.fileSize - chunkStart;++			if (nBytesRead > dev->nDataBytesPerChunk)+				nBytesRead = dev->nDataBytesPerChunk;++			nToWriteBack =+			    (nBytesRead >+			     (start + n)) ? nBytesRead : (start + n);++			if (nToWriteBack < 0 || nToWriteBack > dev->nDataBytesPerChunk)+				YBUG();++		} else {+			nToCopy = dev->nDataBytesPerChunk - start;+			nToWriteBack = dev->nDataBytesPerChunk;+		}++		if (nToCopy != dev->nDataBytesPerChunk || dev->inbandTags) {+			/* An incomplete start or end chunk (or maybe both start and end chunk),+			 * or we're using inband tags, so we want to use the cache buffers.+			 */+			if (dev->nShortOpCaches > 0) {+				yaffs_ChunkCache *cache;+				/* If we can't find the data in the cache, then load the cache */+				cache = yaffs_FindChunkCache(in, chunk);++				if (!cache+				    && yaffs_CheckSpaceForAllocation(in->+								     myDev)) {+					cache = yaffs_GrabChunkCache(in->myDev);+					cache->object = in;+					cache->chunkId = chunk;+					cache->dirty = 0;+					cache->locked = 0;+					yaffs_ReadChunkDataFromObject(in, chunk,+								      cache->+								      data);+				} else if (cache &&+					!cache->dirty &&+					!yaffs_CheckSpaceForAllocation(in->myDev)) {+					/* Drop the cache if it was a read cache item and+					 * no space check has been made for it.+					 */+					 cache = NULL;+				}++				if (cache) {+					yaffs_UseChunkCache(dev, cache, 1);+					cache->locked = 1;+++					memcpy(&cache->data[start], buffer,+					       nToCopy);+++					cache->locked = 0;+					cache->nBytes = nToWriteBack;++					if (writeThrough) {+						chunkWritten =+						    yaffs_WriteChunkDataToObject+						    (cache->object,+						     cache->chunkId,+						     cache->data, cache->nBytes,+						     1);+						cache->dirty = 0;+					}++				} else {+					chunkWritten = -1;	/* fail the write */+				}+			} else {+				/* An incomplete start or end chunk (or maybe both start and end chunk)+				 * Read into the local buffer then copy, then copy over and write back.+				 */++				__u8 *localBuffer =+				    yaffs_GetTempBuffer(dev, __LINE__);++				yaffs_ReadChunkDataFromObject(in, chunk,+							      localBuffer);++++				memcpy(&localBuffer[start], buffer, nToCopy);++				chunkWritten =+				    yaffs_WriteChunkDataToObject(in, chunk,+								 localBuffer,+								 nToWriteBack,+								 0);++				yaffs_ReleaseTempBuffer(dev, localBuffer,+							__LINE__);++			}++		} else {+			/* A full chunk. Write directly from the supplied buffer. */++++			chunkWritten =+			    yaffs_WriteChunkDataToObject(in, chunk, buffer,+							 dev->nDataBytesPerChunk,+							 0);++			/* Since we've overwritten the cached data, we better invalidate it. */+			yaffs_InvalidateChunkCache(in, chunk);+		}++		if (chunkWritten >= 0) {+			n -= nToCopy;+			offset += nToCopy;+			buffer += nToCopy;+			nDone += nToCopy;+		}++	}++	/* Update file object */++	if ((startOfWrite + nDone) > in->variant.fileVariant.fileSize)+		in->variant.fileVariant.fileSize = (startOfWrite + nDone);++	in->dirty = 1;++	return nDone;+}+++/* ---------------------- File resizing stuff ------------------ */++static void yaffs_PruneResizedChunks(yaffs_Object *in, int newSize)+{++	yaffs_Device *dev = in->myDev;+	int oldFileSize = in->variant.fileVariant.fileSize;++	int lastDel = 1 + (oldFileSize - 1) / dev->nDataBytesPerChunk;++	int startDel = 1 + (newSize + dev->nDataBytesPerChunk - 1) /+	    dev->nDataBytesPerChunk;+	int i;+	int chunkId;++	/* Delete backwards so that we don't end up with holes if+	 * power is lost part-way through the operation.+	 */+	for (i = lastDel; i >= startDel; i--) {+		/* NB this could be optimised somewhat,+		 * eg. could retrieve the tags and write them without+		 * using yaffs_DeleteChunk+		 */++		chunkId = yaffs_FindAndDeleteChunkInFile(in, i, NULL);+		if (chunkId > 0) {+			if (chunkId <+			    (dev->internalStartBlock * dev->nChunksPerBlock)+			    || chunkId >=+			    ((dev->internalEndBlock ++			      1) * dev->nChunksPerBlock)) {+				T(YAFFS_TRACE_ALWAYS,+				  (TSTR("Found daft chunkId %d for %d" TENDSTR),+				   chunkId, i));+			} else {+				in->nDataChunks--;+				yaffs_DeleteChunk(dev, chunkId, 1, __LINE__);+			}+		}+	}++}++int yaffs_ResizeFile(yaffs_Object *in, loff_t newSize)+{++	int oldFileSize = in->variant.fileVariant.fileSize;+	__u32 newSizeOfPartialChunk;+	int newFullChunks;++	yaffs_Device *dev = in->myDev;++	yaffs_AddrToChunk(dev, newSize, &newFullChunks, &newSizeOfPartialChunk);++	yaffs_FlushFilesChunkCache(in);+	yaffs_InvalidateWholeChunkCache(in);++	yaffs_CheckGarbageCollection(dev);++	if (in->variantType != YAFFS_OBJECT_TYPE_FILE)+		return YAFFS_FAIL;++	if (newSize == oldFileSize)+		return YAFFS_OK;++	if (newSize < oldFileSize) {++		yaffs_PruneResizedChunks(in, newSize);++		if (newSizeOfPartialChunk != 0) {+			int lastChunk = 1 + newFullChunks;++			__u8 *localBuffer = yaffs_GetTempBuffer(dev, __LINE__);++			/* Got to read and rewrite the last chunk with its new size and zero pad */+			yaffs_ReadChunkDataFromObject(in, lastChunk,+						      localBuffer);++			memset(localBuffer + newSizeOfPartialChunk, 0,+			       dev->nDataBytesPerChunk - newSizeOfPartialChunk);++			yaffs_WriteChunkDataToObject(in, lastChunk, localBuffer,+						     newSizeOfPartialChunk, 1);++			yaffs_ReleaseTempBuffer(dev, localBuffer, __LINE__);+		}++		in->variant.fileVariant.fileSize = newSize;++		yaffs_PruneFileStructure(dev, &in->variant.fileVariant);+	} else {+		/* newsSize > oldFileSize */+		in->variant.fileVariant.fileSize = newSize;+	}+++	/* Write a new object header.+	 * show we've shrunk the file, if need be+	 * Do this only if the file is not in the deleted directories.+	 */+	if (in->parent &&+	    in->parent->objectId != YAFFS_OBJECTID_UNLINKED &&+	    in->parent->objectId != YAFFS_OBJECTID_DELETED)+		yaffs_UpdateObjectHeader(in, NULL, 0,+					 (newSize < oldFileSize) ? 1 : 0, 0);++	return YAFFS_OK;+}++loff_t yaffs_GetFileSize(yaffs_Object *obj)+{+	obj = yaffs_GetEquivalentObject(obj);++	switch (obj->variantType) {+	case YAFFS_OBJECT_TYPE_FILE:+		return obj->variant.fileVariant.fileSize;+	case YAFFS_OBJECT_TYPE_SYMLINK:+		return yaffs_strlen(obj->variant.symLinkVariant.alias);+	default:+		return 0;+	}+}++++int yaffs_FlushFile(yaffs_Object *in, int updateTime)+{+	int retVal;+	if (in->dirty) {+		yaffs_FlushFilesChunkCache(in);+		if (updateTime) {+#ifdef CONFIG_YAFFS_WINCE+			yfsd_WinFileTimeNow(in->win_mtime);+#else++			in->yst_mtime = Y_CURRENT_TIME;++#endif+		}++		retVal = (yaffs_UpdateObjectHeader(in, NULL, 0, 0, 0) >=+			0) ? YAFFS_OK : YAFFS_FAIL;+	} else {+		retVal = YAFFS_OK;+	}++	return retVal;++}++static int yaffs_DoGenericObjectDeletion(yaffs_Object *in)+{++	/* First off, invalidate the file's data in the cache, without flushing. */+	yaffs_InvalidateWholeChunkCache(in);++	if (in->myDev->isYaffs2 && (in->parent != in->myDev->deletedDir)) {+		/* Move to the unlinked directory so we have a record that it was deleted. */+		yaffs_ChangeObjectName(in, in->myDev->deletedDir, _Y("deleted"), 0, 0);++	}++	yaffs_RemoveObjectFromDirectory(in);+	yaffs_DeleteChunk(in->myDev, in->hdrChunk, 1, __LINE__);+	in->hdrChunk = 0;++	yaffs_FreeObject(in);+	return YAFFS_OK;++}++/* yaffs_DeleteFile deletes the whole file data+ * and the inode associated with the file.+ * It does not delete the links associated with the file.+ */+static int yaffs_UnlinkFileIfNeeded(yaffs_Object *in)+{++	int retVal;+	int immediateDeletion = 0;++#ifdef __KERNEL__+	if (!in->myInode)+		immediateDeletion = 1;+#else+	if (in->inUse <= 0)+		immediateDeletion = 1;+#endif++	if (immediateDeletion) {+		retVal =+		    yaffs_ChangeObjectName(in, in->myDev->deletedDir,+					   _Y("deleted"), 0, 0);+		T(YAFFS_TRACE_TRACING,+		  (TSTR("yaffs: immediate deletion of file %d" TENDSTR),+		   in->objectId));+		in->deleted = 1;+		in->myDev->nDeletedFiles++;+		if (1 || in->myDev->isYaffs2)+			yaffs_ResizeFile(in, 0);+		yaffs_SoftDeleteFile(in);+	} else {+		retVal =+		    yaffs_ChangeObjectName(in, in->myDev->unlinkedDir,+					   _Y("unlinked"), 0, 0);+	}+++	return retVal;+}++int yaffs_DeleteFile(yaffs_Object *in)+{+	int retVal = YAFFS_OK;+	int deleted = in->deleted;++	yaffs_ResizeFile(in, 0);++	if (in->nDataChunks > 0) {+		/* Use soft deletion if there is data in the file.+		 * That won't be the case if it has been resized to zero.+		 */+		if (!in->unlinked)+			retVal = yaffs_UnlinkFileIfNeeded(in);++		if (retVal == YAFFS_OK && in->unlinked && !in->deleted) {+			in->deleted = 1;+			deleted = 1;+			in->myDev->nDeletedFiles++;+			yaffs_SoftDeleteFile(in);+		}+		return deleted ? YAFFS_OK : YAFFS_FAIL;+	} else {+		/* The file has no data chunks so we toss it immediately */+		yaffs_FreeTnode(in->myDev, in->variant.fileVariant.top);+		in->variant.fileVariant.top = NULL;+		yaffs_DoGenericObjectDeletion(in);++		return YAFFS_OK;+	}+}++static int yaffs_DeleteDirectory(yaffs_Object *in)+{+	/* First check that the directory is empty. */+	if (ylist_empty(&in->variant.directoryVariant.children))+		return yaffs_DoGenericObjectDeletion(in);++	return YAFFS_FAIL;++}++static int yaffs_DeleteSymLink(yaffs_Object *in)+{+	YFREE(in->variant.symLinkVariant.alias);++	return yaffs_DoGenericObjectDeletion(in);+}++static int yaffs_DeleteHardLink(yaffs_Object *in)+{+	/* remove this hardlink from the list assocaited with the equivalent+	 * object+	 */+	ylist_del_init(&in->hardLinks);+	return yaffs_DoGenericObjectDeletion(in);+}++int yaffs_DeleteObject(yaffs_Object *obj)+{+int retVal = -1;+	switch (obj->variantType) {+	case YAFFS_OBJECT_TYPE_FILE:+		retVal = yaffs_DeleteFile(obj);+		break;+	case YAFFS_OBJECT_TYPE_DIRECTORY:+		return yaffs_DeleteDirectory(obj);+		break;+	case YAFFS_OBJECT_TYPE_SYMLINK:+		retVal = yaffs_DeleteSymLink(obj);+		break;+	case YAFFS_OBJECT_TYPE_HARDLINK:+		retVal = yaffs_DeleteHardLink(obj);+		break;+	case YAFFS_OBJECT_TYPE_SPECIAL:+		retVal = yaffs_DoGenericObjectDeletion(obj);+		break;+	case YAFFS_OBJECT_TYPE_UNKNOWN:+		retVal = 0;+		break;		/* should not happen. */+	}++	return retVal;+}++static int yaffs_UnlinkWorker(yaffs_Object *obj)+{++	int immediateDeletion = 0;++#ifdef __KERNEL__+	if (!obj->myInode)+		immediateDeletion = 1;+#else+	if (obj->inUse <= 0)+		immediateDeletion = 1;+#endif++	if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) {+		return yaffs_DeleteHardLink(obj);+	} else if (!ylist_empty(&obj->hardLinks)) {+		/* Curve ball: We're unlinking an object that has a hardlink.+		 *+		 * This problem arises because we are not strictly following+		 * The Linux link/inode model.+		 *+		 * We can't really delete the object.+		 * Instead, we do the following:+		 * - Select a hardlink.+		 * - Unhook it from the hard links+		 * - Unhook it from its parent directory (so that the rename can work)+		 * - Rename the object to the hardlink's name.+		 * - Delete the hardlink+		 */++		yaffs_Object *hl;+		int retVal;+		YCHAR name[YAFFS_MAX_NAME_LENGTH + 1];++		hl = ylist_entry(obj->hardLinks.next, yaffs_Object, hardLinks);++		ylist_del_init(&hl->hardLinks);+		ylist_del_init(&hl->siblings);++		yaffs_GetObjectName(hl, name, YAFFS_MAX_NAME_LENGTH + 1);++		retVal = yaffs_ChangeObjectName(obj, hl->parent, name, 0, 0);++		if (retVal == YAFFS_OK)+			retVal = yaffs_DoGenericObjectDeletion(hl);++		return retVal;++	} else if (immediateDeletion) {+		switch (obj->variantType) {+		case YAFFS_OBJECT_TYPE_FILE:+			return yaffs_DeleteFile(obj);+			break;+		case YAFFS_OBJECT_TYPE_DIRECTORY:+			return yaffs_DeleteDirectory(obj);+			break;+		case YAFFS_OBJECT_TYPE_SYMLINK:+			return yaffs_DeleteSymLink(obj);+			break;+		case YAFFS_OBJECT_TYPE_SPECIAL:+			return yaffs_DoGenericObjectDeletion(obj);+			break;+		case YAFFS_OBJECT_TYPE_HARDLINK:+		case YAFFS_OBJECT_TYPE_UNKNOWN:+		default:+			return YAFFS_FAIL;+		}+	} else+		return yaffs_ChangeObjectName(obj, obj->myDev->unlinkedDir,+					   _Y("unlinked"), 0, 0);+}+++static int yaffs_UnlinkObject(yaffs_Object *obj)+{++	if (obj && obj->unlinkAllowed)+		return yaffs_UnlinkWorker(obj);++	return YAFFS_FAIL;++}+int yaffs_Unlink(yaffs_Object *dir, const YCHAR *name)+{+	yaffs_Object *obj;++	obj = yaffs_FindObjectByName(dir, name);+	return yaffs_UnlinkObject(obj);+}++/*----------------------- Initialisation Scanning ---------------------- */++static void yaffs_HandleShadowedObject(yaffs_Device *dev, int objId,+				int backwardScanning)+{+	yaffs_Object *obj;++	if (!backwardScanning) {+		/* Handle YAFFS1 forward scanning case+		 * For YAFFS1 we always do the deletion+		 */++	} else {+		/* Handle YAFFS2 case (backward scanning)+		 * If the shadowed object exists then ignore.+		 */+		if (yaffs_FindObjectByNumber(dev, objId))+			return;+	}++	/* Let's create it (if it does not exist) assuming it is a file so that it can do shrinking etc.+	 * We put it in unlinked dir to be cleaned up after the scanning+	 */+	obj =+	    yaffs_FindOrCreateObjectByNumber(dev, objId,+					     YAFFS_OBJECT_TYPE_FILE);+	if (!obj)+		return;+	yaffs_AddObjectToDirectory(dev->unlinkedDir, obj);+	obj->variant.fileVariant.shrinkSize = 0;+	obj->valid = 1;		/* So that we don't read any other info for this file */++}++typedef struct {+	int seq;+	int block;+} yaffs_BlockIndex;+++static void yaffs_HardlinkFixup(yaffs_Device *dev, yaffs_Object *hardList)+{+	yaffs_Object *hl;+	yaffs_Object *in;++	while (hardList) {+		hl = hardList;+		hardList = (yaffs_Object *) (hardList->hardLinks.next);++		in = yaffs_FindObjectByNumber(dev,+					      hl->variant.hardLinkVariant.+					      equivalentObjectId);++		if (in) {+			/* Add the hardlink pointers */+			hl->variant.hardLinkVariant.equivalentObject = in;+			ylist_add(&hl->hardLinks, &in->hardLinks);+		} else {+			/* Todo Need to report/handle this better.+			 * Got a problem... hardlink to a non-existant object+			 */+			hl->variant.hardLinkVariant.equivalentObject = NULL;+			YINIT_LIST_HEAD(&hl->hardLinks);++		}+	}+}++++++static int ybicmp(const void *a, const void *b)+{+	register int aseq = ((yaffs_BlockIndex *)a)->seq;+	register int bseq = ((yaffs_BlockIndex *)b)->seq;+	register int ablock = ((yaffs_BlockIndex *)a)->block;+	register int bblock = ((yaffs_BlockIndex *)b)->block;+	if (aseq == bseq)+		return ablock - bblock;+	else+		return aseq - bseq;+}+++struct yaffs_ShadowFixerStruct {+	int objectId;+	int shadowedId;+	struct yaffs_ShadowFixerStruct *next;+};+++static void yaffs_StripDeletedObjects(yaffs_Device *dev)+{+	/*+	*  Sort out state of unlinked and deleted objects after scanning.+	*/+	struct ylist_head *i;+	struct ylist_head *n;+	yaffs_Object *l;++	/* Soft delete all the unlinked files */+	ylist_for_each_safe(i, n,+		&dev->unlinkedDir->variant.directoryVariant.children) {+		if (i) {+			l = ylist_entry(i, yaffs_Object, siblings);+			yaffs_DeleteObject(l);+		}+	}++	ylist_for_each_safe(i, n,+		&dev->deletedDir->variant.directoryVariant.children) {+		if (i) {+			l = ylist_entry(i, yaffs_Object, siblings);+			yaffs_DeleteObject(l);+		}+	}++}++static int yaffs_Scan(yaffs_Device *dev)+{+	yaffs_ExtendedTags tags;+	int blk;+	int blockIterator;+	int startIterator;+	int endIterator;+	int result;++	int chunk;+	int c;+	int deleted;+	yaffs_BlockState state;+	yaffs_Object *hardList = NULL;+	yaffs_BlockInfo *bi;+	__u32 sequenceNumber;+	yaffs_ObjectHeader *oh;+	yaffs_Object *in;+	yaffs_Object *parent;++	int alloc_failed = 0;++	struct yaffs_ShadowFixerStruct *shadowFixerList = NULL;+++	__u8 *chunkData;++++	T(YAFFS_TRACE_SCAN,+	  (TSTR("yaffs_Scan starts  intstartblk %d intendblk %d..." TENDSTR),+	   dev->internalStartBlock, dev->internalEndBlock));++	chunkData = yaffs_GetTempBuffer(dev, __LINE__);++	dev->sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER;++	/* Scan all the blocks to determine their state */+	for (blk = dev->internalStartBlock; blk <= dev->internalEndBlock; blk++) {+		bi = yaffs_GetBlockInfo(dev, blk);+		yaffs_ClearChunkBits(dev, blk);+		bi->pagesInUse = 0;+		bi->softDeletions = 0;++		yaffs_QueryInitialBlockState(dev, blk, &state, &sequenceNumber);++		bi->blockState = state;+		bi->sequenceNumber = sequenceNumber;++		if (bi->sequenceNumber == YAFFS_SEQUENCE_BAD_BLOCK)+			bi->blockState = state = YAFFS_BLOCK_STATE_DEAD;++		T(YAFFS_TRACE_SCAN_DEBUG,+		  (TSTR("Block scanning block %d state %d seq %d" TENDSTR), blk,+		   state, sequenceNumber));++		if (state == YAFFS_BLOCK_STATE_DEAD) {+			T(YAFFS_TRACE_BAD_BLOCKS,+			  (TSTR("block %d is bad" TENDSTR), blk));+		} else if (state == YAFFS_BLOCK_STATE_EMPTY) {+			T(YAFFS_TRACE_SCAN_DEBUG,+			  (TSTR("Block empty " TENDSTR)));+			dev->nErasedBlocks++;+			dev->nFreeChunks += dev->nChunksPerBlock;+		}+	}++	startIterator = dev->internalStartBlock;+	endIterator = dev->internalEndBlock;++	/* For each block.... */+	for (blockIterator = startIterator; !alloc_failed && blockIterator <= endIterator;+	     blockIterator++) {++		YYIELD();++		YYIELD();++		blk = blockIterator;++		bi = yaffs_GetBlockInfo(dev, blk);+		state = bi->blockState;++		deleted = 0;++		/* For each chunk in each block that needs scanning....*/+		for (c = 0; !alloc_failed && c < dev->nChunksPerBlock &&+		     state == YAFFS_BLOCK_STATE_NEEDS_SCANNING; c++) {+			/* Read the tags and decide what to do */+			chunk = blk * dev->nChunksPerBlock + c;++			result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk, NULL,+							&tags);++			/* Let's have a good look at this chunk... */++			if (tags.eccResult == YAFFS_ECC_RESULT_UNFIXED || tags.chunkDeleted) {+				/* YAFFS1 only...+				 * A deleted chunk+				 */+				deleted++;+				dev->nFreeChunks++;+				/*T((" %d %d deleted\n",blk,c)); */+			} else if (!tags.chunkUsed) {+				/* An unassigned chunk in the block+				 * This means that either the block is empty or+				 * this is the one being allocated from+				 */++				if (c == 0) {+					/* We're looking at the first chunk in the block so the block is unused */+					state = YAFFS_BLOCK_STATE_EMPTY;+					dev->nErasedBlocks++;+				} else {+					/* this is the block being allocated from */+					T(YAFFS_TRACE_SCAN,+					  (TSTR+					   (" Allocating from %d %d" TENDSTR),+					   blk, c));+					state = YAFFS_BLOCK_STATE_ALLOCATING;+					dev->allocationBlock = blk;+					dev->allocationPage = c;+					dev->allocationBlockFinder = blk;+					/* Set it to here to encourage the allocator to go forth from here. */++				}++				dev->nFreeChunks += (dev->nChunksPerBlock - c);+			} else if (tags.chunkId > 0) {+				/* chunkId > 0 so it is a data chunk... */+				unsigned int endpos;++				yaffs_SetChunkBit(dev, blk, c);+				bi->pagesInUse++;++				in = yaffs_FindOrCreateObjectByNumber(dev,+								      tags.+								      objectId,+								      YAFFS_OBJECT_TYPE_FILE);+				/* PutChunkIntoFile checks for a clash (two data chunks with+				 * the same chunkId).+				 */++				if (!in)+					alloc_failed = 1;++				if (in) {+					if (!yaffs_PutChunkIntoFile(in, tags.chunkId, chunk, 1))+						alloc_failed = 1;+				}++				endpos =+				    (tags.chunkId - 1) * dev->nDataBytesPerChunk ++				    tags.byteCount;+				if (in &&+				    in->variantType == YAFFS_OBJECT_TYPE_FILE+				    && in->variant.fileVariant.scannedFileSize <+				    endpos) {+					in->variant.fileVariant.+					    scannedFileSize = endpos;+					if (!dev->useHeaderFileSize) {+						in->variant.fileVariant.+						    fileSize =+						    in->variant.fileVariant.+						    scannedFileSize;+					}++				}+				/* T((" %d %d data %d %d\n",blk,c,tags.objectId,tags.chunkId));   */+			} else {+				/* chunkId == 0, so it is an ObjectHeader.+				 * Thus, we read in the object header and make the object+				 */+				yaffs_SetChunkBit(dev, blk, c);+				bi->pagesInUse++;++				result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk,+								chunkData,+								NULL);++				oh = (yaffs_ObjectHeader *) chunkData;++				in = yaffs_FindObjectByNumber(dev,+							      tags.objectId);+				if (in && in->variantType != oh->type) {+					/* This should not happen, but somehow+					 * Wev'e ended up with an objectId that has been reused but not yet+					 * deleted, and worse still it has changed type. Delete the old object.+					 */++					yaffs_DeleteObject(in);++					in = 0;+				}++				in = yaffs_FindOrCreateObjectByNumber(dev,+								      tags.+								      objectId,+								      oh->type);++				if (!in)+					alloc_failed = 1;++				if (in && oh->shadowsObject > 0) {++					struct yaffs_ShadowFixerStruct *fixer;+					fixer = YMALLOC(sizeof(struct yaffs_ShadowFixerStruct));+					if (fixer) {+						fixer->next = shadowFixerList;+						shadowFixerList = fixer;+						fixer->objectId = tags.objectId;+						fixer->shadowedId = oh->shadowsObject;+					}++				}++				if (in && in->valid) {+					/* We have already filled this one. We have a duplicate and need to resolve it. */++					unsigned existingSerial = in->serial;+					unsigned newSerial = tags.serialNumber;++					if (((existingSerial + 1) & 3) == newSerial) {+						/* Use new one - destroy the exisiting one */+						yaffs_DeleteChunk(dev,+								  in->hdrChunk,+								  1, __LINE__);+						in->valid = 0;+					} else {+						/* Use existing - destroy this one. */+						yaffs_DeleteChunk(dev, chunk, 1,+								  __LINE__);+					}+				}++				if (in && !in->valid &&+				    (tags.objectId == YAFFS_OBJECTID_ROOT ||+				     tags.objectId == YAFFS_OBJECTID_LOSTNFOUND)) {+					/* We only load some info, don't fiddle with directory structure */+					in->valid = 1;+					in->variantType = oh->type;++					in->yst_mode = oh->yst_mode;+#ifdef CONFIG_YAFFS_WINCE+					in->win_atime[0] = oh->win_atime[0];+					in->win_ctime[0] = oh->win_ctime[0];+					in->win_mtime[0] = oh->win_mtime[0];+					in->win_atime[1] = oh->win_atime[1];+					in->win_ctime[1] = oh->win_ctime[1];+					in->win_mtime[1] = oh->win_mtime[1];+#else+					in->yst_uid = oh->yst_uid;+					in->yst_gid = oh->yst_gid;+					in->yst_atime = oh->yst_atime;+					in->yst_mtime = oh->yst_mtime;+					in->yst_ctime = oh->yst_ctime;+					in->yst_rdev = oh->yst_rdev;+#endif+					in->hdrChunk = chunk;+					in->serial = tags.serialNumber;++				} else if (in && !in->valid) {+					/* we need to load this info */++					in->valid = 1;+					in->variantType = oh->type;++					in->yst_mode = oh->yst_mode;+#ifdef CONFIG_YAFFS_WINCE+					in->win_atime[0] = oh->win_atime[0];+					in->win_ctime[0] = oh->win_ctime[0];+					in->win_mtime[0] = oh->win_mtime[0];+					in->win_atime[1] = oh->win_atime[1];+					in->win_ctime[1] = oh->win_ctime[1];+					in->win_mtime[1] = oh->win_mtime[1];+#else+					in->yst_uid = oh->yst_uid;+					in->yst_gid = oh->yst_gid;+					in->yst_atime = oh->yst_atime;+					in->yst_mtime = oh->yst_mtime;+					in->yst_ctime = oh->yst_ctime;+					in->yst_rdev = oh->yst_rdev;+#endif+					in->hdrChunk = chunk;+					in->serial = tags.serialNumber;++					yaffs_SetObjectName(in, oh->name);+					in->dirty = 0;++					/* directory stuff...+					 * hook up to parent+					 */++					parent =+					    yaffs_FindOrCreateObjectByNumber+					    (dev, oh->parentObjectId,+					     YAFFS_OBJECT_TYPE_DIRECTORY);+					if (!parent)+						alloc_failed = 1;+					if (parent && parent->variantType ==+					    YAFFS_OBJECT_TYPE_UNKNOWN) {+						/* Set up as a directory */+						parent->variantType =+							YAFFS_OBJECT_TYPE_DIRECTORY;+						YINIT_LIST_HEAD(&parent->variant.+								directoryVariant.+								children);+					} else if (!parent || parent->variantType !=+						   YAFFS_OBJECT_TYPE_DIRECTORY) {+						/* Hoosterman, another problem....+						 * We're trying to use a non-directory as a directory+						 */++						T(YAFFS_TRACE_ERROR,+						  (TSTR+						   ("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."+						    TENDSTR)));+						parent = dev->lostNFoundDir;+					}++					yaffs_AddObjectToDirectory(parent, in);++					if (0 && (parent == dev->deletedDir ||+						  parent == dev->unlinkedDir)) {+						in->deleted = 1;	/* If it is unlinked at start up then it wants deleting */+						dev->nDeletedFiles++;+					}+					/* Note re hardlinks.+					 * Since we might scan a hardlink before its equivalent object is scanned+					 * we put them all in a list.+					 * After scanning is complete, we should have all the objects, so we run through this+					 * list and fix up all the chains.+					 */++					switch (in->variantType) {+					case YAFFS_OBJECT_TYPE_UNKNOWN:+						/* Todo got a problem */+						break;+					case YAFFS_OBJECT_TYPE_FILE:+						if (dev->useHeaderFileSize)++							in->variant.fileVariant.+							    fileSize =+							    oh->fileSize;++						break;+					case YAFFS_OBJECT_TYPE_HARDLINK:+						in->variant.hardLinkVariant.+							equivalentObjectId =+							oh->equivalentObjectId;+						in->hardLinks.next =+							(struct ylist_head *)+							hardList;+						hardList = in;+						break;+					case YAFFS_OBJECT_TYPE_DIRECTORY:+						/* Do nothing */+						break;+					case YAFFS_OBJECT_TYPE_SPECIAL:+						/* Do nothing */+						break;+					case YAFFS_OBJECT_TYPE_SYMLINK:+						in->variant.symLinkVariant.alias =+						    yaffs_CloneString(oh->alias);+						if (!in->variant.symLinkVariant.alias)+							alloc_failed = 1;+						break;+					}++/*+					if (parent == dev->deletedDir) {+						yaffs_DestroyObject(in);+						bi->hasShrinkHeader = 1;+					}+*/+				}+			}+		}++		if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {+			/* If we got this far while scanning, then the block is fully allocated.*/+			state = YAFFS_BLOCK_STATE_FULL;+		}++		bi->blockState = state;++		/* Now let's see if it was dirty */+		if (bi->pagesInUse == 0 &&+		    !bi->hasShrinkHeader &&+		    bi->blockState == YAFFS_BLOCK_STATE_FULL) {+			yaffs_BlockBecameDirty(dev, blk);+		}++	}+++	/* Ok, we've done all the scanning.+	 * Fix up the hard link chains.+	 * We should now have scanned all the objects, now it's time to add these+	 * hardlinks.+	 */++	yaffs_HardlinkFixup(dev, hardList);++	/* Fix up any shadowed objects */+	{+		struct yaffs_ShadowFixerStruct *fixer;+		yaffs_Object *obj;++		while (shadowFixerList) {+			fixer = shadowFixerList;+			shadowFixerList = fixer->next;+			/* Complete the rename transaction by deleting the shadowed object+			 * then setting the object header to unshadowed.+			 */+			obj = yaffs_FindObjectByNumber(dev, fixer->shadowedId);+			if (obj)+				yaffs_DeleteObject(obj);++			obj = yaffs_FindObjectByNumber(dev, fixer->objectId);++			if (obj)+				yaffs_UpdateObjectHeader(obj, NULL, 1, 0, 0);++			YFREE(fixer);+		}+	}++	yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__);++	if (alloc_failed)+		return YAFFS_FAIL;++	T(YAFFS_TRACE_SCAN, (TSTR("yaffs_Scan ends" TENDSTR)));+++	return YAFFS_OK;+}++static void yaffs_CheckObjectDetailsLoaded(yaffs_Object *in)+{+	__u8 *chunkData;+	yaffs_ObjectHeader *oh;+	yaffs_Device *dev;+	yaffs_ExtendedTags tags;+	int result;+	int alloc_failed = 0;++	if (!in)+		return;++	dev = in->myDev;++#if 0+	T(YAFFS_TRACE_SCAN, (TSTR("details for object %d %s loaded" TENDSTR),+		in->objectId,+		in->lazyLoaded ? "not yet" : "already"));+#endif++	if (in->lazyLoaded && in->hdrChunk > 0) {+		in->lazyLoaded = 0;+		chunkData = yaffs_GetTempBuffer(dev, __LINE__);++		result = yaffs_ReadChunkWithTagsFromNAND(dev, in->hdrChunk, chunkData, &tags);+		oh = (yaffs_ObjectHeader *) chunkData;++		in->yst_mode = oh->yst_mode;+#ifdef CONFIG_YAFFS_WINCE+		in->win_atime[0] = oh->win_atime[0];+		in->win_ctime[0] = oh->win_ctime[0];+		in->win_mtime[0] = oh->win_mtime[0];+		in->win_atime[1] = oh->win_atime[1];+		in->win_ctime[1] = oh->win_ctime[1];+		in->win_mtime[1] = oh->win_mtime[1];+#else+		in->yst_uid = oh->yst_uid;+		in->yst_gid = oh->yst_gid;+		in->yst_atime = oh->yst_atime;+		in->yst_mtime = oh->yst_mtime;+		in->yst_ctime = oh->yst_ctime;+		in->yst_rdev = oh->yst_rdev;++#endif+		yaffs_SetObjectName(in, oh->name);++		if (in->variantType == YAFFS_OBJECT_TYPE_SYMLINK) {+			in->variant.symLinkVariant.alias =+						    yaffs_CloneString(oh->alias);+			if (!in->variant.symLinkVariant.alias)+				alloc_failed = 1; /* Not returned to caller */+		}++		yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__);+	}+}++static int yaffs_ScanBackwards(yaffs_Device *dev)+{+	yaffs_ExtendedTags tags;+	int blk;+	int blockIterator;+	int startIterator;+	int endIterator;+	int nBlocksToScan = 0;++	int chunk;+	int result;+	int c;+	int deleted;+	yaffs_BlockState state;+	yaffs_Object *hardList = NULL;+	yaffs_BlockInfo *bi;+	__u32 sequenceNumber;+	yaffs_ObjectHeader *oh;+	yaffs_Object *in;+	yaffs_Object *parent;+	int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1;+	int itsUnlinked;+	__u8 *chunkData;++	int fileSize;+	int isShrink;+	int foundChunksInBlock;+	int equivalentObjectId;+	int alloc_failed = 0;+++	yaffs_BlockIndex *blockIndex = NULL;+	int altBlockIndex = 0;++	if (!dev->isYaffs2) {+		T(YAFFS_TRACE_SCAN,+		  (TSTR("yaffs_ScanBackwards is only for YAFFS2!" TENDSTR)));+		return YAFFS_FAIL;+	}++	T(YAFFS_TRACE_SCAN,+	  (TSTR+	   ("yaffs_ScanBackwards starts  intstartblk %d intendblk %d..."+	    TENDSTR), dev->internalStartBlock, dev->internalEndBlock));+++	dev->sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER;++	blockIndex = YMALLOC(nBlocks * sizeof(yaffs_BlockIndex));++	if (!blockIndex) {+		blockIndex = YMALLOC_ALT(nBlocks * sizeof(yaffs_BlockIndex));+		altBlockIndex = 1;+	}++	if (!blockIndex) {+		T(YAFFS_TRACE_SCAN,+		  (TSTR("yaffs_Scan() could not allocate block index!" TENDSTR)));+		return YAFFS_FAIL;+	}++	dev->blocksInCheckpoint = 0;++	chunkData = yaffs_GetTempBuffer(dev, __LINE__);++	/* Scan all the blocks to determine their state */+	for (blk = dev->internalStartBlock; blk <= dev->internalEndBlock; blk++) {+		bi = yaffs_GetBlockInfo(dev, blk);+		yaffs_ClearChunkBits(dev, blk);+		bi->pagesInUse = 0;+		bi->softDeletions = 0;++		yaffs_QueryInitialBlockState(dev, blk, &state, &sequenceNumber);++		bi->blockState = state;+		bi->sequenceNumber = sequenceNumber;++		if (bi->sequenceNumber == YAFFS_SEQUENCE_CHECKPOINT_DATA)+			bi->blockState = state = YAFFS_BLOCK_STATE_CHECKPOINT;+		if (bi->sequenceNumber == YAFFS_SEQUENCE_BAD_BLOCK)+			bi->blockState = state = YAFFS_BLOCK_STATE_DEAD;++		T(YAFFS_TRACE_SCAN_DEBUG,+		  (TSTR("Block scanning block %d state %d seq %d" TENDSTR), blk,+		   state, sequenceNumber));+++		if (state == YAFFS_BLOCK_STATE_CHECKPOINT) {+			dev->blocksInCheckpoint++;++		} else if (state == YAFFS_BLOCK_STATE_DEAD) {+			T(YAFFS_TRACE_BAD_BLOCKS,+			  (TSTR("block %d is bad" TENDSTR), blk));+		} else if (state == YAFFS_BLOCK_STATE_EMPTY) {+			T(YAFFS_TRACE_SCAN_DEBUG,+			  (TSTR("Block empty " TENDSTR)));+			dev->nErasedBlocks++;+			dev->nFreeChunks += dev->nChunksPerBlock;+		} else if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {++			/* Determine the highest sequence number */+			if (sequenceNumber >= YAFFS_LOWEST_SEQUENCE_NUMBER &&+			    sequenceNumber < YAFFS_HIGHEST_SEQUENCE_NUMBER) {++				blockIndex[nBlocksToScan].seq = sequenceNumber;+				blockIndex[nBlocksToScan].block = blk;++				nBlocksToScan++;++				if (sequenceNumber >= dev->sequenceNumber)+					dev->sequenceNumber = sequenceNumber;+			} else {+				/* TODO: Nasty sequence number! */+				T(YAFFS_TRACE_SCAN,+				  (TSTR+				   ("Block scanning block %d has bad sequence number %d"+				    TENDSTR), blk, sequenceNumber));++			}+		}+	}++	T(YAFFS_TRACE_SCAN,+	(TSTR("%d blocks to be sorted..." TENDSTR), nBlocksToScan));++++	YYIELD();++	/* Sort the blocks */+#ifndef CONFIG_YAFFS_USE_OWN_SORT+	{+		/* Use qsort now. */+		yaffs_qsort(blockIndex, nBlocksToScan, sizeof(yaffs_BlockIndex), ybicmp);+	}+#else+	{+		/* Dungy old bubble sort... */++		yaffs_BlockIndex temp;+		int i;+		int j;++		for (i = 0; i < nBlocksToScan; i++)+			for (j = i + 1; j < nBlocksToScan; j++)+				if (blockIndex[i].seq > blockIndex[j].seq) {+					temp = blockIndex[j];+					blockIndex[j] = blockIndex[i];+					blockIndex[i] = temp;+				}+	}+#endif++	YYIELD();++	T(YAFFS_TRACE_SCAN, (TSTR("...done" TENDSTR)));++	/* Now scan the blocks looking at the data. */+	startIterator = 0;+	endIterator = nBlocksToScan - 1;+	T(YAFFS_TRACE_SCAN_DEBUG,+	  (TSTR("%d blocks to be scanned" TENDSTR), nBlocksToScan));++	/* For each block.... backwards */+	for (blockIterator = endIterator; !alloc_failed && blockIterator >= startIterator;+			blockIterator--) {+		/* Cooperative multitasking! This loop can run for so+		   long that watchdog timers expire. */+		YYIELD();++		/* get the block to scan in the correct order */+		blk = blockIndex[blockIterator].block;++		bi = yaffs_GetBlockInfo(dev, blk);+++		state = bi->blockState;++		deleted = 0;++		/* For each chunk in each block that needs scanning.... */+		foundChunksInBlock = 0;+		for (c = dev->nChunksPerBlock - 1;+		     !alloc_failed && c >= 0 &&+		     (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||+		      state == YAFFS_BLOCK_STATE_ALLOCATING); c--) {+			/* Scan backwards...+			 * Read the tags and decide what to do+			 */++			chunk = blk * dev->nChunksPerBlock + c;++			result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk, NULL,+							&tags);++			/* Let's have a good look at this chunk... */++			if (!tags.chunkUsed) {+				/* An unassigned chunk in the block.+				 * If there are used chunks after this one, then+				 * it is a chunk that was skipped due to failing the erased+				 * check. Just skip it so that it can be deleted.+				 * But, more typically, We get here when this is an unallocated+				 * chunk and his means that either the block is empty or+				 * this is the one being allocated from+				 */++				if (foundChunksInBlock) {+					/* This is a chunk that was skipped due to failing the erased check */+				} else if (c == 0) {+					/* We're looking at the first chunk in the block so the block is unused */+					state = YAFFS_BLOCK_STATE_EMPTY;+					dev->nErasedBlocks++;+				} else {+					if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||+					    state == YAFFS_BLOCK_STATE_ALLOCATING) {+						if (dev->sequenceNumber == bi->sequenceNumber) {+							/* this is the block being allocated from */++							T(YAFFS_TRACE_SCAN,+							  (TSTR+							   (" Allocating from %d %d"+							    TENDSTR), blk, c));++							state = YAFFS_BLOCK_STATE_ALLOCATING;+							dev->allocationBlock = blk;+							dev->allocationPage = c;+							dev->allocationBlockFinder = blk;+						} else {+							/* This is a partially written block that is not+							 * the current allocation block. This block must have+							 * had a write failure, so set up for retirement.+							 */++							 /* bi->needsRetiring = 1; ??? TODO */+							 bi->gcPrioritise = 1;++							 T(YAFFS_TRACE_ALWAYS,+							 (TSTR("Partially written block %d detected" TENDSTR),+							 blk));+						}+					}+				}++				dev->nFreeChunks++;++			} else if (tags.eccResult == YAFFS_ECC_RESULT_UNFIXED) {+				T(YAFFS_TRACE_SCAN,+				  (TSTR(" Unfixed ECC in chunk(%d:%d), chunk ignored"TENDSTR),+				  blk, c));++				  dev->nFreeChunks++;++			} else if (tags.chunkId > 0) {+				/* chunkId > 0 so it is a data chunk... */+				unsigned int endpos;+				__u32 chunkBase =+				    (tags.chunkId - 1) * dev->nDataBytesPerChunk;++				foundChunksInBlock = 1;+++				yaffs_SetChunkBit(dev, blk, c);+				bi->pagesInUse++;++				in = yaffs_FindOrCreateObjectByNumber(dev,+								      tags.+								      objectId,+								      YAFFS_OBJECT_TYPE_FILE);+				if (!in) {+					/* Out of memory */+					alloc_failed = 1;+				}++				if (in &&+				    in->variantType == YAFFS_OBJECT_TYPE_FILE+				    && chunkBase <+				    in->variant.fileVariant.shrinkSize) {+					/* This has not been invalidated by a resize */+					if (!yaffs_PutChunkIntoFile(in, tags.chunkId,+							       chunk, -1)) {+						alloc_failed = 1;+					}++					/* File size is calculated by looking at the data chunks if we have not+					 * seen an object header yet. Stop this practice once we find an object header.+					 */+					endpos =+					    (tags.chunkId -+					     1) * dev->nDataBytesPerChunk ++					    tags.byteCount;++					if (!in->valid &&	/* have not got an object header yet */+					    in->variant.fileVariant.+					    scannedFileSize < endpos) {+						in->variant.fileVariant.+						    scannedFileSize = endpos;+						in->variant.fileVariant.+						    fileSize =+						    in->variant.fileVariant.+						    scannedFileSize;+					}++				} else if (in) {+					/* This chunk has been invalidated by a resize, so delete */+					yaffs_DeleteChunk(dev, chunk, 1, __LINE__);++				}+			} else {+				/* chunkId == 0, so it is an ObjectHeader.+				 * Thus, we read in the object header and make the object+				 */+				foundChunksInBlock = 1;++				yaffs_SetChunkBit(dev, blk, c);+				bi->pagesInUse++;++				oh = NULL;+				in = NULL;++				if (tags.extraHeaderInfoAvailable) {+					in = yaffs_FindOrCreateObjectByNumber+					    (dev, tags.objectId,+					     tags.extraObjectType);+					if (!in)+						alloc_failed = 1;+				}++				if (!in ||+#ifdef CONFIG_YAFFS_DISABLE_LAZY_LOAD+				    !in->valid ||+#endif+				    tags.extraShadows ||+				    (!in->valid &&+				    (tags.objectId == YAFFS_OBJECTID_ROOT ||+				     tags.objectId == YAFFS_OBJECTID_LOSTNFOUND))) {++					/* If we don't have  valid info then we need to read the chunk+					 * TODO In future we can probably defer reading the chunk and+					 * living with invalid data until needed.+					 */++					result = yaffs_ReadChunkWithTagsFromNAND(dev,+									chunk,+									chunkData,+									NULL);++					oh = (yaffs_ObjectHeader *) chunkData;++					if (dev->inbandTags) {+						/* Fix up the header if they got corrupted by inband tags */+						oh->shadowsObject = oh->inbandShadowsObject;+						oh->isShrink = oh->inbandIsShrink;+					}++					if (!in) {+						in = yaffs_FindOrCreateObjectByNumber(dev, tags.objectId, oh->type);+						if (!in)+							alloc_failed = 1;+					}++				}++				if (!in) {+					/* TODO Hoosterman we have a problem! */+					T(YAFFS_TRACE_ERROR,+					  (TSTR+					   ("yaffs tragedy: Could not make object for object  %d at chunk %d during scan"+					    TENDSTR), tags.objectId, chunk));+					continue;+				}++				if (in->valid) {+					/* We have already filled this one.+					 * We have a duplicate that will be discarded, but+					 * we first have to suck out resize info if it is a file.+					 */++					if ((in->variantType == YAFFS_OBJECT_TYPE_FILE) &&+					     ((oh &&+					       oh->type == YAFFS_OBJECT_TYPE_FILE) ||+					      (tags.extraHeaderInfoAvailable  &&+					       tags.extraObjectType == YAFFS_OBJECT_TYPE_FILE))) {+						__u32 thisSize =+						    (oh) ? oh->fileSize : tags.+						    extraFileLength;+						__u32 parentObjectId =+						    (oh) ? oh->+						    parentObjectId : tags.+						    extraParentObjectId;+++						isShrink =+						    (oh) ? oh->isShrink : tags.+						    extraIsShrinkHeader;++						/* If it is deleted (unlinked at start also means deleted)+						 * we treat the file size as being zeroed at this point.+						 */+						if (parentObjectId ==+						    YAFFS_OBJECTID_DELETED+						    || parentObjectId ==+						    YAFFS_OBJECTID_UNLINKED) {+							thisSize = 0;+							isShrink = 1;+						}++						if (isShrink &&+						    in->variant.fileVariant.+						    shrinkSize > thisSize) {+							in->variant.fileVariant.+							    shrinkSize =+							    thisSize;+						}++						if (isShrink)+							bi->hasShrinkHeader = 1;++					}+					/* Use existing - destroy this one. */+					yaffs_DeleteChunk(dev, chunk, 1, __LINE__);++				}++				if (!in->valid && in->variantType !=+				    (oh ? oh->type : tags.extraObjectType))+					T(YAFFS_TRACE_ERROR, (+						TSTR("yaffs tragedy: Bad object type, "+					    TCONT("%d != %d, for object %d at chunk ")+					    TCONT("%d during scan")+						TENDSTR), oh ?+					    oh->type : tags.extraObjectType,+					    in->variantType, tags.objectId,+					    chunk));++				if (!in->valid &&+				    (tags.objectId == YAFFS_OBJECTID_ROOT ||+				     tags.objectId ==+				     YAFFS_OBJECTID_LOSTNFOUND)) {+					/* We only load some info, don't fiddle with directory structure */+					in->valid = 1;++					if (oh) {+						in->variantType = oh->type;++						in->yst_mode = oh->yst_mode;+#ifdef CONFIG_YAFFS_WINCE+						in->win_atime[0] = oh->win_atime[0];+						in->win_ctime[0] = oh->win_ctime[0];+						in->win_mtime[0] = oh->win_mtime[0];+						in->win_atime[1] = oh->win_atime[1];+						in->win_ctime[1] = oh->win_ctime[1];+						in->win_mtime[1] = oh->win_mtime[1];+#else+						in->yst_uid = oh->yst_uid;+						in->yst_gid = oh->yst_gid;+						in->yst_atime = oh->yst_atime;+						in->yst_mtime = oh->yst_mtime;+						in->yst_ctime = oh->yst_ctime;+						in->yst_rdev = oh->yst_rdev;++#endif+					} else {+						in->variantType = tags.extraObjectType;+						in->lazyLoaded = 1;+					}++					in->hdrChunk = chunk;++				} else if (!in->valid) {+					/* we need to load this info */++					in->valid = 1;+					in->hdrChunk = chunk;++					if (oh) {+						in->variantType = oh->type;++						in->yst_mode = oh->yst_mode;+#ifdef CONFIG_YAFFS_WINCE+						in->win_atime[0] = oh->win_atime[0];+						in->win_ctime[0] = oh->win_ctime[0];+						in->win_mtime[0] = oh->win_mtime[0];+						in->win_atime[1] = oh->win_atime[1];+						in->win_ctime[1] = oh->win_ctime[1];+						in->win_mtime[1] = oh->win_mtime[1];+#else+						in->yst_uid = oh->yst_uid;+						in->yst_gid = oh->yst_gid;+						in->yst_atime = oh->yst_atime;+						in->yst_mtime = oh->yst_mtime;+						in->yst_ctime = oh->yst_ctime;+						in->yst_rdev = oh->yst_rdev;+#endif++						if (oh->shadowsObject > 0)+							yaffs_HandleShadowedObject(dev,+									   oh->+									   shadowsObject,+									   1);+++						yaffs_SetObjectName(in, oh->name);+						parent =+						    yaffs_FindOrCreateObjectByNumber+							(dev, oh->parentObjectId,+							 YAFFS_OBJECT_TYPE_DIRECTORY);++						 fileSize = oh->fileSize;+						 isShrink = oh->isShrink;+						 equivalentObjectId = oh->equivalentObjectId;++					} else {+						in->variantType = tags.extraObjectType;+						parent =+						    yaffs_FindOrCreateObjectByNumber+							(dev, tags.extraParentObjectId,+							 YAFFS_OBJECT_TYPE_DIRECTORY);+						 fileSize = tags.extraFileLength;+						 isShrink = tags.extraIsShrinkHeader;+						 equivalentObjectId = tags.extraEquivalentObjectId;+						in->lazyLoaded = 1;++					}+					in->dirty = 0;++					if (!parent)+						alloc_failed = 1;++					/* directory stuff...+					 * hook up to parent+					 */++					if (parent && parent->variantType ==+					    YAFFS_OBJECT_TYPE_UNKNOWN) {+						/* Set up as a directory */+						parent->variantType =+							YAFFS_OBJECT_TYPE_DIRECTORY;+						YINIT_LIST_HEAD(&parent->variant.+							directoryVariant.+							children);+					} else if (!parent || parent->variantType !=+						   YAFFS_OBJECT_TYPE_DIRECTORY) {+						/* Hoosterman, another problem....+						 * We're trying to use a non-directory as a directory+						 */++						T(YAFFS_TRACE_ERROR,+						  (TSTR+						   ("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."+						    TENDSTR)));+						parent = dev->lostNFoundDir;+					}++					yaffs_AddObjectToDirectory(parent, in);++					itsUnlinked = (parent == dev->deletedDir) ||+						      (parent == dev->unlinkedDir);++					if (isShrink) {+						/* Mark the block as having a shrinkHeader */+						bi->hasShrinkHeader = 1;+					}++					/* Note re hardlinks.+					 * Since we might scan a hardlink before its equivalent object is scanned+					 * we put them all in a list.+					 * After scanning is complete, we should have all the objects, so we run+					 * through this list and fix up all the chains.+					 */++					switch (in->variantType) {+					case YAFFS_OBJECT_TYPE_UNKNOWN:+						/* Todo got a problem */+						break;+					case YAFFS_OBJECT_TYPE_FILE:++						if (in->variant.fileVariant.+						    scannedFileSize < fileSize) {+							/* This covers the case where the file size is greater+							 * than where the data is+							 * This will happen if the file is resized to be larger+							 * than its current data extents.+							 */+							in->variant.fileVariant.fileSize = fileSize;+							in->variant.fileVariant.scannedFileSize =+							    in->variant.fileVariant.fileSize;+						}++						if (isShrink &&+						    in->variant.fileVariant.shrinkSize > fileSize) {+							in->variant.fileVariant.shrinkSize = fileSize;+						}++						break;+					case YAFFS_OBJECT_TYPE_HARDLINK:+						if (!itsUnlinked) {+							in->variant.hardLinkVariant.equivalentObjectId =+								equivalentObjectId;+							in->hardLinks.next =+								(struct ylist_head *) hardList;+							hardList = in;+						}+						break;+					case YAFFS_OBJECT_TYPE_DIRECTORY:+						/* Do nothing */+						break;+					case YAFFS_OBJECT_TYPE_SPECIAL:+						/* Do nothing */+						break;+					case YAFFS_OBJECT_TYPE_SYMLINK:+						if (oh) {+							in->variant.symLinkVariant.alias =+								yaffs_CloneString(oh->alias);+							if (!in->variant.symLinkVariant.alias)+								alloc_failed = 1;+						}+						break;+					}++				}++			}++		} /* End of scanning for each chunk */++		if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {+			/* If we got this far while scanning, then the block is fully allocated. */+			state = YAFFS_BLOCK_STATE_FULL;+		}++		bi->blockState = state;++		/* Now let's see if it was dirty */+		if (bi->pagesInUse == 0 &&+		    !bi->hasShrinkHeader &&+		    bi->blockState == YAFFS_BLOCK_STATE_FULL) {+			yaffs_BlockBecameDirty(dev, blk);+		}++	}++	if (altBlockIndex)+		YFREE_ALT(blockIndex);+	else+		YFREE(blockIndex);++	/* Ok, we've done all the scanning.+	 * Fix up the hard link chains.+	 * We should now have scanned all the objects, now it's time to add these+	 * hardlinks.+	 */+	yaffs_HardlinkFixup(dev, hardList);+++	yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__);++	if (alloc_failed)+		return YAFFS_FAIL;++	T(YAFFS_TRACE_SCAN, (TSTR("yaffs_ScanBackwards ends" TENDSTR)));++	return YAFFS_OK;+}++/*------------------------------  Directory Functions ----------------------------- */++static void yaffs_VerifyObjectInDirectory(yaffs_Object *obj)+{+	struct ylist_head *lh;+	yaffs_Object *listObj;++	int count = 0;++	if (!obj) {+		T(YAFFS_TRACE_ALWAYS, (TSTR("No object to verify" TENDSTR)));+		YBUG();+		return;+	}++	if (yaffs_SkipVerification(obj->myDev))+		return;++	if (!obj->parent) {+		T(YAFFS_TRACE_ALWAYS, (TSTR("Object does not have parent" TENDSTR)));+		YBUG();+		return;+	}++	if (obj->parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {+		T(YAFFS_TRACE_ALWAYS, (TSTR("Parent is not directory" TENDSTR)));+		YBUG();+	}++	/* Iterate through the objects in each hash entry */++	ylist_for_each(lh, &obj->parent->variant.directoryVariant.children) {+		if (lh) {+			listObj = ylist_entry(lh, yaffs_Object, siblings);+			yaffs_VerifyObject(listObj);+			if (obj == listObj)+				count++;+		}+	 }++	if (count != 1) {+		T(YAFFS_TRACE_ALWAYS, (TSTR("Object in directory %d times" TENDSTR), count));+		YBUG();+	}+}++static void yaffs_VerifyDirectory(yaffs_Object *directory)+{+	struct ylist_head *lh;+	yaffs_Object *listObj;++	if (!directory) {+		YBUG();+		return;+	}++	if (yaffs_SkipFullVerification(directory->myDev))+		return;++	if (directory->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {+		T(YAFFS_TRACE_ALWAYS, (TSTR("Directory has wrong type: %d" TENDSTR), directory->variantType));+		YBUG();+	}++	/* Iterate through the objects in each hash entry */++	ylist_for_each(lh, &directory->variant.directoryVariant.children) {+		if (lh) {+			listObj = ylist_entry(lh, yaffs_Object, siblings);+			if (listObj->parent != directory) {+				T(YAFFS_TRACE_ALWAYS, (TSTR("Object in directory list has wrong parent %p" TENDSTR), listObj->parent));+				YBUG();+			}+			yaffs_VerifyObjectInDirectory(listObj);+		}+	}+}+++static void yaffs_RemoveObjectFromDirectory(yaffs_Object *obj)+{+	yaffs_Device *dev = obj->myDev;+	yaffs_Object *parent;++	yaffs_VerifyObjectInDirectory(obj);+	parent = obj->parent;++	yaffs_VerifyDirectory(parent);++	if (dev && dev->removeObjectCallback)+		dev->removeObjectCallback(obj);+++	ylist_del_init(&obj->siblings);+	obj->parent = NULL;++	yaffs_VerifyDirectory(parent);+}+++static void yaffs_AddObjectToDirectory(yaffs_Object *directory,+					yaffs_Object *obj)+{+	if (!directory) {+		T(YAFFS_TRACE_ALWAYS,+		  (TSTR+		   ("tragedy: Trying to add an object to a null pointer directory"+		    TENDSTR)));+		YBUG();+		return;+	}+	if (directory->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {+		T(YAFFS_TRACE_ALWAYS,+		  (TSTR+		   ("tragedy: Trying to add an object to a non-directory"+		    TENDSTR)));+		YBUG();+	}++	if (obj->siblings.prev == NULL) {+		/* Not initialised */+		YBUG();+	}+++	yaffs_VerifyDirectory(directory);++	yaffs_RemoveObjectFromDirectory(obj);+++	/* Now add it */+	ylist_add(&obj->siblings, &directory->variant.directoryVariant.children);+	obj->parent = directory;++	if (directory == obj->myDev->unlinkedDir+			|| directory == obj->myDev->deletedDir) {+		obj->unlinked = 1;+		obj->myDev->nUnlinkedFiles++;+		obj->renameAllowed = 0;+	}++	yaffs_VerifyDirectory(directory);+	yaffs_VerifyObjectInDirectory(obj);+}++yaffs_Object *yaffs_FindObjectByName(yaffs_Object *directory,+				     const YCHAR *name)+{+	int sum;++	struct ylist_head *i;+	YCHAR buffer[YAFFS_MAX_NAME_LENGTH + 1];++	yaffs_Object *l;++	if (!name)+		return NULL;++	if (!directory) {+		T(YAFFS_TRACE_ALWAYS,+		  (TSTR+		   ("tragedy: yaffs_FindObjectByName: null pointer directory"+		    TENDSTR)));+		YBUG();+		return NULL;+	}+	if (directory->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {+		T(YAFFS_TRACE_ALWAYS,+		  (TSTR+		   ("tragedy: yaffs_FindObjectByName: non-directory" TENDSTR)));+		YBUG();+	}++	sum = yaffs_CalcNameSum(name);++	ylist_for_each(i, &directory->variant.directoryVariant.children) {+		if (i) {+			l = ylist_entry(i, yaffs_Object, siblings);++			if (l->parent != directory)+				YBUG();++			yaffs_CheckObjectDetailsLoaded(l);++			/* Special case for lost-n-found */+			if (l->objectId == YAFFS_OBJECTID_LOSTNFOUND) {+				if (yaffs_strcmp(name, YAFFS_LOSTNFOUND_NAME) == 0)+					return l;+			} else if (yaffs_SumCompare(l->sum, sum) || l->hdrChunk <= 0) {+				/* LostnFound chunk called Objxxx+				 * Do a real check+				 */+				yaffs_GetObjectName(l, buffer,+						    YAFFS_MAX_NAME_LENGTH);+				if (yaffs_strncmp(name, buffer, YAFFS_MAX_NAME_LENGTH) == 0)+					return l;+			}+		}+	}++	return NULL;+}+++#if 0+int yaffs_ApplyToDirectoryChildren(yaffs_Object *theDir,+					int (*fn) (yaffs_Object *))+{+	struct ylist_head *i;+	yaffs_Object *l;++	if (!theDir) {+		T(YAFFS_TRACE_ALWAYS,+		  (TSTR+		   ("tragedy: yaffs_FindObjectByName: null pointer directory"+		    TENDSTR)));+		YBUG();+		return YAFFS_FAIL;+	}+	if (theDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {+		T(YAFFS_TRACE_ALWAYS,+		  (TSTR+		   ("tragedy: yaffs_FindObjectByName: non-directory" TENDSTR)));+		YBUG();+		return YAFFS_FAIL;+	}++	ylist_for_each(i, &theDir->variant.directoryVariant.children) {+		if (i) {+			l = ylist_entry(i, yaffs_Object, siblings);+			if (l && !fn(l))+				return YAFFS_FAIL;+		}+	}++	return YAFFS_OK;++}+#endif++/* GetEquivalentObject dereferences any hard links to get to the+ * actual object.+ */++yaffs_Object *yaffs_GetEquivalentObject(yaffs_Object *obj)+{+	if (obj && obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) {+		/* We want the object id of the equivalent object, not this one */+		obj = obj->variant.hardLinkVariant.equivalentObject;+		yaffs_CheckObjectDetailsLoaded(obj);+	}+	return obj;+}++int yaffs_GetObjectName(yaffs_Object *obj, YCHAR *name, int buffSize)+{+	memset(name, 0, buffSize * sizeof(YCHAR));++	yaffs_CheckObjectDetailsLoaded(obj);++	if (obj->objectId == YAFFS_OBJECTID_LOSTNFOUND) {+		yaffs_strncpy(name, YAFFS_LOSTNFOUND_NAME, buffSize - 1);+	} else if (obj->hdrChunk <= 0) {+		YCHAR locName[20];+		YCHAR numString[20];+		YCHAR *x = &numString[19];+		unsigned v = obj->objectId;+		numString[19] = 0;+		while (v > 0) {+			x--;+			*x = '0' + (v % 10);+			v /= 10;+		}+		/* make up a name */+		yaffs_strcpy(locName, YAFFS_LOSTNFOUND_PREFIX);+		yaffs_strcat(locName, x);+		yaffs_strncpy(name, locName, buffSize - 1);++	}+#ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM+	else if (obj->shortName[0])+		yaffs_strcpy(name, obj->shortName);+#endif+	else {+		int result;+		__u8 *buffer = yaffs_GetTempBuffer(obj->myDev, __LINE__);++		yaffs_ObjectHeader *oh = (yaffs_ObjectHeader *) buffer;++		memset(buffer, 0, obj->myDev->nDataBytesPerChunk);++		if (obj->hdrChunk > 0) {+			result = yaffs_ReadChunkWithTagsFromNAND(obj->myDev,+							obj->hdrChunk, buffer,+							NULL);+		}+		yaffs_strncpy(name, oh->name, buffSize - 1);++		yaffs_ReleaseTempBuffer(obj->myDev, buffer, __LINE__);+	}++	return yaffs_strlen(name);+}++int yaffs_GetObjectFileLength(yaffs_Object *obj)+{+	/* Dereference any hard linking */+	obj = yaffs_GetEquivalentObject(obj);++	if (obj->variantType == YAFFS_OBJECT_TYPE_FILE)+		return obj->variant.fileVariant.fileSize;+	if (obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK)+		return yaffs_strlen(obj->variant.symLinkVariant.alias);+	else {+		/* Only a directory should drop through to here */+		return obj->myDev->nDataBytesPerChunk;+	}+}++int yaffs_GetObjectLinkCount(yaffs_Object *obj)+{+	int count = 0;+	struct ylist_head *i;++	if (!obj->unlinked)+		count++;		/* the object itself */++	ylist_for_each(i, &obj->hardLinks)+		count++;		/* add the hard links; */++	return count;+}++int yaffs_GetObjectInode(yaffs_Object *obj)+{+	obj = yaffs_GetEquivalentObject(obj);++	return obj->objectId;+}++unsigned yaffs_GetObjectType(yaffs_Object *obj)+{+	obj = yaffs_GetEquivalentObject(obj);++	switch (obj->variantType) {+	case YAFFS_OBJECT_TYPE_FILE:+		return DT_REG;+		break;+	case YAFFS_OBJECT_TYPE_DIRECTORY:+		return DT_DIR;+		break;+	case YAFFS_OBJECT_TYPE_SYMLINK:+		return DT_LNK;+		break;+	case YAFFS_OBJECT_TYPE_HARDLINK:+		return DT_REG;+		break;+	case YAFFS_OBJECT_TYPE_SPECIAL:+		if (S_ISFIFO(obj->yst_mode))+			return DT_FIFO;+		if (S_ISCHR(obj->yst_mode))+			return DT_CHR;+		if (S_ISBLK(obj->yst_mode))+			return DT_BLK;+		if (S_ISSOCK(obj->yst_mode))+			return DT_SOCK;+	default:+		return DT_REG;+		break;+	}+}++YCHAR *yaffs_GetSymlinkAlias(yaffs_Object *obj)+{+	obj = yaffs_GetEquivalentObject(obj);+	if (obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK)+		return yaffs_CloneString(obj->variant.symLinkVariant.alias);+	else+		return yaffs_CloneString(_Y(""));+}++#ifndef CONFIG_YAFFS_WINCE++int yaffs_SetAttributes(yaffs_Object *obj, struct iattr *attr)+{+	unsigned int valid = attr->ia_valid;++	if (valid & ATTR_MODE)+		obj->yst_mode = attr->ia_mode;+	if (valid & ATTR_UID)+		obj->yst_uid = attr->ia_uid;+	if (valid & ATTR_GID)+		obj->yst_gid = attr->ia_gid;++	if (valid & ATTR_ATIME)+		obj->yst_atime = Y_TIME_CONVERT(attr->ia_atime);+	if (valid & ATTR_CTIME)+		obj->yst_ctime = Y_TIME_CONVERT(attr->ia_ctime);+	if (valid & ATTR_MTIME)+		obj->yst_mtime = Y_TIME_CONVERT(attr->ia_mtime);++	if (valid & ATTR_SIZE)+		yaffs_ResizeFile(obj, attr->ia_size);++	yaffs_UpdateObjectHeader(obj, NULL, 1, 0, 0);++	return YAFFS_OK;++}+int yaffs_GetAttributes(yaffs_Object *obj, struct iattr *attr)+{+	unsigned int valid = 0;++	attr->ia_mode = obj->yst_mode;+	valid |= ATTR_MODE;+	attr->ia_uid = obj->yst_uid;+	valid |= ATTR_UID;+	attr->ia_gid = obj->yst_gid;+	valid |= ATTR_GID;++	Y_TIME_CONVERT(attr->ia_atime) = obj->yst_atime;+	valid |= ATTR_ATIME;+	Y_TIME_CONVERT(attr->ia_ctime) = obj->yst_ctime;+	valid |= ATTR_CTIME;+	Y_TIME_CONVERT(attr->ia_mtime) = obj->yst_mtime;+	valid |= ATTR_MTIME;++	attr->ia_size = yaffs_GetFileSize(obj);+	valid |= ATTR_SIZE;++	attr->ia_valid = valid;++	return YAFFS_OK;+}++#endif++#if 0+int yaffs_DumpObject(yaffs_Object *obj)+{+	YCHAR name[257];++	yaffs_GetObjectName(obj, name, 256);++	T(YAFFS_TRACE_ALWAYS,+	  (TSTR+	   ("Object %d, inode %d \"%s\"\n dirty %d valid %d serial %d sum %d"+	    " chunk %d type %d size %d\n"+	    TENDSTR), obj->objectId, yaffs_GetObjectInode(obj), name,+	   obj->dirty, obj->valid, obj->serial, obj->sum, obj->hdrChunk,+	   yaffs_GetObjectType(obj), yaffs_GetObjectFileLength(obj)));++	return YAFFS_OK;+}+#endif++/*---------------------------- Initialisation code -------------------------------------- */++static int yaffs_CheckDevFunctions(const yaffs_Device *dev)+{++	/* Common functions, gotta have */+	if (!dev->eraseBlockInNAND || !dev->initialiseNAND)+		return 0;++#ifdef CONFIG_YAFFS_YAFFS2++	/* Can use the "with tags" style interface for yaffs1 or yaffs2 */+	if (dev->writeChunkWithTagsToNAND &&+	    dev->readChunkWithTagsFromNAND &&+	    !dev->writeChunkToNAND &&+	    !dev->readChunkFromNAND &&+	    dev->markNANDBlockBad && dev->queryNANDBlock)+		return 1;+#endif++	/* Can use the "spare" style interface for yaffs1 */+	if (!dev->isYaffs2 &&+	    !dev->writeChunkWithTagsToNAND &&+	    !dev->readChunkWithTagsFromNAND &&+	    dev->writeChunkToNAND &&+	    dev->readChunkFromNAND &&+	    !dev->markNANDBlockBad && !dev->queryNANDBlock)+		return 1;++	return 0;		/* bad */+}+++static int yaffs_CreateInitialDirectories(yaffs_Device *dev)+{+	/* Initialise the unlinked, deleted, root and lost and found directories */++	dev->lostNFoundDir = dev->rootDir =  NULL;+	dev->unlinkedDir = dev->deletedDir = NULL;++	dev->unlinkedDir =+	    yaffs_CreateFakeDirectory(dev, YAFFS_OBJECTID_UNLINKED, S_IFDIR);++	dev->deletedDir =+	    yaffs_CreateFakeDirectory(dev, YAFFS_OBJECTID_DELETED, S_IFDIR);++	dev->rootDir =+	    yaffs_CreateFakeDirectory(dev, YAFFS_OBJECTID_ROOT,+				      YAFFS_ROOT_MODE | S_IFDIR);+	dev->lostNFoundDir =+	    yaffs_CreateFakeDirectory(dev, YAFFS_OBJECTID_LOSTNFOUND,+				      YAFFS_LOSTNFOUND_MODE | S_IFDIR);++	if (dev->lostNFoundDir && dev->rootDir && dev->unlinkedDir && dev->deletedDir) {+		yaffs_AddObjectToDirectory(dev->rootDir, dev->lostNFoundDir);+		return YAFFS_OK;+	}++	return YAFFS_FAIL;+}++int yaffs_GutsInitialise(yaffs_Device *dev)+{+	int init_failed = 0;+	unsigned x;+	int bits;++	T(YAFFS_TRACE_TRACING, (TSTR("yaffs: yaffs_GutsInitialise()" TENDSTR)));++	/* Check stuff that must be set */++	if (!dev) {+		T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: Need a device" TENDSTR)));+		return YAFFS_FAIL;+	}++	dev->internalStartBlock = dev->startBlock;+	dev->internalEndBlock = dev->endBlock;+	dev->blockOffset = 0;+	dev->chunkOffset = 0;+	dev->nFreeChunks = 0;++	dev->gcBlock = -1;++	if (dev->startBlock == 0) {+		dev->internalStartBlock = dev->startBlock + 1;+		dev->internalEndBlock = dev->endBlock + 1;+		dev->blockOffset = 1;+		dev->chunkOffset = dev->nChunksPerBlock;+	}++	/* Check geometry parameters. */++	if ((!dev->inbandTags && dev->isYaffs2 && dev->totalBytesPerChunk < 1024) ||+	    (!dev->isYaffs2 && dev->totalBytesPerChunk < 512) ||+	    (dev->inbandTags && !dev->isYaffs2) ||+	     dev->nChunksPerBlock < 2 ||+	     dev->nReservedBlocks < 2 ||+	     dev->internalStartBlock <= 0 ||+	     dev->internalEndBlock <= 0 ||+	     dev->internalEndBlock <= (dev->internalStartBlock + dev->nReservedBlocks + 2)) {	/* otherwise it is too small */+		T(YAFFS_TRACE_ALWAYS,+		  (TSTR+		   ("yaffs: NAND geometry problems: chunk size %d, type is yaffs%s, inbandTags %d "+		    TENDSTR), dev->totalBytesPerChunk, dev->isYaffs2 ? "2" : "", dev->inbandTags));+		return YAFFS_FAIL;+	}++	if (yaffs_InitialiseNAND(dev) != YAFFS_OK) {+		T(YAFFS_TRACE_ALWAYS,+		  (TSTR("yaffs: InitialiseNAND failed" TENDSTR)));+		return YAFFS_FAIL;+	}++	/* Sort out space for inband tags, if required */+	if (dev->inbandTags)+		dev->nDataBytesPerChunk = dev->totalBytesPerChunk - sizeof(yaffs_PackedTags2TagsPart);+	else+		dev->nDataBytesPerChunk = dev->totalBytesPerChunk;++	/* Got the right mix of functions? */+	if (!yaffs_CheckDevFunctions(dev)) {+		/* Function missing */+		T(YAFFS_TRACE_ALWAYS,+		  (TSTR+		   ("yaffs: device function(s) missing or wrong\n" TENDSTR)));++		return YAFFS_FAIL;+	}++	/* This is really a compilation check. */+	if (!yaffs_CheckStructures()) {+		T(YAFFS_TRACE_ALWAYS,+		  (TSTR("yaffs_CheckStructures failed\n" TENDSTR)));+		return YAFFS_FAIL;+	}++	if (dev->isMounted) {+		T(YAFFS_TRACE_ALWAYS,+		  (TSTR("yaffs: device already mounted\n" TENDSTR)));+		return YAFFS_FAIL;+	}++	/* Finished with most checks. One or two more checks happen later on too. */++	dev->isMounted = 1;++	/* OK now calculate a few things for the device */++	/*+	 *  Calculate all the chunk size manipulation numbers:+	 */+	x = dev->nDataBytesPerChunk;+	/* We always use dev->chunkShift and dev->chunkDiv */+	dev->chunkShift = Shifts(x);+	x >>= dev->chunkShift;+	dev->chunkDiv = x;+	/* We only use chunk mask if chunkDiv is 1 */+	dev->chunkMask = (1<<dev->chunkShift) - 1;++	/*+	 * Calculate chunkGroupBits.+	 * We need to find the next power of 2 > than internalEndBlock+	 */++	x = dev->nChunksPerBlock * (dev->internalEndBlock + 1);++	bits = ShiftsGE(x);++	/* Set up tnode width if wide tnodes are enabled. */+	if (!dev->wideTnodesDisabled) {+		/* bits must be even so that we end up with 32-bit words */+		if (bits & 1)+			bits++;+		if (bits < 16)+			dev->tnodeWidth = 16;+		else+			dev->tnodeWidth = bits;+	} else+		dev->tnodeWidth = 16;++	dev->tnodeMask = (1<<dev->tnodeWidth)-1;++	/* Level0 Tnodes are 16 bits or wider (if wide tnodes are enabled),+	 * so if the bitwidth of the+	 * chunk range we're using is greater than 16 we need+	 * to figure out chunk shift and chunkGroupSize+	 */++	if (bits <= dev->tnodeWidth)+		dev->chunkGroupBits = 0;+	else+		dev->chunkGroupBits = bits - dev->tnodeWidth;+++	dev->chunkGroupSize = 1 << dev->chunkGroupBits;++	if (dev->nChunksPerBlock < dev->chunkGroupSize) {+		/* We have a problem because the soft delete won't work if+		 * the chunk group size > chunks per block.+		 * This can be remedied by using larger "virtual blocks".+		 */+		T(YAFFS_TRACE_ALWAYS,+		  (TSTR("yaffs: chunk group too large\n" TENDSTR)));++		return YAFFS_FAIL;+	}++	/* OK, we've finished verifying the device, lets continue with initialisation */++	/* More device initialisation */+	dev->garbageCollections = 0;+	dev->passiveGarbageCollections = 0;+	dev->currentDirtyChecker = 0;+	dev->bufferedBlock = -1;+	dev->doingBufferedBlockRewrite = 0;+	dev->nDeletedFiles = 0;+	dev->nBackgroundDeletions = 0;+	dev->nUnlinkedFiles = 0;+	dev->eccFixed = 0;+	dev->eccUnfixed = 0;+	dev->tagsEccFixed = 0;+	dev->tagsEccUnfixed = 0;+	dev->nErasureFailures = 0;+	dev->nErasedBlocks = 0;+	dev->isDoingGC = 0;+	dev->hasPendingPrioritisedGCs = 1; /* Assume the worst for now, will get fixed on first GC */++	/* Initialise temporary buffers and caches. */+	if (!yaffs_InitialiseTempBuffers(dev))+		init_failed = 1;++	dev->srCache = NULL;+	dev->gcCleanupList = NULL;+++	if (!init_failed &&+	    dev->nShortOpCaches > 0) {+		int i;+		void *buf;+		int srCacheBytes = dev->nShortOpCaches * sizeof(yaffs_ChunkCache);++		if (dev->nShortOpCaches > YAFFS_MAX_SHORT_OP_CACHES)+			dev->nShortOpCaches = YAFFS_MAX_SHORT_OP_CACHES;++		dev->srCache =  YMALLOC(srCacheBytes);++		buf = (__u8 *) dev->srCache;++		if (dev->srCache)+			memset(dev->srCache, 0, srCacheBytes);++		for (i = 0; i < dev->nShortOpCaches && buf; i++) {+			dev->srCache[i].object = NULL;+			dev->srCache[i].lastUse = 0;+			dev->srCache[i].dirty = 0;+			dev->srCache[i].data = buf = YMALLOC_DMA(dev->totalBytesPerChunk);+		}+		if (!buf)+			init_failed = 1;++		dev->srLastUse = 0;+	}++	dev->cacheHits = 0;++	if (!init_failed) {+		dev->gcCleanupList = YMALLOC(dev->nChunksPerBlock * sizeof(__u32));+		if (!dev->gcCleanupList)+			init_failed = 1;+	}++	if (dev->isYaffs2)+		dev->useHeaderFileSize = 1;++	if (!init_failed && !yaffs_InitialiseBlocks(dev))+		init_failed = 1;++	yaffs_InitialiseTnodes(dev);+	yaffs_InitialiseObjects(dev);++	if (!init_failed && !yaffs_CreateInitialDirectories(dev))+		init_failed = 1;+++	if (!init_failed) {+		/* Now scan the flash. */+		if (dev->isYaffs2) {+			if (yaffs_CheckpointRestore(dev)) {+				yaffs_CheckObjectDetailsLoaded(dev->rootDir);+				T(YAFFS_TRACE_ALWAYS,+				  (TSTR("yaffs: restored from checkpoint" TENDSTR)));+			} else {++				/* Clean up the mess caused by an aborted checkpoint load+				 * and scan backwards.+				 */+				yaffs_DeinitialiseBlocks(dev);+				yaffs_DeinitialiseTnodes(dev);+				yaffs_DeinitialiseObjects(dev);+++				dev->nErasedBlocks = 0;+				dev->nFreeChunks = 0;+				dev->allocationBlock = -1;+				dev->allocationPage = -1;+				dev->nDeletedFiles = 0;+				dev->nUnlinkedFiles = 0;+				dev->nBackgroundDeletions = 0;+				dev->oldestDirtySequence = 0;++				if (!init_failed && !yaffs_InitialiseBlocks(dev))+					init_failed = 1;++				yaffs_InitialiseTnodes(dev);+				yaffs_InitialiseObjects(dev);++				if (!init_failed && !yaffs_CreateInitialDirectories(dev))+					init_failed = 1;++				if (!init_failed && !yaffs_ScanBackwards(dev))+					init_failed = 1;+			}+		} else if (!yaffs_Scan(dev))+				init_failed = 1;++		yaffs_StripDeletedObjects(dev);+	}++	if (init_failed) {+		/* Clean up the mess */+		T(YAFFS_TRACE_TRACING,+		  (TSTR("yaffs: yaffs_GutsInitialise() aborted.\n" TENDSTR)));++		yaffs_Deinitialise(dev);+		return YAFFS_FAIL;+	}++	/* Zero out stats */+	dev->nPageReads = 0;+	dev->nPageWrites = 0;+	dev->nBlockErasures = 0;+	dev->nGCCopies = 0;+	dev->nRetriedWrites = 0;++	dev->nRetiredBlocks = 0;++	yaffs_VerifyFreeChunks(dev);+	yaffs_VerifyBlocks(dev);+++	T(YAFFS_TRACE_TRACING,+	  (TSTR("yaffs: yaffs_GutsInitialise() done.\n" TENDSTR)));+	return YAFFS_OK;++}++void yaffs_Deinitialise(yaffs_Device *dev)+{+	if (dev->isMounted) {+		int i;++		yaffs_DeinitialiseBlocks(dev);+		yaffs_DeinitialiseTnodes(dev);+		yaffs_DeinitialiseObjects(dev);+		if (dev->nShortOpCaches > 0 &&+		    dev->srCache) {++			for (i = 0; i < dev->nShortOpCaches; i++) {+				if (dev->srCache[i].data)+					YFREE(dev->srCache[i].data);+				dev->srCache[i].data = NULL;+			}++			YFREE(dev->srCache);+			dev->srCache = NULL;+		}++		YFREE(dev->gcCleanupList);++		for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++)+			YFREE(dev->tempBuffer[i].buffer);++		dev->isMounted = 0;++		if (dev->deinitialiseNAND)+			dev->deinitialiseNAND(dev);+	}+}++static int yaffs_CountFreeChunks(yaffs_Device *dev)+{+	int nFree;+	int b;++	yaffs_BlockInfo *blk;++	for (nFree = 0, b = dev->internalStartBlock; b <= dev->internalEndBlock;+			b++) {+		blk = yaffs_GetBlockInfo(dev, b);++		switch (blk->blockState) {+		case YAFFS_BLOCK_STATE_EMPTY:+		case YAFFS_BLOCK_STATE_ALLOCATING:+		case YAFFS_BLOCK_STATE_COLLECTING:+		case YAFFS_BLOCK_STATE_FULL:+			nFree +=+			    (dev->nChunksPerBlock - blk->pagesInUse ++			     blk->softDeletions);+			break;+		default:+			break;+		}+	}++	return nFree;+}++int yaffs_GetNumberOfFreeChunks(yaffs_Device *dev)+{+	/* This is what we report to the outside world */++	int nFree;+	int nDirtyCacheChunks;+	int blocksForCheckpoint;+	int i;++#if 1+	nFree = dev->nFreeChunks;+#else+	nFree = yaffs_CountFreeChunks(dev);+#endif++	nFree += dev->nDeletedFiles;++	/* Now count the number of dirty chunks in the cache and subtract those */++	for (nDirtyCacheChunks = 0, i = 0; i < dev->nShortOpCaches; i++) {+		if (dev->srCache[i].dirty)+			nDirtyCacheChunks++;+	}++	nFree -= nDirtyCacheChunks;++	nFree -= ((dev->nReservedBlocks + 1) * dev->nChunksPerBlock);++	/* Now we figure out how much to reserve for the checkpoint and report that... */+	blocksForCheckpoint = yaffs_CalcCheckpointBlocksRequired(dev) - dev->blocksInCheckpoint;+	if (blocksForCheckpoint < 0)+		blocksForCheckpoint = 0;++	nFree -= (blocksForCheckpoint * dev->nChunksPerBlock);++	if (nFree < 0)+		nFree = 0;++	return nFree;++}++static int yaffs_freeVerificationFailures;++static void yaffs_VerifyFreeChunks(yaffs_Device *dev)+{+	int counted;+	int difference;++	if (yaffs_SkipVerification(dev))+		return;++	counted = yaffs_CountFreeChunks(dev);++	difference = dev->nFreeChunks - counted;++	if (difference) {+		T(YAFFS_TRACE_ALWAYS,+		  (TSTR("Freechunks verification failure %d %d %d" TENDSTR),+		   dev->nFreeChunks, counted, difference));+		yaffs_freeVerificationFailures++;+	}+}++/*---------------------------------------- YAFFS test code ----------------------*/++#define yaffs_CheckStruct(structure, syze, name) \+	do { \+		if (sizeof(structure) != syze) { \+			T(YAFFS_TRACE_ALWAYS, (TSTR("%s should be %d but is %d\n" TENDSTR),\+				name, syze, sizeof(structure))); \+			return YAFFS_FAIL; \+		} \+	} while (0)++static int yaffs_CheckStructures(void)+{+/*      yaffs_CheckStruct(yaffs_Tags,8,"yaffs_Tags"); */+/*      yaffs_CheckStruct(yaffs_TagsUnion,8,"yaffs_TagsUnion"); */+/*      yaffs_CheckStruct(yaffs_Spare,16,"yaffs_Spare"); */+#ifndef CONFIG_YAFFS_TNODE_LIST_DEBUG+	yaffs_CheckStruct(yaffs_Tnode, 2 * YAFFS_NTNODES_LEVEL0, "yaffs_Tnode");+#endif+#ifndef CONFIG_YAFFS_WINCE+	yaffs_CheckStruct(yaffs_ObjectHeader, 512, "yaffs_ObjectHeader");+#endif+	return YAFFS_OK;+}diff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_guts.h linux-2.6.30/fs/yaffs2/yaffs_guts.h--- linux-2.6.30.orig/fs/yaffs2/yaffs_guts.h	1970-01-01 01:00:00.000000000 +0100+++ linux-2.6.30/fs/yaffs2/yaffs_guts.h	2009-06-11 09:21:04.000000000 +0200@@ -0,0 +1,904 @@+/*+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.+ *+ * Copyright (C) 2002-2007 Aleph One Ltd.+ *   for Toby Churchill Ltd and Brightstar Engineering+ *+ * Created by Charles Manning <charles@aleph1.co.uk>+ *+ * This program is free software; you can redistribute it and/or modify+ * it under the terms of the GNU Lesser General Public License version 2.1 as+ * published by the Free Software Foundation.+ *+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.+ */++#ifndef __YAFFS_GUTS_H__+#define __YAFFS_GUTS_H__++#include "devextras.h"+#include "yportenv.h"++#define YAFFS_OK	1+#define YAFFS_FAIL  0++/* Give us a  Y=0x59,+ * Give us an A=0x41,+ * Give us an FF=0xFF+ * Give us an S=0x53+ * And what have we got...+ */+#define YAFFS_MAGIC			0x5941FF53++#define YAFFS_NTNODES_LEVEL0	  	16+#define YAFFS_TNODES_LEVEL0_BITS	4+#define YAFFS_TNODES_LEVEL0_MASK	0xf++#define YAFFS_NTNODES_INTERNAL 		(YAFFS_NTNODES_LEVEL0 / 2)+#define YAFFS_TNODES_INTERNAL_BITS 	(YAFFS_TNODES_LEVEL0_BITS - 1)+#define YAFFS_TNODES_INTERNAL_MASK	0x7+#define YAFFS_TNODES_MAX_LEVEL		6++#ifndef CONFIG_YAFFS_NO_YAFFS1+#define YAFFS_BYTES_PER_SPARE		16+#define YAFFS_BYTES_PER_CHUNK		512+#define YAFFS_CHUNK_SIZE_SHIFT		9+#define YAFFS_CHUNKS_PER_BLOCK		32+#define YAFFS_BYTES_PER_BLOCK		(YAFFS_CHUNKS_PER_BLOCK*YAFFS_BYTES_PER_CHUNK)+#endif++#define YAFFS_MIN_YAFFS2_CHUNK_SIZE 	1024+#define YAFFS_MIN_YAFFS2_SPARE_SIZE	32++#define YAFFS_MAX_CHUNK_ID		0x000FFFFF++#define YAFFS_UNUSED_OBJECT_ID		0x0003FFFF++#define YAFFS_ALLOCATION_NOBJECTS	100+#define YAFFS_ALLOCATION_NTNODES	100+#define YAFFS_ALLOCATION_NLINKS		100++#define YAFFS_NOBJECT_BUCKETS		256+++#define YAFFS_OBJECT_SPACE		0x40000++#define YAFFS_CHECKPOINT_VERSION 	3++#ifdef CONFIG_YAFFS_UNICODE+#define YAFFS_MAX_NAME_LENGTH		127+#define YAFFS_MAX_ALIAS_LENGTH		79+#else+#define YAFFS_MAX_NAME_LENGTH		255+#define YAFFS_MAX_ALIAS_LENGTH		159+#endif++#define YAFFS_SHORT_NAME_LENGTH		15++/* Some special object ids for pseudo objects */+#define YAFFS_OBJECTID_ROOT		1+#define YAFFS_OBJECTID_LOSTNFOUND	2+#define YAFFS_OBJECTID_UNLINKED		3+#define YAFFS_OBJECTID_DELETED		4++/* Sseudo object ids for checkpointing */+#define YAFFS_OBJECTID_SB_HEADER	0x10+#define YAFFS_OBJECTID_CHECKPOINT_DATA	0x20+#define YAFFS_SEQUENCE_CHECKPOINT_DATA  0x21++/* */++#define YAFFS_MAX_SHORT_OP_CACHES	20++#define YAFFS_N_TEMP_BUFFERS		6++/* We limit the number attempts at sucessfully saving a chunk of data.+ * Small-page devices have 32 pages per block; large-page devices have 64.+ * Default to something in the order of 5 to 10 blocks worth of chunks.+ */+#define YAFFS_WR_ATTEMPTS		(5*64)++/* Sequence numbers are used in YAFFS2 to determine block allocation order.+ * The range is limited slightly to help distinguish bad numbers from good.+ * This also allows us to perhaps in the future use special numbers for+ * special purposes.+ * EFFFFF00 allows the allocation of 8 blocks per second (~1Mbytes) for 15 years,+ * and is a larger number than the lifetime of a 2GB device.+ */+#define YAFFS_LOWEST_SEQUENCE_NUMBER	0x00001000+#define YAFFS_HIGHEST_SEQUENCE_NUMBER	0xEFFFFF00++/* Special sequence number for bad block that failed to be marked bad */+#define YAFFS_SEQUENCE_BAD_BLOCK	0xFFFF0000++/* ChunkCache is used for short read/write operations.*/+typedef struct {+	struct yaffs_ObjectStruct *object;+	int chunkId;+	int lastUse;+	int dirty;+	int nBytes;		/* Only valid if the cache is dirty */+	int locked;		/* Can't push out or flush while locked. */+#ifdef CONFIG_YAFFS_YAFFS2+	__u8 *data;+#else+	__u8 data[YAFFS_BYTES_PER_CHUNK];+#endif+} yaffs_ChunkCache;++++/* Tags structures in RAM+ * NB This uses bitfield. Bitfields should not straddle a u32 boundary otherwise+ * the structure size will get blown out.+ */++#ifndef CONFIG_YAFFS_NO_YAFFS1+typedef struct {+	unsigned chunkId:20;+	unsigned serialNumber:2;+	unsigned byteCountLSB:10;+	unsigned objectId:18;+	unsigned ecc:12;+	unsigned byteCountMSB:2;+} yaffs_Tags;++typedef union {+	yaffs_Tags asTags;+	__u8 asBytes[8];+} yaffs_TagsUnion;++#endif++/* Stuff used for extended tags in YAFFS2 */++typedef enum {+	YAFFS_ECC_RESULT_UNKNOWN,+	YAFFS_ECC_RESULT_NO_ERROR,+	YAFFS_ECC_RESULT_FIXED,+	YAFFS_ECC_RESULT_UNFIXED+} yaffs_ECCResult;++typedef enum {+	YAFFS_OBJECT_TYPE_UNKNOWN,+	YAFFS_OBJECT_TYPE_FILE,+	YAFFS_OBJECT_TYPE_SYMLINK,+	YAFFS_OBJECT_TYPE_DIRECTORY,+	YAFFS_OBJECT_TYPE_HARDLINK,+	YAFFS_OBJECT_TYPE_SPECIAL+} yaffs_ObjectType;++#define YAFFS_OBJECT_TYPE_MAX YAFFS_OBJECT_TYPE_SPECIAL++typedef struct {++	unsigned validMarker0;+	unsigned chunkUsed;	/*  Status of the chunk: used or unused */+	unsigned objectId;	/* If 0 then this is not part of an object (unused) */+	unsigned chunkId;	/* If 0 then this is a header, else a data chunk */+	unsigned byteCount;	/* Only valid for data chunks */++	/* The following stuff only has meaning when we read */+	yaffs_ECCResult eccResult;+	unsigned blockBad;++	/* YAFFS 1 stuff */+	unsigned chunkDeleted;	/* The chunk is marked deleted */+	unsigned serialNumber;	/* Yaffs1 2-bit serial number */++	/* YAFFS2 stuff */+	unsigned sequenceNumber;	/* The sequence number of this block */++	/* Extra info if this is an object header (YAFFS2 only) */++	unsigned extraHeaderInfoAvailable;	/* There is extra info available if this is not zero */+	unsigned extraParentObjectId;	/* The parent object */+	unsigned extraIsShrinkHeader;	/* Is it a shrink header? */+	unsigned extraShadows;		/* Does this shadow another object? */++	yaffs_ObjectType extraObjectType;	/* What object type? */++	unsigned extraFileLength;		/* Length if it is a file */+	unsigned extraEquivalentObjectId;	/* Equivalent object Id if it is a hard link */++	unsigned validMarker1;++} yaffs_ExtendedTags;++/* Spare structure for YAFFS1 */+typedef struct {+	__u8 tagByte0;+	__u8 tagByte1;+	__u8 tagByte2;+	__u8 tagByte3;+	__u8 pageStatus;	/* set to 0 to delete the chunk */+	__u8 blockStatus;+	__u8 tagByte4;+	__u8 tagByte5;+	__u8 ecc1[3];+	__u8 tagByte6;+	__u8 tagByte7;+	__u8 ecc2[3];+} yaffs_Spare;++/*Special structure for passing through to mtd */+struct yaffs_NANDSpare {+	yaffs_Spare spare;+	int eccres1;+	int eccres2;+};++/* Block data in RAM */++typedef enum {+	YAFFS_BLOCK_STATE_UNKNOWN = 0,++	YAFFS_BLOCK_STATE_SCANNING,+	YAFFS_BLOCK_STATE_NEEDS_SCANNING,+	/* The block might have something on it (ie it is allocating or full, perhaps empty)+	 * but it needs to be scanned to determine its true state.+	 * This state is only valid during yaffs_Scan.+	 * NB We tolerate empty because the pre-scanner might be incapable of deciding+	 * However, if this state is returned on a YAFFS2 device, then we expect a sequence number+	 */++	YAFFS_BLOCK_STATE_EMPTY,+	/* This block is empty */++	YAFFS_BLOCK_STATE_ALLOCATING,+	/* This block is partially allocated.+	 * At least one page holds valid data.+	 * This is the one currently being used for page+	 * allocation. Should never be more than one of these+	 */++	YAFFS_BLOCK_STATE_FULL,+	/* All the pages in this block have been allocated.+	 */++	YAFFS_BLOCK_STATE_DIRTY,+	/* All pages have been allocated and deleted.+	 * Erase me, reuse me.+	 */++	YAFFS_BLOCK_STATE_CHECKPOINT,+	/* This block is assigned to holding checkpoint data.+	 */++	YAFFS_BLOCK_STATE_COLLECTING,+	/* This block is being garbage collected */++	YAFFS_BLOCK_STATE_DEAD+	/* This block has failed and is not in use */+} yaffs_BlockState;++#define	YAFFS_NUMBER_OF_BLOCK_STATES (YAFFS_BLOCK_STATE_DEAD + 1)+++typedef struct {++	int softDeletions:10;	/* number of soft deleted pages */+	int pagesInUse:10;	/* number of pages in use */+	unsigned blockState:4;	/* One of the above block states. NB use unsigned because enum is sometimes an int */+	__u32 needsRetiring:1;	/* Data has failed on this block, need to get valid data off */+				/* and retire the block. */+	__u32 skipErasedCheck:1; /* If this is set we can skip the erased check on this block */+	__u32 gcPrioritise:1; 	/* An ECC check or blank check has failed on this block.+				   It should be prioritised for GC */+	__u32 chunkErrorStrikes:3; /* How many times we've had ecc etc failures on this block and tried to reuse it */++#ifdef CONFIG_YAFFS_YAFFS2+	__u32 hasShrinkHeader:1; /* This block has at least one shrink object header */+	__u32 sequenceNumber;	 /* block sequence number for yaffs2 */+#endif++} yaffs_BlockInfo;++/* -------------------------- Object structure -------------------------------*/+/* This is the object structure as stored on NAND */++typedef struct {+	yaffs_ObjectType type;++	/* Apply to everything  */+	int parentObjectId;+	__u16 sum__NoLongerUsed;        /* checksum of name. No longer used */+	YCHAR name[YAFFS_MAX_NAME_LENGTH + 1];++	/* The following apply to directories, files, symlinks - not hard links */+	__u32 yst_mode;         /* protection */++#ifdef CONFIG_YAFFS_WINCE+	__u32 notForWinCE[5];+#else+	__u32 yst_uid;+	__u32 yst_gid;+	__u32 yst_atime;+	__u32 yst_mtime;+	__u32 yst_ctime;+#endif++	/* File size  applies to files only */+	int fileSize;++	/* Equivalent object id applies to hard links only. */+	int equivalentObjectId;++	/* Alias is for symlinks only. */+	YCHAR alias[YAFFS_MAX_ALIAS_LENGTH + 1];++	__u32 yst_rdev;		/* device stuff for block and char devices (major/min) */++#ifdef CONFIG_YAFFS_WINCE+	__u32 win_ctime[2];+	__u32 win_atime[2];+	__u32 win_mtime[2];+#else+	__u32 roomToGrow[6];++#endif+	__u32 inbandShadowsObject;+	__u32 inbandIsShrink;++	__u32 reservedSpace[2];+	int shadowsObject;	/* This object header shadows the specified object if > 0 */++	/* isShrink applies to object headers written when we shrink the file (ie resize) */+	__u32 isShrink;++} yaffs_ObjectHeader;++/*--------------------------- Tnode -------------------------- */++union yaffs_Tnode_union {+#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG+	union yaffs_Tnode_union *internal[YAFFS_NTNODES_INTERNAL + 1];+#else+	union yaffs_Tnode_union *internal[YAFFS_NTNODES_INTERNAL];+#endif+/*	__u16 level0[YAFFS_NTNODES_LEVEL0]; */++};++typedef union yaffs_Tnode_union yaffs_Tnode;++struct yaffs_TnodeList_struct {+	struct yaffs_TnodeList_struct *next;+	yaffs_Tnode *tnodes;+};++typedef struct yaffs_TnodeList_struct yaffs_TnodeList;++/*------------------------  Object -----------------------------*/+/* An object can be one of:+ * - a directory (no data, has children links+ * - a regular file (data.... not prunes :->).+ * - a symlink [symbolic link] (the alias).+ * - a hard link+ */++typedef struct {+	__u32 fileSize;+	__u32 scannedFileSize;+	__u32 shrinkSize;+	int topLevel;+	yaffs_Tnode *top;+} yaffs_FileStructure;++typedef struct {+	struct ylist_head children;     /* list of child links */+} yaffs_DirectoryStructure;++typedef struct {+	YCHAR *alias;+} yaffs_SymLinkStructure;++typedef struct {+	struct yaffs_ObjectStruct *equivalentObject;+	__u32 equivalentObjectId;+} yaffs_HardLinkStructure;++typedef union {+	yaffs_FileStructure fileVariant;+	yaffs_DirectoryStructure directoryVariant;+	yaffs_SymLinkStructure symLinkVariant;+	yaffs_HardLinkStructure hardLinkVariant;+} yaffs_ObjectVariant;++struct yaffs_ObjectStruct {+	__u8 deleted:1;		/* This should only apply to unlinked files. */+	__u8 softDeleted:1;	/* it has also been soft deleted */+	__u8 unlinked:1;	/* An unlinked file. The file should be in the unlinked directory.*/+	__u8 fake:1;		/* A fake object has no presence on NAND. */+	__u8 renameAllowed:1;	/* Some objects are not allowed to be renamed. */+	__u8 unlinkAllowed:1;+	__u8 dirty:1;		/* the object needs to be written to flash */+	__u8 valid:1;		/* When the file system is being loaded up, this+				 * object might be created before the data+				 * is available (ie. file data records appear before the header).+				 */+	__u8 lazyLoaded:1;	/* This object has been lazy loaded and is missing some detail */++	__u8 deferedFree:1;	/* For Linux kernel. Object is removed from NAND, but is+				 * still in the inode cache. Free of object is defered.+				 * until the inode is released.+				 */+	__u8 beingCreated:1;	/* This object is still being created so skip some checks. */++	__u8 serial;		/* serial number of chunk in NAND. Cached here */+	__u16 sum;		/* sum of the name to speed searching */++	struct yaffs_DeviceStruct *myDev;       /* The device I'm on */++	struct ylist_head hashLink;     /* list of objects in this hash bucket */++	struct ylist_head hardLinks;    /* all the equivalent hard linked objects */++	/* directory structure stuff */+	/* also used for linking up the free list */+	struct yaffs_ObjectStruct *parent;+	struct ylist_head siblings;++	/* Where's my object header in NAND? */+	int hdrChunk;++	int nDataChunks;	/* Number of data chunks attached to the file. */++	__u32 objectId;		/* the object id value */++	__u32 yst_mode;++#ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM+	YCHAR shortName[YAFFS_SHORT_NAME_LENGTH + 1];+#endif++#ifndef __KERNEL__+	__u32 inUse;+#endif++#ifdef CONFIG_YAFFS_WINCE+	__u32 win_ctime[2];+	__u32 win_mtime[2];+	__u32 win_atime[2];+#else+	__u32 yst_uid;+	__u32 yst_gid;+	__u32 yst_atime;+	__u32 yst_mtime;+	__u32 yst_ctime;+#endif++	__u32 yst_rdev;++#ifdef __KERNEL__+	struct inode *myInode;++#endif++	yaffs_ObjectType variantType;++	yaffs_ObjectVariant variant;++};++typedef struct yaffs_ObjectStruct yaffs_Object;++struct yaffs_ObjectList_struct {+	yaffs_Object *objects;+	struct yaffs_ObjectList_struct *next;+};++typedef struct yaffs_ObjectList_struct yaffs_ObjectList;++typedef struct {+	struct ylist_head list;+	int count;+} yaffs_ObjectBucket;+++/* yaffs_CheckpointObject holds the definition of an object as dumped+ * by checkpointing.+ */++typedef struct {+	int structType;+	__u32 objectId;+	__u32 parentId;+	int hdrChunk;+	yaffs_ObjectType variantType:3;+	__u8 deleted:1;+	__u8 softDeleted:1;+	__u8 unlinked:1;+	__u8 fake:1;+	__u8 renameAllowed:1;+	__u8 unlinkAllowed:1;+	__u8 serial;++	int nDataChunks;+	__u32 fileSizeOrEquivalentObjectId;+} yaffs_CheckpointObject;++/*--------------------- Temporary buffers ----------------+ *+ * These are chunk-sized working buffers. Each device has a few+ */++typedef struct {+	__u8 *buffer;+	int line;	/* track from whence this buffer was allocated */+	int maxLine;+} yaffs_TempBuffer;++/*----------------- Device ---------------------------------*/++struct yaffs_DeviceStruct {+	struct ylist_head devList;+	const char *name;++	/* Entry parameters set up way early. Yaffs sets up the rest.*/+	int nDataBytesPerChunk;	/* Should be a power of 2 >= 512 */+	int nChunksPerBlock;	/* does not need to be a power of 2 */+	int spareBytesPerChunk;	/* spare area size */+	int startBlock;		/* Start block we're allowed to use */+	int endBlock;		/* End block we're allowed to use */+	int nReservedBlocks;	/* We want this tuneable so that we can reduce */+				/* reserved blocks on NOR and RAM. */+++	/* Stuff used by the shared space checkpointing mechanism */+	/* If this value is zero, then this mechanism is disabled */++/*	int nCheckpointReservedBlocks; */ /* Blocks to reserve for checkpoint data */+++	int nShortOpCaches;	/* If <= 0, then short op caching is disabled, else+				 * the number of short op caches (don't use too many)+				 */++	int useHeaderFileSize;	/* Flag to determine if we should use file sizes from the header */++	int useNANDECC;		/* Flag to decide whether or not to use NANDECC */++	void *genericDevice;	/* Pointer to device context+				 * On an mtd this holds the mtd pointer.+				 */+	void *superBlock;++	/* NAND access functions (Must be set before calling YAFFS)*/++	int (*writeChunkToNAND) (struct yaffs_DeviceStruct *dev,+					int chunkInNAND, const __u8 *data,+					const yaffs_Spare *spare);+	int (*readChunkFromNAND) (struct yaffs_DeviceStruct *dev,+					int chunkInNAND, __u8 *data,+					yaffs_Spare *spare);+	int (*eraseBlockInNAND) (struct yaffs_DeviceStruct *dev,+					int blockInNAND);+	int (*initialiseNAND) (struct yaffs_DeviceStruct *dev);+	int (*deinitialiseNAND) (struct yaffs_DeviceStruct *dev);++#ifdef CONFIG_YAFFS_YAFFS2+	int (*writeChunkWithTagsToNAND) (struct yaffs_DeviceStruct *dev,+					 int chunkInNAND, const __u8 *data,+					 const yaffs_ExtendedTags *tags);+	int (*readChunkWithTagsFromNAND) (struct yaffs_DeviceStruct *dev,+					  int chunkInNAND, __u8 *data,+					  yaffs_ExtendedTags *tags);+	int (*markNANDBlockBad) (struct yaffs_DeviceStruct *dev, int blockNo);+	int (*queryNANDBlock) (struct yaffs_DeviceStruct *dev, int blockNo,+			       yaffs_BlockState *state, __u32 *sequenceNumber);+#endif++	int isYaffs2;++	/* The removeObjectCallback function must be supplied by OS flavours that+	 * need it. The Linux kernel does not use this, but yaffs direct does use+	 * it to implement the faster readdir+	 */+	void (*removeObjectCallback)(struct yaffs_ObjectStruct *obj);++	/* Callback to mark the superblock dirsty */+	void (*markSuperBlockDirty)(void *superblock);++	int wideTnodesDisabled; /* Set to disable wide tnodes */++	YCHAR *pathDividers;	/* String of legal path dividers */+++	/* End of stuff that must be set before initialisation. */++	/* Checkpoint control. Can be set before or after initialisation */+	__u8 skipCheckpointRead;+	__u8 skipCheckpointWrite;++	/* Runtime parameters. Set up by YAFFS. */++	__u16 chunkGroupBits;	/* 0 for devices <= 32MB. else log2(nchunks) - 16 */+	__u16 chunkGroupSize;	/* == 2^^chunkGroupBits */++	/* Stuff to support wide tnodes */+	__u32 tnodeWidth;+	__u32 tnodeMask;++	/* Stuff for figuring out file offset to chunk conversions */+	__u32 chunkShift; /* Shift value */+	__u32 chunkDiv;   /* Divisor after shifting: 1 for power-of-2 sizes */+	__u32 chunkMask;  /* Mask to use for power-of-2 case */++	/* Stuff to handle inband tags */+	int inbandTags;+	__u32 totalBytesPerChunk;++#ifdef __KERNEL__++	struct semaphore sem;	/* Semaphore for waiting on erasure.*/+	struct semaphore grossLock;	/* Gross locking semaphore */+	__u8 *spareBuffer;	/* For mtdif2 use. Don't know the size of the buffer+				 * at compile time so we have to allocate it.+				 */+	void (*putSuperFunc) (struct super_block *sb);+#endif++	int isMounted;++	int isCheckpointed;+++	/* Stuff to support block offsetting to support start block zero */+	int internalStartBlock;+	int internalEndBlock;+	int blockOffset;+	int chunkOffset;+++	/* Runtime checkpointing stuff */+	int checkpointPageSequence;   /* running sequence number of checkpoint pages */+	int checkpointByteCount;+	int checkpointByteOffset;+	__u8 *checkpointBuffer;+	int checkpointOpenForWrite;+	int blocksInCheckpoint;+	int checkpointCurrentChunk;+	int checkpointCurrentBlock;+	int checkpointNextBlock;+	int *checkpointBlockList;+	int checkpointMaxBlocks;+	__u32 checkpointSum;+	__u32 checkpointXor;++	int nCheckpointBlocksRequired; /* Number of blocks needed to store current checkpoint set */++	/* Block Info */+	yaffs_BlockInfo *blockInfo;+	__u8 *chunkBits;	/* bitmap of chunks in use */+	unsigned blockInfoAlt:1;	/* was allocated using alternative strategy */+	unsigned chunkBitsAlt:1;	/* was allocated using alternative strategy */+	int chunkBitmapStride;	/* Number of bytes of chunkBits per block.+				 * Must be consistent with nChunksPerBlock.+				 */++	int nErasedBlocks;+	int allocationBlock;	/* Current block being allocated off */+	__u32 allocationPage;+	int allocationBlockFinder;	/* Used to search for next allocation block */++	/* Runtime state */+	int nTnodesCreated;+	yaffs_Tnode *freeTnodes;+	int nFreeTnodes;+	yaffs_TnodeList *allocatedTnodeList;++	int isDoingGC;+	int gcBlock;+	int gcChunk;++	int nObjectsCreated;+	yaffs_Object *freeObjects;+	int nFreeObjects;++	int nHardLinks;++	yaffs_ObjectList *allocatedObjectList;++	yaffs_ObjectBucket objectBucket[YAFFS_NOBJECT_BUCKETS];++	int nFreeChunks;++	int currentDirtyChecker;	/* Used to find current dirtiest block */++	__u32 *gcCleanupList;	/* objects to delete at the end of a GC. */+	int nonAggressiveSkip;	/* GC state/mode */++	/* Statistcs */+	int nPageWrites;+	int nPageReads;+	int nBlockErasures;+	int nErasureFailures;+	int nGCCopies;+	int garbageCollections;+	int passiveGarbageCollections;+	int nRetriedWrites;+	int nRetiredBlocks;+	int eccFixed;+	int eccUnfixed;+	int tagsEccFixed;+	int tagsEccUnfixed;+	int nDeletions;+	int nUnmarkedDeletions;++	int hasPendingPrioritisedGCs; /* We think this device might have pending prioritised gcs */++	/* Special directories */+	yaffs_Object *rootDir;+	yaffs_Object *lostNFoundDir;++	/* Buffer areas for storing data to recover from write failures TODO+	 *      __u8            bufferedData[YAFFS_CHUNKS_PER_BLOCK][YAFFS_BYTES_PER_CHUNK];+	 *      yaffs_Spare bufferedSpare[YAFFS_CHUNKS_PER_BLOCK];+	 */++	int bufferedBlock;	/* Which block is buffered here? */+	int doingBufferedBlockRewrite;++	yaffs_ChunkCache *srCache;+	int srLastUse;++	int cacheHits;++	/* Stuff for background deletion and unlinked files.*/+	yaffs_Object *unlinkedDir;	/* Directory where unlinked and deleted files live. */+	yaffs_Object *deletedDir;	/* Directory where deleted objects are sent to disappear. */+	yaffs_Object *unlinkedDeletion;	/* Current file being background deleted.*/+	int nDeletedFiles;		/* Count of files awaiting deletion;*/+	int nUnlinkedFiles;		/* Count of unlinked files. */+	int nBackgroundDeletions;	/* Count of background deletions. */+++	/* Temporary buffer management */+	yaffs_TempBuffer tempBuffer[YAFFS_N_TEMP_BUFFERS];+	int maxTemp;+	int tempInUse;+	int unmanagedTempAllocations;+	int unmanagedTempDeallocations;++	/* yaffs2 runtime stuff */+	unsigned sequenceNumber;	/* Sequence number of currently allocating block */+	unsigned oldestDirtySequence;++};++typedef struct yaffs_DeviceStruct yaffs_Device;++/* The static layout of block usage etc is stored in the super block header */+typedef struct {+	int StructType;+	int version;+	int checkpointStartBlock;+	int checkpointEndBlock;+	int startBlock;+	int endBlock;+	int rfu[100];+} yaffs_SuperBlockHeader;++/* The CheckpointDevice structure holds the device information that changes at runtime and+ * must be preserved over unmount/mount cycles.+ */+typedef struct {+	int structType;+	int nErasedBlocks;+	int allocationBlock;	/* Current block being allocated off */+	__u32 allocationPage;+	int nFreeChunks;++	int nDeletedFiles;		/* Count of files awaiting deletion;*/+	int nUnlinkedFiles;		/* Count of unlinked files. */+	int nBackgroundDeletions;	/* Count of background deletions. */++	/* yaffs2 runtime stuff */+	unsigned sequenceNumber;	/* Sequence number of currently allocating block */+	unsigned oldestDirtySequence;++} yaffs_CheckpointDevice;+++typedef struct {+	int structType;+	__u32 magic;+	__u32 version;+	__u32 head;+} yaffs_CheckpointValidity;+++/*----------------------- YAFFS Functions -----------------------*/++int yaffs_GutsInitialise(yaffs_Device *dev);+void yaffs_Deinitialise(yaffs_Device *dev);++int yaffs_GetNumberOfFreeChunks(yaffs_Device *dev);++int yaffs_RenameObject(yaffs_Object *oldDir, const YCHAR *oldName,+		       yaffs_Object *newDir, const YCHAR *newName);++int yaffs_Unlink(yaffs_Object *dir, const YCHAR *name);+int yaffs_DeleteObject(yaffs_Object *obj);++int yaffs_GetObjectName(yaffs_Object *obj, YCHAR *name, int buffSize);+int yaffs_GetObjectFileLength(yaffs_Object *obj);+int yaffs_GetObjectInode(yaffs_Object *obj);+unsigned yaffs_GetObjectType(yaffs_Object *obj);+int yaffs_GetObjectLinkCount(yaffs_Object *obj);++int yaffs_SetAttributes(yaffs_Object *obj, struct iattr *attr);+int yaffs_GetAttributes(yaffs_Object *obj, struct iattr *attr);++/* File operations */+int yaffs_ReadDataFromFile(yaffs_Object *obj, __u8 *buffer, loff_t offset,+				int nBytes);+int yaffs_WriteDataToFile(yaffs_Object *obj, const __u8 *buffer, loff_t offset,+				int nBytes, int writeThrough);+int yaffs_ResizeFile(yaffs_Object *obj, loff_t newSize);++yaffs_Object *yaffs_MknodFile(yaffs_Object *parent, const YCHAR *name,+				__u32 mode, __u32 uid, __u32 gid);+int yaffs_FlushFile(yaffs_Object *obj, int updateTime);++/* Flushing and checkpointing */+void yaffs_FlushEntireDeviceCache(yaffs_Device *dev);++int yaffs_CheckpointSave(yaffs_Device *dev);+int yaffs_CheckpointRestore(yaffs_Device *dev);++/* Directory operations */+yaffs_Object *yaffs_MknodDirectory(yaffs_Object *parent, const YCHAR *name,+				__u32 mode, __u32 uid, __u32 gid);+yaffs_Object *yaffs_FindObjectByName(yaffs_Object *theDir, const YCHAR *name);+int yaffs_ApplyToDirectoryChildren(yaffs_Object *theDir,+				   int (*fn) (yaffs_Object *));++yaffs_Object *yaffs_FindObjectByNumber(yaffs_Device *dev, __u32 number);++/* Link operations */+yaffs_Object *yaffs_Link(yaffs_Object *parent, const YCHAR *name,+			 yaffs_Object *equivalentObject);++yaffs_Object *yaffs_GetEquivalentObject(yaffs_Object *obj);++/* Symlink operations */+yaffs_Object *yaffs_MknodSymLink(yaffs_Object *parent, const YCHAR *name,+				 __u32 mode, __u32 uid, __u32 gid,+				 const YCHAR *alias);+YCHAR *yaffs_GetSymlinkAlias(yaffs_Object *obj);++/* Special inodes (fifos, sockets and devices) */+yaffs_Object *yaffs_MknodSpecial(yaffs_Object *parent, const YCHAR *name,+				 __u32 mode, __u32 uid, __u32 gid, __u32 rdev);++/* Special directories */+yaffs_Object *yaffs_Root(yaffs_Device *dev);+yaffs_Object *yaffs_LostNFound(yaffs_Device *dev);++#ifdef CONFIG_YAFFS_WINCE+/* CONFIG_YAFFS_WINCE special stuff */+void yfsd_WinFileTimeNow(__u32 target[2]);+#endif++#ifdef __KERNEL__++void yaffs_HandleDeferedFree(yaffs_Object *obj);+#endif++/* Debug dump  */+int yaffs_DumpObject(yaffs_Object *obj);++void yaffs_GutsTest(yaffs_Device *dev);++/* A few useful functions */+void yaffs_InitialiseTags(yaffs_ExtendedTags *tags);+void yaffs_DeleteChunk(yaffs_Device *dev, int chunkId, int markNAND, int lyn);+int yaffs_CheckFF(__u8 *buffer, int nBytes);+void yaffs_HandleChunkError(yaffs_Device *dev, yaffs_BlockInfo *bi);++__u8 *yaffs_GetTempBuffer(yaffs_Device *dev, int lineNo);+void yaffs_ReleaseTempBuffer(yaffs_Device *dev, __u8 *buffer, int lineNo);++#endifdiff -Nur linux-2.6.30.orig/fs/yaffs2/yaffsinterface.h linux-2.6.30/fs/yaffs2/yaffsinterface.h--- linux-2.6.30.orig/fs/yaffs2/yaffsinterface.h	1970-01-01 01:00:00.000000000 +0100+++ linux-2.6.30/fs/yaffs2/yaffsinterface.h	2009-06-11 09:21:04.000000000 +0200@@ -0,0 +1,21 @@+/*+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.+ *+ * Copyright (C) 2002-2007 Aleph One Ltd.+ *   for Toby Churchill Ltd and Brightstar Engineering+ *+ * Created by Charles Manning <charles@aleph1.co.uk>+ *+ * This program is free software; you can redistribute it and/or modify+ * it under the terms of the GNU Lesser General Public License version 2.1 as+ * published by the Free Software Foundation.+ *+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.+ */++#ifndef __YAFFSINTERFACE_H__+#define __YAFFSINTERFACE_H__++int yaffs_Initialise(unsigned nBlocks);++#endifdiff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_mtdif1.c linux-2.6.30/fs/yaffs2/yaffs_mtdif1.c--- linux-2.6.30.orig/fs/yaffs2/yaffs_mtdif1.c	1970-01-01 01:00:00.000000000 +0100+++ linux-2.6.30/fs/yaffs2/yaffs_mtdif1.c	2009-06-11 09:21:04.000000000 +0200@@ -0,0 +1,365 @@+/*+ * YAFFS: Yet another FFS. A NAND-flash specific file system.+ * yaffs_mtdif1.c  NAND mtd interface functions for small-page NAND.+ *+ * Copyright (C) 2002 Aleph One Ltd.+ *   for Toby Churchill Ltd and Brightstar Engineering+ *+ * This program is free software; you can redistribute it and/or modify+ * it under the terms of the GNU General Public License version 2 as+ * published by the Free Software Foundation.+ */++/*+ * This module provides the interface between yaffs_nand.c and the+ * MTD API.  This version is used when the MTD interface supports the+ * 'mtd_oob_ops' style calls to read_oob and write_oob, circa 2.6.17,+ * and we have small-page NAND device.+ *+ * These functions are invoked via function pointers in yaffs_nand.c.+ * This replaces functionality provided by functions in yaffs_mtdif.c+ * and the yaffs_TagsCompatability functions in yaffs_tagscompat.c that are+ * called in yaffs_mtdif.c when the function pointers are NULL.+ * We assume the MTD layer is performing ECC (useNANDECC is true).+ */++#include "yportenv.h"+#include "yaffs_guts.h"+#include "yaffs_packedtags1.h"+#include "yaffs_tagscompat.h"	/* for yaffs_CalcTagsECC */++#include "linux/kernel.h"+#include "linux/version.h"+#include "linux/types.h"+#include "linux/mtd/mtd.h"++/* Don't compile this module if we don't have MTD's mtd_oob_ops interface */+#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))++const char *yaffs_mtdif1_c_version = "$Id: yaffs_mtdif1.c,v 1.10 2009-03-09 07:41:10 charles Exp $";++#ifndef CONFIG_YAFFS_9BYTE_TAGS+# define YTAG1_SIZE 8+#else+# define YTAG1_SIZE 9+#endif++#if 0+/* Use the following nand_ecclayout with MTD when using+ * CONFIG_YAFFS_9BYTE_TAGS and the older on-NAND tags layout.+ * If you have existing Yaffs images and the byte order differs from this,+ * adjust 'oobfree' to match your existing Yaffs data.+ *+ * This nand_ecclayout scatters/gathers to/from the old-yaffs layout with the+ * pageStatus byte (at NAND spare offset 4) scattered/gathered from/to+ * the 9th byte.+ *+ * Old-style on-NAND format: T0,T1,T2,T3,P,B,T4,T5,E0,E1,E2,T6,T7,E3,E4,E5+ * We have/need PackedTags1 plus pageStatus: T0,T1,T2,T3,T4,T5,T6,T7,P+ * where Tn are the tag bytes, En are MTD's ECC bytes, P is the pageStatus+ * byte and B is the small-page bad-block indicator byte.+ */+static struct nand_ecclayout nand_oob_16 = {+	.eccbytes = 6,+	.eccpos = { 8, 9, 10, 13, 14, 15 },+	.oobavail = 9,+	.oobfree = { { 0, 4 }, { 6, 2 }, { 11, 2 }, { 4, 1 } }+};+#endif++/* Write a chunk (page) of data to NAND.+ *+ * Caller always provides ExtendedTags data which are converted to a more+ * compact (packed) form for storage in NAND.  A mini-ECC runs over the+ * contents of the tags meta-data; used to valid the tags when read.+ *+ *  - Pack ExtendedTags to PackedTags1 form+ *  - Compute mini-ECC for PackedTags1+ *  - Write data and packed tags to NAND.+ *+ * Note: Due to the use of the PackedTags1 meta-data which does not include+ * a full sequence number (as found in the larger PackedTags2 form) it is+ * necessary for Yaffs to re-write a chunk/page (just once) to mark it as+ * discarded and dirty.  This is not ideal: newer NAND parts are supposed+ * to be written just once.  When Yaffs performs this operation, this+ * function is called with a NULL data pointer -- calling MTD write_oob+ * without data is valid usage (2.6.17).+ *+ * Any underlying MTD error results in YAFFS_FAIL.+ * Returns YAFFS_OK or YAFFS_FAIL.+ */+int nandmtd1_WriteChunkWithTagsToNAND(yaffs_Device *dev,+	int chunkInNAND, const __u8 *data, const yaffs_ExtendedTags *etags)+{+	struct mtd_info *mtd = dev->genericDevice;+	int chunkBytes = dev->nDataBytesPerChunk;+	loff_t addr = ((loff_t)chunkInNAND) * chunkBytes;+	struct mtd_oob_ops ops;+	yaffs_PackedTags1 pt1;+	int retval;++	/* we assume that PackedTags1 and yaffs_Tags are compatible */+	compile_time_assertion(sizeof(yaffs_PackedTags1) == 12);+	compile_time_assertion(sizeof(yaffs_Tags) == 8);++	dev->nPageWrites++;++	yaffs_PackTags1(&pt1, etags);+	yaffs_CalcTagsECC((yaffs_Tags *)&pt1);++	/* When deleting a chunk, the upper layer provides only skeletal+	 * etags, one with chunkDeleted set.  However, we need to update the+	 * tags, not erase them completely.  So we use the NAND write property+	 * that only zeroed-bits stick and set tag bytes to all-ones and+	 * zero just the (not) deleted bit.+	 */+#ifndef CONFIG_YAFFS_9BYTE_TAGS+	if (etags->chunkDeleted) {+		memset(&pt1, 0xff, 8);+		/* clear delete status bit to indicate deleted */+		pt1.deleted = 0;+	}+#else+	((__u8 *)&pt1)[8] = 0xff;+	if (etags->chunkDeleted) {+		memset(&pt1, 0xff, 8);+		/* zero pageStatus byte to indicate deleted */+		((__u8 *)&pt1)[8] = 0;+	}+#endif++	memset(&ops, 0, sizeof(ops));+	ops.mode = MTD_OOB_AUTO;+	ops.len = (data) ? chunkBytes : 0;+	ops.ooblen = YTAG1_SIZE;+	ops.datbuf = (__u8 *)data;+	ops.oobbuf = (__u8 *)&pt1;++	retval = mtd->write_oob(mtd, addr, &ops);+	if (retval) {+		yaffs_trace(YAFFS_TRACE_MTD,+			"write_oob failed, chunk %d, mtd error %d\n",+			chunkInNAND, retval);+	}+	return retval ? YAFFS_FAIL : YAFFS_OK;+}++/* Return with empty ExtendedTags but add eccResult.+ */+static int rettags(yaffs_ExtendedTags *etags, int eccResult, int retval)+{+	if (etags) {+		memset(etags, 0, sizeof(*etags));+		etags->eccResult = eccResult;+	}+	return retval;+}++/* Read a chunk (page) from NAND.+ *+ * Caller expects ExtendedTags data to be usable even on error; that is,+ * all members except eccResult and blockBad are zeroed.+ *+ *  - Check ECC results for data (if applicable)+ *  - Check for blank/erased block (return empty ExtendedTags if blank)+ *  - Check the PackedTags1 mini-ECC (correct if necessary/possible)+ *  - Convert PackedTags1 to ExtendedTags+ *  - Update eccResult and blockBad members to refect state.+ *+ * Returns YAFFS_OK or YAFFS_FAIL.+ */+int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device *dev,+	int chunkInNAND, __u8 *data, yaffs_ExtendedTags *etags)+{+	struct mtd_info *mtd = dev->genericDevice;+	int chunkBytes = dev->nDataBytesPerChunk;+	loff_t addr = ((loff_t)chunkInNAND) * chunkBytes;+	int eccres = YAFFS_ECC_RESULT_NO_ERROR;+	struct mtd_oob_ops ops;+	yaffs_PackedTags1 pt1;+	int retval;+	int deleted;++	dev->nPageReads++;++	memset(&ops, 0, sizeof(ops));+	ops.mode = MTD_OOB_AUTO;+	ops.len = (data) ? chunkBytes : 0;+	ops.ooblen = YTAG1_SIZE;+	ops.datbuf = data;+	ops.oobbuf = (__u8 *)&pt1;++#if (MTD_VERSION_CODE < MTD_VERSION(2, 6, 20))+	/* In MTD 2.6.18 to 2.6.19 nand_base.c:nand_do_read_oob() has a bug;+	 * help it out with ops.len = ops.ooblen when ops.datbuf == NULL.+	 */+	ops.len = (ops.datbuf) ? ops.len : ops.ooblen;+#endif+	/* Read page and oob using MTD.+	 * Check status and determine ECC result.+	 */+	retval = mtd->read_oob(mtd, addr, &ops);+	if (retval) {+		yaffs_trace(YAFFS_TRACE_MTD,+			"read_oob failed, chunk %d, mtd error %d\n",+			chunkInNAND, retval);+	}++	switch (retval) {+	case 0:+		/* no error */+		break;++	case -EUCLEAN:+		/* MTD's ECC fixed the data */+		eccres = YAFFS_ECC_RESULT_FIXED;+		dev->eccFixed++;+		break;++	case -EBADMSG:+		/* MTD's ECC could not fix the data */+		dev->eccUnfixed++;+		/* fall into... */+	default:+		rettags(etags, YAFFS_ECC_RESULT_UNFIXED, 0);+		etags->blockBad = (mtd->block_isbad)(mtd, addr);+		return YAFFS_FAIL;+	}++	/* Check for a blank/erased chunk.+	 */+	if (yaffs_CheckFF((__u8 *)&pt1, 8)) {+		/* when blank, upper layers want eccResult to be <= NO_ERROR */+		return rettags(etags, YAFFS_ECC_RESULT_NO_ERROR, YAFFS_OK);+	}++#ifndef CONFIG_YAFFS_9BYTE_TAGS+	/* Read deleted status (bit) then return it to it's non-deleted+	 * state before performing tags mini-ECC check. pt1.deleted is+	 * inverted.+	 */+	deleted = !pt1.deleted;+	pt1.deleted = 1;+#else+	deleted = (yaffs_CountBits(((__u8 *)&pt1)[8]) < 7);+#endif++	/* Check the packed tags mini-ECC and correct if necessary/possible.+	 */+	retval = yaffs_CheckECCOnTags((yaffs_Tags *)&pt1);+	switch (retval) {+	case 0:+		/* no tags error, use MTD result */+		break;+	case 1:+		/* recovered tags-ECC error */+		dev->tagsEccFixed++;+		if (eccres == YAFFS_ECC_RESULT_NO_ERROR)+			eccres = YAFFS_ECC_RESULT_FIXED;+		break;+	default:+		/* unrecovered tags-ECC error */+		dev->tagsEccUnfixed++;+		return rettags(etags, YAFFS_ECC_RESULT_UNFIXED, YAFFS_FAIL);+	}++	/* Unpack the tags to extended form and set ECC result.+	 * [set shouldBeFF just to keep yaffs_UnpackTags1 happy]+	 */+	pt1.shouldBeFF = 0xFFFFFFFF;+	yaffs_UnpackTags1(etags, &pt1);+	etags->eccResult = eccres;++	/* Set deleted state */+	etags->chunkDeleted = deleted;+	return YAFFS_OK;+}++/* Mark a block bad.+ *+ * This is a persistant state.+ * Use of this function should be rare.+ *+ * Returns YAFFS_OK or YAFFS_FAIL.+ */+int nandmtd1_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)+{+	struct mtd_info *mtd = dev->genericDevice;+	int blocksize = dev->nChunksPerBlock * dev->nDataBytesPerChunk;+	int retval;++	yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, "marking block %d bad\n", blockNo);++	retval = mtd->block_markbad(mtd, (loff_t)blocksize * blockNo);+	return (retval) ? YAFFS_FAIL : YAFFS_OK;+}++/* Check any MTD prerequists.+ *+ * Returns YAFFS_OK or YAFFS_FAIL.+ */+static int nandmtd1_TestPrerequists(struct mtd_info *mtd)+{+	/* 2.6.18 has mtd->ecclayout->oobavail */+	/* 2.6.21 has mtd->ecclayout->oobavail and mtd->oobavail */+	int oobavail = mtd->ecclayout->oobavail;++	if (oobavail < YTAG1_SIZE) {+		yaffs_trace(YAFFS_TRACE_ERROR,+			"mtd device has only %d bytes for tags, need %d\n",+			oobavail, YTAG1_SIZE);+		return YAFFS_FAIL;+	}+	return YAFFS_OK;+}++/* Query for the current state of a specific block.+ *+ * Examine the tags of the first chunk of the block and return the state:+ *  - YAFFS_BLOCK_STATE_DEAD, the block is marked bad+ *  - YAFFS_BLOCK_STATE_NEEDS_SCANNING, the block is in use+ *  - YAFFS_BLOCK_STATE_EMPTY, the block is clean+ *+ * Always returns YAFFS_OK.+ */+int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,+	yaffs_BlockState *pState, __u32 *pSequenceNumber)+{+	struct mtd_info *mtd = dev->genericDevice;+	int chunkNo = blockNo * dev->nChunksPerBlock;+	loff_t addr = (loff_t)chunkNo * dev->nDataBytesPerChunk;+	yaffs_ExtendedTags etags;+	int state = YAFFS_BLOCK_STATE_DEAD;+	int seqnum = 0;+	int retval;++	/* We don't yet have a good place to test for MTD config prerequists.+	 * Do it here as we are called during the initial scan.+	 */+	if (nandmtd1_TestPrerequists(mtd) != YAFFS_OK)+		return YAFFS_FAIL;++	retval = nandmtd1_ReadChunkWithTagsFromNAND(dev, chunkNo, NULL, &etags);+	etags.blockBad = (mtd->block_isbad)(mtd, addr);+	if (etags.blockBad) {+		yaffs_trace(YAFFS_TRACE_BAD_BLOCKS,+			"block %d is marked bad\n", blockNo);+		state = YAFFS_BLOCK_STATE_DEAD;+	} else if (etags.eccResult != YAFFS_ECC_RESULT_NO_ERROR) {+		/* bad tags, need to look more closely */+		state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;+	} else if (etags.chunkUsed) {+		state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;+		seqnum = etags.sequenceNumber;+	} else {+		state = YAFFS_BLOCK_STATE_EMPTY;+	}++	*pState = state;+	*pSequenceNumber = seqnum;++	/* query always succeeds */+	return YAFFS_OK;+}++#endif /*MTD_VERSION*/diff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_mtdif1.h linux-2.6.30/fs/yaffs2/yaffs_mtdif1.h--- linux-2.6.30.orig/fs/yaffs2/yaffs_mtdif1.h	1970-01-01 01:00:00.000000000 +0100+++ linux-2.6.30/fs/yaffs2/yaffs_mtdif1.h	2009-06-11 09:21:04.000000000 +0200@@ -0,0 +1,28 @@+/*+ * YAFFS: Yet another Flash File System. A NAND-flash specific file system.+ *+ * Copyright (C) 2002-2007 Aleph One Ltd.+ *   for Toby Churchill Ltd and Brightstar Engineering+ *+ * This program is free software; you can redistribute it and/or modify+ * it under the terms of the GNU Lesser General Public License version 2.1 as+ * published by the Free Software Foundation.+ *+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.+ */++#ifndef __YAFFS_MTDIF1_H__+#define __YAFFS_MTDIF1_H__++int nandmtd1_WriteChunkWithTagsToNAND(yaffs_Device *dev, int chunkInNAND,+	const __u8 *data, const yaffs_ExtendedTags *tags);++int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND,+	__u8 *data, yaffs_ExtendedTags *tags);++int nandmtd1_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo);++int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,+	yaffs_BlockState *state, __u32 *sequenceNumber);++#endifdiff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_mtdif2.c linux-2.6.30/fs/yaffs2/yaffs_mtdif2.c--- linux-2.6.30.orig/fs/yaffs2/yaffs_mtdif2.c	1970-01-01 01:00:00.000000000 +0100+++ linux-2.6.30/fs/yaffs2/yaffs_mtdif2.c	2009-06-11 09:21:04.000000000 +0200@@ -0,0 +1,246 @@+/*+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.+ *+ * Copyright (C) 2002-2007 Aleph One Ltd.+ *   for Toby Churchill Ltd and Brightstar Engineering+ *+ * Created by Charles Manning <charles@aleph1.co.uk>+ *+ * This program is free software; you can redistribute it and/or modify+ * it under the terms of the GNU General Public License version 2 as+ * published by the Free Software Foundation.+ */++/* mtd interface for YAFFS2 */++const char *yaffs_mtdif2_c_version =+	"$Id: yaffs_mtdif2.c,v 1.23 2009-03-06 17:20:53 wookey Exp $";++#include "yportenv.h"+++#include "yaffs_mtdif2.h"++#include "linux/mtd/mtd.h"+#include "linux/types.h"+#include "linux/time.h"++#include "yaffs_packedtags2.h"++/* NB For use with inband tags....+ * We assume that the data buffer is of size totalBytersPerChunk so that we can also+ * use it to load the tags.+ */+int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device *dev, int chunkInNAND,+				      const __u8 *data,+				      const yaffs_ExtendedTags *tags)+{+	struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);+#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))+	struct mtd_oob_ops ops;+#else+	size_t dummy;+#endif+	int retval = 0;++	loff_t addr;++	yaffs_PackedTags2 pt;++	T(YAFFS_TRACE_MTD,+	  (TSTR+	   ("nandmtd2_WriteChunkWithTagsToNAND chunk %d data %p tags %p"+	    TENDSTR), chunkInNAND, data, tags));+++	addr  = ((loff_t) chunkInNAND) * dev->totalBytesPerChunk;++	/* For yaffs2 writing there must be both data and tags.+	 * If we're using inband tags, then the tags are stuffed into+	 * the end of the data buffer.+	 */+	if (!data || !tags)+		BUG();+	else if (dev->inbandTags) {+		yaffs_PackedTags2TagsPart *pt2tp;+		pt2tp = (yaffs_PackedTags2TagsPart *)(data + dev->nDataBytesPerChunk);+		yaffs_PackTags2TagsPart(pt2tp, tags);+	} else+		yaffs_PackTags2(&pt, tags);++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))+	ops.mode = MTD_OOB_AUTO;+	ops.ooblen = (dev->inbandTags) ? 0 : sizeof(pt);+	ops.len = dev->totalBytesPerChunk;+	ops.ooboffs = 0;+	ops.datbuf = (__u8 *)data;+	ops.oobbuf = (dev->inbandTags) ? NULL : (void *)&pt;+	retval = mtd->write_oob(mtd, addr, &ops);++#else+	if (!dev->inbandTags) {+		retval =+		    mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,+				   &dummy, data, (__u8 *) &pt, NULL);+	} else {+		retval =+		    mtd->write(mtd, addr, dev->totalBytesPerChunk, &dummy,+			       data);+	}+#endif++	if (retval == 0)+		return YAFFS_OK;+	else+		return YAFFS_FAIL;+}++int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND,+				       __u8 *data, yaffs_ExtendedTags *tags)+{+	struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);+#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))+	struct mtd_oob_ops ops;+#endif+	size_t dummy;+	int retval = 0;+	int localData = 0;++	loff_t addr = ((loff_t) chunkInNAND) * dev->totalBytesPerChunk;++	yaffs_PackedTags2 pt;++	T(YAFFS_TRACE_MTD,+	  (TSTR+	   ("nandmtd2_ReadChunkWithTagsFromNAND chunk %d data %p tags %p"+	    TENDSTR), chunkInNAND, data, tags));++	if (dev->inbandTags) {++		if (!data) {+			localData = 1;+			data = yaffs_GetTempBuffer(dev, __LINE__);+		}+++	}+++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))+	if (dev->inbandTags || (data && !tags))+		retval = mtd->read(mtd, addr, dev->totalBytesPerChunk,+				&dummy, data);+	else if (tags) {+		ops.mode = MTD_OOB_AUTO;+		ops.ooblen = sizeof(pt);+		ops.len = data ? dev->nDataBytesPerChunk : sizeof(pt);+		ops.ooboffs = 0;+		ops.datbuf = data;+		ops.oobbuf = dev->spareBuffer;+		retval = mtd->read_oob(mtd, addr, &ops);+	}+#else+	if (!dev->inbandTags && data && tags) {++		retval = mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,+					  &dummy, data, dev->spareBuffer,+					  NULL);+	} else {+		if (data)+			retval =+			    mtd->read(mtd, addr, dev->nDataBytesPerChunk, &dummy,+				      data);+		if (!dev->inbandTags && tags)+			retval =+			    mtd->read_oob(mtd, addr, mtd->oobsize, &dummy,+					  dev->spareBuffer);+	}+#endif+++	if (dev->inbandTags) {+		if (tags) {+			yaffs_PackedTags2TagsPart *pt2tp;+			pt2tp = (yaffs_PackedTags2TagsPart *)&data[dev->nDataBytesPerChunk];+			yaffs_UnpackTags2TagsPart(tags, pt2tp);+		}+	} else {+		if (tags) {+			memcpy(&pt, dev->spareBuffer, sizeof(pt));+			yaffs_UnpackTags2(tags, &pt);+		}+	}++	if (localData)+		yaffs_ReleaseTempBuffer(dev, data, __LINE__);++	if (tags && retval == -EBADMSG && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR)+		tags->eccResult = YAFFS_ECC_RESULT_UNFIXED;+	if (retval == 0)+		return YAFFS_OK;+	else+		return YAFFS_FAIL;+}++int nandmtd2_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)+{+	struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);+	int retval;+	T(YAFFS_TRACE_MTD,+	  (TSTR("nandmtd2_MarkNANDBlockBad %d" TENDSTR), blockNo));++	retval =+	    mtd->block_markbad(mtd,+			       blockNo * dev->nChunksPerBlock *+			       dev->totalBytesPerChunk);++	if (retval == 0)+		return YAFFS_OK;+	else+		return YAFFS_FAIL;++}++int nandmtd2_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,+			    yaffs_BlockState *state, __u32 *sequenceNumber)+{+	struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);+	int retval;++	T(YAFFS_TRACE_MTD,+	  (TSTR("nandmtd2_QueryNANDBlock %d" TENDSTR), blockNo));+	retval =+	    mtd->block_isbad(mtd,+			     blockNo * dev->nChunksPerBlock *+			     dev->totalBytesPerChunk);++	if (retval) {+		T(YAFFS_TRACE_MTD, (TSTR("block is bad" TENDSTR)));++		*state = YAFFS_BLOCK_STATE_DEAD;+		*sequenceNumber = 0;+	} else {+		yaffs_ExtendedTags t;+		nandmtd2_ReadChunkWithTagsFromNAND(dev,+						   blockNo *+						   dev->nChunksPerBlock, NULL,+						   &t);++		if (t.chunkUsed) {+			*sequenceNumber = t.sequenceNumber;+			*state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;+		} else {+			*sequenceNumber = 0;+			*state = YAFFS_BLOCK_STATE_EMPTY;+		}+	}+	T(YAFFS_TRACE_MTD,+	  (TSTR("block is bad seq %d state %d" TENDSTR), *sequenceNumber,+	   *state));++	if (retval == 0)+		return YAFFS_OK;+	else+		return YAFFS_FAIL;+}+diff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_mtdif2.h linux-2.6.30/fs/yaffs2/yaffs_mtdif2.h--- linux-2.6.30.orig/fs/yaffs2/yaffs_mtdif2.h	1970-01-01 01:00:00.000000000 +0100+++ linux-2.6.30/fs/yaffs2/yaffs_mtdif2.h	2009-06-11 09:21:04.000000000 +0200@@ -0,0 +1,29 @@+/*+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.+ *+ * Copyright (C) 2002-2007 Aleph One Ltd.+ *   for Toby Churchill Ltd and Brightstar Engineering+ *+ * Created by Charles Manning <charles@aleph1.co.uk>+ *+ * This program is free software; you can redistribute it and/or modify+ * it under the terms of the GNU Lesser General Public License version 2.1 as+ * published by the Free Software Foundation.+ *+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.+ */++#ifndef __YAFFS_MTDIF2_H__+#define __YAFFS_MTDIF2_H__++#include "yaffs_guts.h"+int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device *dev, int chunkInNAND,+				const __u8 *data,+				const yaffs_ExtendedTags *tags);+int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND,+				__u8 *data, yaffs_ExtendedTags *tags);+int nandmtd2_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo);+int nandmtd2_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,+			yaffs_BlockState *state, __u32 *sequenceNumber);++#endifdiff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_mtdif.c linux-2.6.30/fs/yaffs2/yaffs_mtdif.c--- linux-2.6.30.orig/fs/yaffs2/yaffs_mtdif.c	1970-01-01 01:00:00.000000000 +0100+++ linux-2.6.30/fs/yaffs2/yaffs_mtdif.c	2009-06-11 09:21:04.000000000 +0200@@ -0,0 +1,241 @@+/*+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.+ *+ * Copyright (C) 2002-2007 Aleph One Ltd.+ *   for Toby Churchill Ltd and Brightstar Engineering+ *+ * Created by Charles Manning <charles@aleph1.co.uk>+ *+ * This program is free software; you can redistribute it and/or modify+ * it under the terms of the GNU General Public License version 2 as+ * published by the Free Software Foundation.+ */++const char *yaffs_mtdif_c_version =+	"$Id: yaffs_mtdif.c,v 1.22 2009-03-06 17:20:51 wookey Exp $";++#include "yportenv.h"+++#include "yaffs_mtdif.h"++#include "linux/mtd/mtd.h"+#include "linux/types.h"+#include "linux/time.h"+#include "linux/mtd/nand.h"++#if (MTD_VERSION_CODE < MTD_VERSION(2, 6, 18))+static struct nand_oobinfo yaffs_oobinfo = {+	.useecc = 1,+	.eccbytes = 6,+	.eccpos = {8, 9, 10, 13, 14, 15}+};++static struct nand_oobinfo yaffs_noeccinfo = {+	.useecc = 0,+};+#endif++#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))+static inline void translate_spare2oob(const yaffs_Spare *spare, __u8 *oob)+{+	oob[0] = spare->tagByte0;+	oob[1] = spare->tagByte1;+	oob[2] = spare->tagByte2;+	oob[3] = spare->tagByte3;+	oob[4] = spare->tagByte4;+	oob[5] = spare->tagByte5 & 0x3f;+	oob[5] |= spare->blockStatus == 'Y' ? 0 : 0x80;+	oob[5] |= spare->pageStatus == 0 ? 0 : 0x40;+	oob[6] = spare->tagByte6;+	oob[7] = spare->tagByte7;+}++static inline void translate_oob2spare(yaffs_Spare *spare, __u8 *oob)+{+	struct yaffs_NANDSpare *nspare = (struct yaffs_NANDSpare *)spare;+	spare->tagByte0 = oob[0];+	spare->tagByte1 = oob[1];+	spare->tagByte2 = oob[2];+	spare->tagByte3 = oob[3];+	spare->tagByte4 = oob[4];+	spare->tagByte5 = oob[5] == 0xff ? 0xff : oob[5] & 0x3f;+	spare->blockStatus = oob[5] & 0x80 ? 0xff : 'Y';+	spare->pageStatus = oob[5] & 0x40 ? 0xff : 0;+	spare->ecc1[0] = spare->ecc1[1] = spare->ecc1[2] = 0xff;+	spare->tagByte6 = oob[6];+	spare->tagByte7 = oob[7];+	spare->ecc2[0] = spare->ecc2[1] = spare->ecc2[2] = 0xff;++	nspare->eccres1 = nspare->eccres2 = 0; /* FIXME */+}+#endif++int nandmtd_WriteChunkToNAND(yaffs_Device *dev, int chunkInNAND,+			     const __u8 *data, const yaffs_Spare *spare)+{+	struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);+#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))+	struct mtd_oob_ops ops;+#endif+	size_t dummy;+	int retval = 0;++	loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk;+#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))+	__u8 spareAsBytes[8]; /* OOB */++	if (data && !spare)+		retval = mtd->write(mtd, addr, dev->nDataBytesPerChunk,+				&dummy, data);+	else if (spare) {+		if (dev->useNANDECC) {+			translate_spare2oob(spare, spareAsBytes);+			ops.mode = MTD_OOB_AUTO;+			ops.ooblen = 8; /* temp hack */+		} else {+			ops.mode = MTD_OOB_RAW;+			ops.ooblen = YAFFS_BYTES_PER_SPARE;+		}+		ops.len = data ? dev->nDataBytesPerChunk : ops.ooblen;+		ops.datbuf = (u8 *)data;+		ops.ooboffs = 0;+		ops.oobbuf = spareAsBytes;+		retval = mtd->write_oob(mtd, addr, &ops);+	}+#else+	__u8 *spareAsBytes = (__u8 *) spare;++	if (data && spare) {+		if (dev->useNANDECC)+			retval =+			    mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,+					   &dummy, data, spareAsBytes,+					   &yaffs_oobinfo);+		else+			retval =+			    mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,+					   &dummy, data, spareAsBytes,+					   &yaffs_noeccinfo);+	} else {+		if (data)+			retval =+			    mtd->write(mtd, addr, dev->nDataBytesPerChunk, &dummy,+				       data);+		if (spare)+			retval =+			    mtd->write_oob(mtd, addr, YAFFS_BYTES_PER_SPARE,+					   &dummy, spareAsBytes);+	}+#endif++	if (retval == 0)+		return YAFFS_OK;+	else+		return YAFFS_FAIL;+}++int nandmtd_ReadChunkFromNAND(yaffs_Device *dev, int chunkInNAND, __u8 *data,+			      yaffs_Spare *spare)+{+	struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);+#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))+	struct mtd_oob_ops ops;+#endif+	size_t dummy;+	int retval = 0;++	loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk;+#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))+	__u8 spareAsBytes[8]; /* OOB */++	if (data && !spare)+		retval = mtd->read(mtd, addr, dev->nDataBytesPerChunk,+				&dummy, data);+	else if (spare) {+		if (dev->useNANDECC) {+			ops.mode = MTD_OOB_AUTO;+			ops.ooblen = 8; /* temp hack */+		} else {+			ops.mode = MTD_OOB_RAW;+			ops.ooblen = YAFFS_BYTES_PER_SPARE;+		}+		ops.len = data ? dev->nDataBytesPerChunk : ops.ooblen;+		ops.datbuf = data;+		ops.ooboffs = 0;+		ops.oobbuf = spareAsBytes;+		retval = mtd->read_oob(mtd, addr, &ops);+		if (dev->useNANDECC)+			translate_oob2spare(spare, spareAsBytes);+	}+#else+	__u8 *spareAsBytes = (__u8 *) spare;++	if (data && spare) {+		if (dev->useNANDECC) {+			/* Careful, this call adds 2 ints */+			/* to the end of the spare data.  Calling function */+			/* should allocate enough memory for spare, */+			/* i.e. [YAFFS_BYTES_PER_SPARE+2*sizeof(int)]. */+			retval =+			    mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,+					  &dummy, data, spareAsBytes,+					  &yaffs_oobinfo);+		} else {+			retval =+			    mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,+					  &dummy, data, spareAsBytes,+					  &yaffs_noeccinfo);+		}+	} else {+		if (data)+			retval =+			    mtd->read(mtd, addr, dev->nDataBytesPerChunk, &dummy,+				      data);+		if (spare)+			retval =+			    mtd->read_oob(mtd, addr, YAFFS_BYTES_PER_SPARE,+					  &dummy, spareAsBytes);+	}+#endif++	if (retval == 0)+		return YAFFS_OK;+	else+		return YAFFS_FAIL;+}++int nandmtd_EraseBlockInNAND(yaffs_Device *dev, int blockNumber)+{+	struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);+	__u32 addr =+	    ((loff_t) blockNumber) * dev->nDataBytesPerChunk+		* dev->nChunksPerBlock;+	struct erase_info ei;+	int retval = 0;++	ei.mtd = mtd;+	ei.addr = addr;+	ei.len = dev->nDataBytesPerChunk * dev->nChunksPerBlock;+	ei.time = 1000;+	ei.retries = 2;+	ei.callback = NULL;+	ei.priv = (u_long) dev;++	/* Todo finish off the ei if required */++	sema_init(&dev->sem, 0);++	retval = mtd->erase(mtd, &ei);++	if (retval == 0)+		return YAFFS_OK;+	else+		return YAFFS_FAIL;+}++int nandmtd_InitialiseNAND(yaffs_Device *dev)+{+	return YAFFS_OK;+}+diff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_mtdif.h linux-2.6.30/fs/yaffs2/yaffs_mtdif.h--- linux-2.6.30.orig/fs/yaffs2/yaffs_mtdif.h	1970-01-01 01:00:00.000000000 +0100+++ linux-2.6.30/fs/yaffs2/yaffs_mtdif.h	2009-06-11 09:21:04.000000000 +0200@@ -0,0 +1,32 @@+/*+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.+ *+ * Copyright (C) 2002-2007 Aleph One Ltd.+ *   for Toby Churchill Ltd and Brightstar Engineering+ *+ * Created by Charles Manning <charles@aleph1.co.uk>+ *+ * This program is free software; you can redistribute it and/or modify+ * it under the terms of the GNU Lesser General Public License version 2.1 as+ * published by the Free Software Foundation.+ *+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.+ */++#ifndef __YAFFS_MTDIF_H__+#define __YAFFS_MTDIF_H__++#include "yaffs_guts.h"++#if (MTD_VERSION_CODE < MTD_VERSION(2, 6, 18))+extern struct nand_oobinfo yaffs_oobinfo;+extern struct nand_oobinfo yaffs_noeccinfo;+#endif++int nandmtd_WriteChunkToNAND(yaffs_Device *dev, int chunkInNAND,+			const __u8 *data, const yaffs_Spare *spare);+int nandmtd_ReadChunkFromNAND(yaffs_Device *dev, int chunkInNAND, __u8 *data,+			yaffs_Spare *spare);+int nandmtd_EraseBlockInNAND(yaffs_Device *dev, int blockNumber);+int nandmtd_InitialiseNAND(yaffs_Device *dev);+#endifdiff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_nand.c linux-2.6.30/fs/yaffs2/yaffs_nand.c--- linux-2.6.30.orig/fs/yaffs2/yaffs_nand.c	1970-01-01 01:00:00.000000000 +0100+++ linux-2.6.30/fs/yaffs2/yaffs_nand.c	2009-06-11 09:21:04.000000000 +0200@@ -0,0 +1,135 @@+/*+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.+ *+ * Copyright (C) 2002-2007 Aleph One Ltd.+ *   for Toby Churchill Ltd and Brightstar Engineering+ *+ * Created by Charles Manning <charles@aleph1.co.uk>+ *+ * This program is free software; you can redistribute it and/or modify+ * it under the terms of the GNU General Public License version 2 as+ * published by the Free Software Foundation.+ */++const char *yaffs_nand_c_version =+	"$Id: yaffs_nand.c,v 1.10 2009-03-06 17:20:54 wookey Exp $";++#include "yaffs_nand.h"+#include "yaffs_tagscompat.h"+#include "yaffs_tagsvalidity.h"++#include "yaffs_getblockinfo.h"++int yaffs_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND,+					   __u8 *buffer,+					   yaffs_ExtendedTags *tags)+{+	int result;+	yaffs_ExtendedTags localTags;++	int realignedChunkInNAND = chunkInNAND - dev->chunkOffset;++	/* If there are no tags provided, use local tags to get prioritised gc working */+	if (!tags)+		tags = &localTags;++	if (dev->readChunkWithTagsFromNAND)+		result = dev->readChunkWithTagsFromNAND(dev, realignedChunkInNAND, buffer,+						      tags);+	else+		result = yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(dev,+									realignedChunkInNAND,+									buffer,+									tags);+	if (tags &&+	   tags->eccResult > YAFFS_ECC_RESULT_NO_ERROR) {++		yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, chunkInNAND/dev->nChunksPerBlock);+		yaffs_HandleChunkError(dev, bi);+	}++	return result;+}++int yaffs_WriteChunkWithTagsToNAND(yaffs_Device *dev,+						   int chunkInNAND,+						   const __u8 *buffer,+						   yaffs_ExtendedTags *tags)+{+	chunkInNAND -= dev->chunkOffset;+++	if (tags) {+		tags->sequenceNumber = dev->sequenceNumber;+		tags->chunkUsed = 1;+		if (!yaffs_ValidateTags(tags)) {+			T(YAFFS_TRACE_ERROR,+			  (TSTR("Writing uninitialised tags" TENDSTR)));+			YBUG();+		}+		T(YAFFS_TRACE_WRITE,+		  (TSTR("Writing chunk %d tags %d %d" TENDSTR), chunkInNAND,+		   tags->objectId, tags->chunkId));+	} else {+		T(YAFFS_TRACE_ERROR, (TSTR("Writing with no tags" TENDSTR)));+		YBUG();+	}++	if (dev->writeChunkWithTagsToNAND)+		return dev->writeChunkWithTagsToNAND(dev, chunkInNAND, buffer,+						     tags);+	else+		return yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(dev,+								       chunkInNAND,+								       buffer,+								       tags);+}++int yaffs_MarkBlockBad(yaffs_Device *dev, int blockNo)+{+	blockNo -= dev->blockOffset;++;+	if (dev->markNANDBlockBad)+		return dev->markNANDBlockBad(dev, blockNo);+	else+		return yaffs_TagsCompatabilityMarkNANDBlockBad(dev, blockNo);+}++int yaffs_QueryInitialBlockState(yaffs_Device *dev,+						 int blockNo,+						 yaffs_BlockState *state,+						 __u32 *sequenceNumber)+{+	blockNo -= dev->blockOffset;++	if (dev->queryNANDBlock)+		return dev->queryNANDBlock(dev, blockNo, state, sequenceNumber);+	else+		return yaffs_TagsCompatabilityQueryNANDBlock(dev, blockNo,+							     state,+							     sequenceNumber);+}+++int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,+				  int blockInNAND)+{+	int result;++	blockInNAND -= dev->blockOffset;+++	dev->nBlockErasures++;+	result = dev->eraseBlockInNAND(dev, blockInNAND);++	return result;+}++int yaffs_InitialiseNAND(struct yaffs_DeviceStruct *dev)+{+	return dev->initialiseNAND(dev);+}+++diff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_nandemul2k.h linux-2.6.30/fs/yaffs2/yaffs_nandemul2k.h--- linux-2.6.30.orig/fs/yaffs2/yaffs_nandemul2k.h	1970-01-01 01:00:00.000000000 +0100+++ linux-2.6.30/fs/yaffs2/yaffs_nandemul2k.h	2009-06-11 09:21:04.000000000 +0200@@ -0,0 +1,39 @@+/*+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.+ *+ * Copyright (C) 2002-2007 Aleph One Ltd.+ *   for Toby Churchill Ltd and Brightstar Engineering+ *+ * Created by Charles Manning <charles@aleph1.co.uk>+ *+ * This program is free software; you can redistribute it and/or modify+ * it under the terms of the GNU Lesser General Public License version 2.1 as+ * published by the Free Software Foundation.+ *+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.+ */++/* Interface to emulated NAND functions (2k page size) */++#ifndef __YAFFS_NANDEMUL2K_H__+#define __YAFFS_NANDEMUL2K_H__++#include "yaffs_guts.h"++int nandemul2k_WriteChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev,+					int chunkInNAND, const __u8 *data,+					const yaffs_ExtendedTags *tags);+int nandemul2k_ReadChunkWithTagsFromNAND(struct yaffs_DeviceStruct *dev,+					 int chunkInNAND, __u8 *data,+					 yaffs_ExtendedTags *tags);+int nandemul2k_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo);+int nandemul2k_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,+			      yaffs_BlockState *state, __u32 *sequenceNumber);+int nandemul2k_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,+				int blockInNAND);+int nandemul2k_InitialiseNAND(struct yaffs_DeviceStruct *dev);+int nandemul2k_GetBytesPerChunk(void);+int nandemul2k_GetChunksPerBlock(void);+int nandemul2k_GetNumberOfBlocks(void);++#endifdiff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_nand.h linux-2.6.30/fs/yaffs2/yaffs_nand.h--- linux-2.6.30.orig/fs/yaffs2/yaffs_nand.h	1970-01-01 01:00:00.000000000 +0100+++ linux-2.6.30/fs/yaffs2/yaffs_nand.h	2009-06-11 09:21:04.000000000 +0200@@ -0,0 +1,44 @@+/*+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.+ *+ * Copyright (C) 2002-2007 Aleph One Ltd.+ *   for Toby Churchill Ltd and Brightstar Engineering+ *+ * Created by Charles Manning <charles@aleph1.co.uk>+ *+ * This program is free software; you can redistribute it and/or modify+ * it under the terms of the GNU Lesser General Public License version 2.1 as+ * published by the Free Software Foundation.+ *+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.+ */++#ifndef __YAFFS_NAND_H__+#define __YAFFS_NAND_H__+#include "yaffs_guts.h"++++int yaffs_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND,+					__u8 *buffer,+					yaffs_ExtendedTags *tags);++int yaffs_WriteChunkWithTagsToNAND(yaffs_Device *dev,+						int chunkInNAND,+						const __u8 *buffer,+						yaffs_ExtendedTags *tags);++int yaffs_MarkBlockBad(yaffs_Device *dev, int blockNo);++int yaffs_QueryInitialBlockState(yaffs_Device *dev,+						int blockNo,+						yaffs_BlockState *state,+						unsigned *sequenceNumber);++int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,+				  int blockInNAND);++int yaffs_InitialiseNAND(struct yaffs_DeviceStruct *dev);++#endif+diff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_packedtags1.c linux-2.6.30/fs/yaffs2/yaffs_packedtags1.c--- linux-2.6.30.orig/fs/yaffs2/yaffs_packedtags1.c	1970-01-01 01:00:00.000000000 +0100+++ linux-2.6.30/fs/yaffs2/yaffs_packedtags1.c	2009-06-11 09:21:04.000000000 +0200@@ -0,0 +1,50 @@+/*+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.+ *+ * Copyright (C) 2002-2007 Aleph One Ltd.+ *   for Toby Churchill Ltd and Brightstar Engineering+ *+ * Created by Charles Manning <charles@aleph1.co.uk>+ *+ * This program is free software; you can redistribute it and/or modify+ * it under the terms of the GNU General Public License version 2 as+ * published by the Free Software Foundation.+ */++#include "yaffs_packedtags1.h"+#include "yportenv.h"++void yaffs_PackTags1(yaffs_PackedTags1 *pt, const yaffs_ExtendedTags *t)+{+	pt->chunkId = t->chunkId;+	pt->serialNumber = t->serialNumber;+	pt->byteCount = t->byteCount;+	pt->objectId = t->objectId;+	pt->ecc = 0;+	pt->deleted = (t->chunkDeleted) ? 0 : 1;+	pt->unusedStuff = 0;+	pt->shouldBeFF = 0xFFFFFFFF;++}++void yaffs_UnpackTags1(yaffs_ExtendedTags *t, const yaffs_PackedTags1 *pt)+{+	static const __u8 allFF[] =+	    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,+0xff };++	if (memcmp(allFF, pt, sizeof(yaffs_PackedTags1))) {+		t->blockBad = 0;+		if (pt->shouldBeFF != 0xFFFFFFFF)+			t->blockBad = 1;+		t->chunkUsed = 1;+		t->objectId = pt->objectId;+		t->chunkId = pt->chunkId;+		t->byteCount = pt->byteCount;+		t->eccResult = YAFFS_ECC_RESULT_NO_ERROR;+		t->chunkDeleted = (pt->deleted) ? 0 : 1;+		t->serialNumber = pt->serialNumber;+	} else {+		memset(t, 0, sizeof(yaffs_ExtendedTags));+	}+}diff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_packedtags1.h linux-2.6.30/fs/yaffs2/yaffs_packedtags1.h--- linux-2.6.30.orig/fs/yaffs2/yaffs_packedtags1.h	1970-01-01 01:00:00.000000000 +0100+++ linux-2.6.30/fs/yaffs2/yaffs_packedtags1.h	2009-06-11 09:21:04.000000000 +0200@@ -0,0 +1,37 @@+/*+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.+ *+ * Copyright (C) 2002-2007 Aleph One Ltd.+ *   for Toby Churchill Ltd and Brightstar Engineering+ *+ * Created by Charles Manning <charles@aleph1.co.uk>+ *+ * This program is free software; you can redistribute it and/or modify+ * it under the terms of the GNU Lesser General Public License version 2.1 as+ * published by the Free Software Foundation.+ *+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.+ */++/* This is used to pack YAFFS1 tags, not YAFFS2 tags. */++#ifndef __YAFFS_PACKEDTAGS1_H__+#define __YAFFS_PACKEDTAGS1_H__++#include "yaffs_guts.h"++typedef struct {+	unsigned chunkId:20;+	unsigned serialNumber:2;+	unsigned byteCount:10;+	unsigned objectId:18;+	unsigned ecc:12;+	unsigned deleted:1;+	unsigned unusedStuff:1;+	unsigned shouldBeFF;++} yaffs_PackedTags1;++void yaffs_PackTags1(yaffs_PackedTags1 *pt, const yaffs_ExtendedTags *t);+void yaffs_UnpackTags1(yaffs_ExtendedTags *t, const yaffs_PackedTags1 *pt);+#endifdiff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_packedtags2.c linux-2.6.30/fs/yaffs2/yaffs_packedtags2.c--- linux-2.6.30.orig/fs/yaffs2/yaffs_packedtags2.c	1970-01-01 01:00:00.000000000 +0100+++ linux-2.6.30/fs/yaffs2/yaffs_packedtags2.c	2009-06-11 09:21:04.000000000 +0200@@ -0,0 +1,206 @@+/*+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.+ *+ * Copyright (C) 2002-2007 Aleph One Ltd.+ *   for Toby Churchill Ltd and Brightstar Engineering+ *+ * Created by Charles Manning <charles@aleph1.co.uk>+ *+ * This program is free software; you can redistribute it and/or modify+ * it under the terms of the GNU General Public License version 2 as+ * published by the Free Software Foundation.+ */++#include "yaffs_packedtags2.h"+#include "yportenv.h"+#include "yaffs_tagsvalidity.h"++/* This code packs a set of extended tags into a binary structure for+ * NAND storage+ */++/* Some of the information is "extra" struff which can be packed in to+ * speed scanning+ * This is defined by having the EXTRA_HEADER_INFO_FLAG set.+ */++/* Extra flags applied to chunkId */++#define EXTRA_HEADER_INFO_FLAG	0x80000000+#define EXTRA_SHRINK_FLAG	0x40000000+#define EXTRA_SHADOWS_FLAG	0x20000000+#define EXTRA_SPARE_FLAGS	0x10000000++#define ALL_EXTRA_FLAGS		0xF0000000++/* Also, the top 4 bits of the object Id are set to the object type. */+#define EXTRA_OBJECT_TYPE_SHIFT (28)+#define EXTRA_OBJECT_TYPE_MASK  ((0x0F) << EXTRA_OBJECT_TYPE_SHIFT)+++static void yaffs_DumpPackedTags2TagsPart(const yaffs_PackedTags2TagsPart *ptt)+{+	T(YAFFS_TRACE_MTD,+	  (TSTR("packed tags obj %d chunk %d byte %d seq %d" TENDSTR),+	   ptt->objectId, ptt->chunkId, ptt->byteCount,+	   ptt->sequenceNumber));+}+static void yaffs_DumpPackedTags2(const yaffs_PackedTags2 *pt)+{+	yaffs_DumpPackedTags2TagsPart(&pt->t);+}++static void yaffs_DumpTags2(const yaffs_ExtendedTags *t)+{+	T(YAFFS_TRACE_MTD,+	  (TSTR+	   ("ext.tags eccres %d blkbad %d chused %d obj %d chunk%d byte %d del %d ser %d seq %d"+	    TENDSTR), t->eccResult, t->blockBad, t->chunkUsed, t->objectId,+	   t->chunkId, t->byteCount, t->chunkDeleted, t->serialNumber,+	   t->sequenceNumber));++}++void yaffs_PackTags2TagsPart(yaffs_PackedTags2TagsPart *ptt,+		const yaffs_ExtendedTags *t)+{+	ptt->chunkId = t->chunkId;+	ptt->sequenceNumber = t->sequenceNumber;+	ptt->byteCount = t->byteCount;+	ptt->objectId = t->objectId;++	if (t->chunkId == 0 && t->extraHeaderInfoAvailable) {+		/* Store the extra header info instead */+		/* We save the parent object in the chunkId */+		ptt->chunkId = EXTRA_HEADER_INFO_FLAG+			| t->extraParentObjectId;+		if (t->extraIsShrinkHeader)+			ptt->chunkId |= EXTRA_SHRINK_FLAG;+		if (t->extraShadows)+			ptt->chunkId |= EXTRA_SHADOWS_FLAG;++		ptt->objectId &= ~EXTRA_OBJECT_TYPE_MASK;+		ptt->objectId |=+		    (t->extraObjectType << EXTRA_OBJECT_TYPE_SHIFT);++		if (t->extraObjectType == YAFFS_OBJECT_TYPE_HARDLINK)+			ptt->byteCount = t->extraEquivalentObjectId;+		else if (t->extraObjectType == YAFFS_OBJECT_TYPE_FILE)+			ptt->byteCount = t->extraFileLength;+		else+			ptt->byteCount = 0;+	}++	yaffs_DumpPackedTags2TagsPart(ptt);+	yaffs_DumpTags2(t);+}+++void yaffs_PackTags2(yaffs_PackedTags2 *pt, const yaffs_ExtendedTags *t)+{+	yaffs_PackTags2TagsPart(&pt->t, t);++#ifndef YAFFS_IGNORE_TAGS_ECC+	{+		yaffs_ECCCalculateOther((unsigned char *)&pt->t,+					sizeof(yaffs_PackedTags2TagsPart),+					&pt->ecc);+	}+#endif+}+++void yaffs_UnpackTags2TagsPart(yaffs_ExtendedTags *t,+		yaffs_PackedTags2TagsPart *ptt)+{++	memset(t, 0, sizeof(yaffs_ExtendedTags));++	yaffs_InitialiseTags(t);++	if (ptt->sequenceNumber != 0xFFFFFFFF) {+		t->blockBad = 0;+		t->chunkUsed = 1;+		t->objectId = ptt->objectId;+		t->chunkId = ptt->chunkId;+		t->byteCount = ptt->byteCount;+		t->chunkDeleted = 0;+		t->serialNumber = 0;+		t->sequenceNumber = ptt->sequenceNumber;++		/* Do extra header info stuff */++		if (ptt->chunkId & EXTRA_HEADER_INFO_FLAG) {+			t->chunkId = 0;+			t->byteCount = 0;++			t->extraHeaderInfoAvailable = 1;+			t->extraParentObjectId =+			    ptt->chunkId & (~(ALL_EXTRA_FLAGS));+			t->extraIsShrinkHeader =+			    (ptt->chunkId & EXTRA_SHRINK_FLAG) ? 1 : 0;+			t->extraShadows =+			    (ptt->chunkId & EXTRA_SHADOWS_FLAG) ? 1 : 0;+			t->extraObjectType =+			    ptt->objectId >> EXTRA_OBJECT_TYPE_SHIFT;+			t->objectId &= ~EXTRA_OBJECT_TYPE_MASK;++			if (t->extraObjectType == YAFFS_OBJECT_TYPE_HARDLINK)+				t->extraEquivalentObjectId = ptt->byteCount;+			else+				t->extraFileLength = ptt->byteCount;+		}+	}++	yaffs_DumpPackedTags2TagsPart(ptt);+	yaffs_DumpTags2(t);++}+++void yaffs_UnpackTags2(yaffs_ExtendedTags *t, yaffs_PackedTags2 *pt)+{++	yaffs_ECCResult eccResult = YAFFS_ECC_RESULT_NO_ERROR;++	if (pt->t.sequenceNumber != 0xFFFFFFFF) {+		/* Page is in use */+#ifndef YAFFS_IGNORE_TAGS_ECC+		{+			yaffs_ECCOther ecc;+			int result;+			yaffs_ECCCalculateOther((unsigned char *)&pt->t,+						sizeof+						(yaffs_PackedTags2TagsPart),+						&ecc);+			result =+			    yaffs_ECCCorrectOther((unsigned char *)&pt->t,+						  sizeof+						  (yaffs_PackedTags2TagsPart),+						  &pt->ecc, &ecc);+			switch (result) {+			case 0:+				eccResult = YAFFS_ECC_RESULT_NO_ERROR;+				break;+			case 1:+				eccResult = YAFFS_ECC_RESULT_FIXED;+				break;+			case -1:+				eccResult = YAFFS_ECC_RESULT_UNFIXED;+				break;+			default:+				eccResult = YAFFS_ECC_RESULT_UNKNOWN;+			}+		}+#endif+	}++	yaffs_UnpackTags2TagsPart(t, &pt->t);++	t->eccResult = eccResult;++	yaffs_DumpPackedTags2(pt);+	yaffs_DumpTags2(t);++}+diff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_packedtags2.h linux-2.6.30/fs/yaffs2/yaffs_packedtags2.h--- linux-2.6.30.orig/fs/yaffs2/yaffs_packedtags2.h	1970-01-01 01:00:00.000000000 +0100+++ linux-2.6.30/fs/yaffs2/yaffs_packedtags2.h	2009-06-11 09:21:04.000000000 +0200@@ -0,0 +1,43 @@+/*+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.+ *+ * Copyright (C) 2002-2007 Aleph One Ltd.+ *   for Toby Churchill Ltd and Brightstar Engineering+ *+ * Created by Charles Manning <charles@aleph1.co.uk>+ *+ * This program is free software; you can redistribute it and/or modify+ * it under the terms of the GNU Lesser General Public License version 2.1 as+ * published by the Free Software Foundation.+ *+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.+ */++/* This is used to pack YAFFS2 tags, not YAFFS1tags. */++#ifndef __YAFFS_PACKEDTAGS2_H__+#define __YAFFS_PACKEDTAGS2_H__++#include "yaffs_guts.h"+#include "yaffs_ecc.h"++typedef struct {+	unsigned sequenceNumber;+	unsigned objectId;+	unsigned chunkId;+	unsigned byteCount;+} yaffs_PackedTags2TagsPart;++typedef struct {+	yaffs_PackedTags2TagsPart t;+	yaffs_ECCOther ecc;+} yaffs_PackedTags2;++/* Full packed tags with ECC, used for oob tags */+void yaffs_PackTags2(yaffs_PackedTags2 *pt, const yaffs_ExtendedTags *t);+void yaffs_UnpackTags2(yaffs_ExtendedTags *t, yaffs_PackedTags2 *pt);++/* Only the tags part (no ECC for use with inband tags */+void yaffs_PackTags2TagsPart(yaffs_PackedTags2TagsPart *pt, const yaffs_ExtendedTags *t);+void yaffs_UnpackTags2TagsPart(yaffs_ExtendedTags *t, yaffs_PackedTags2TagsPart *pt);+#endifdiff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_qsort.c linux-2.6.30/fs/yaffs2/yaffs_qsort.c--- linux-2.6.30.orig/fs/yaffs2/yaffs_qsort.c	1970-01-01 01:00:00.000000000 +0100+++ linux-2.6.30/fs/yaffs2/yaffs_qsort.c	2009-06-11 09:21:04.000000000 +0200@@ -0,0 +1,163 @@+/*+ * Copyright (c) 1992, 1993+ *	The Regents of the University of California.  All rights reserved.+ *+ * Redistribution and use in source and binary forms, with or without+ * modification, are permitted provided that the following conditions+ * are met:+ * 1. Redistributions of source code must retain the above copyright+ *    notice, this list of conditions and the following disclaimer.+ * 2. Redistributions in binary form must reproduce the above copyright+ *    notice, this list of conditions and the following disclaimer in the+ *    documentation and/or other materials provided with the distribution.+ * 3. Neither the name of the University nor the names of its contributors+ *    may be used to endorse or promote products derived from this software+ *    without specific prior written permission.+ *+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF+ * SUCH DAMAGE.+ */++#include "yportenv.h"+/* #include <linux/string.h> */++/*+ * Qsort routine from Bentley & McIlroy's "Engineering a Sort Function".+ */+#define swapcode(TYPE, parmi, parmj, n) do { 		\+	long i = (n) / sizeof (TYPE); 			\+	register TYPE *pi = (TYPE *) (parmi); 		\+	register TYPE *pj = (TYPE *) (parmj); 		\+	do { 						\+		register TYPE	t = *pi;		\+		*pi++ = *pj;				\+		*pj++ = t;				\+	} while (--i > 0);				\+} while (0)++#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \+	es % sizeof(long) ? 2 : es == sizeof(long) ? 0 : 1;++static __inline void+swapfunc(char *a, char *b, int n, int swaptype)+{+	if (swaptype <= 1)+		swapcode(long, a, b, n);+	else+		swapcode(char, a, b, n);+}++#define yswap(a, b) do {					\+	if (swaptype == 0) {				\+		long t = *(long *)(a);			\+		*(long *)(a) = *(long *)(b);		\+		*(long *)(b) = t;			\+	} else						\+		swapfunc(a, b, es, swaptype);		\+} while (0)++#define vecswap(a, b, n) 	if ((n) > 0) swapfunc(a, b, n, swaptype)++static __inline char *+med3(char *a, char *b, char *c, int (*cmp)(const void *, const void *))+{+	return cmp(a, b) < 0 ?+		(cmp(b, c) < 0 ? b : (cmp(a, c) < 0 ? c : a))+		: (cmp(b, c) > 0 ? b : (cmp(a, c) < 0 ? a : c));+}++#ifndef min+#define min(a, b) (((a) < (b)) ? (a) : (b))+#endif++void+yaffs_qsort(void *aa, size_t n, size_t es,+	int (*cmp)(const void *, const void *))+{+	char *pa, *pb, *pc, *pd, *pl, *pm, *pn;+	int d, r, swaptype, swap_cnt;+	register char *a = aa;++loop:	SWAPINIT(a, es);+	swap_cnt = 0;+	if (n < 7) {+		for (pm = (char *)a + es; pm < (char *) a + n * es; pm += es)+			for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0;+			     pl -= es)+				yswap(pl, pl - es);+		return;+	}+	pm = (char *)a + (n / 2) * es;+	if (n > 7) {+		pl = (char *)a;+		pn = (char *)a + (n - 1) * es;+		if (n > 40) {+			d = (n / 8) * es;+			pl = med3(pl, pl + d, pl + 2 * d, cmp);+			pm = med3(pm - d, pm, pm + d, cmp);+			pn = med3(pn - 2 * d, pn - d, pn, cmp);+		}+		pm = med3(pl, pm, pn, cmp);+	}+	yswap(a, pm);+	pa = pb = (char *)a + es;++	pc = pd = (char *)a + (n - 1) * es;+	for (;;) {+		while (pb <= pc && (r = cmp(pb, a)) <= 0) {+			if (r == 0) {+				swap_cnt = 1;+				yswap(pa, pb);+				pa += es;+			}+			pb += es;+		}+		while (pb <= pc && (r = cmp(pc, a)) >= 0) {+			if (r == 0) {+				swap_cnt = 1;+				yswap(pc, pd);+				pd -= es;+			}+			pc -= es;+		}+		if (pb > pc)+			break;+		yswap(pb, pc);+		swap_cnt = 1;+		pb += es;+		pc -= es;+	}+	if (swap_cnt == 0) {  /* Switch to insertion sort */+		for (pm = (char *) a + es; pm < (char *) a + n * es; pm += es)+			for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0;+			     pl -= es)+				yswap(pl, pl - es);+		return;+	}++	pn = (char *)a + n * es;+	r = min(pa - (char *)a, pb - pa);+	vecswap(a, pb - r, r);+	r = min((long)(pd - pc), (long)(pn - pd - es));+	vecswap(pb, pn - r, r);+	r = pb - pa;+	if (r > es)+		yaffs_qsort(a, r / es, es, cmp);+	r = pd - pc;+	if (r > es) {+		/* Iterate rather than recurse to save stack space */+		a = pn - r;+		n = r / es;+		goto loop;+	}+/*		yaffs_qsort(pn - r, r / es, es, cmp);*/+}diff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_qsort.h linux-2.6.30/fs/yaffs2/yaffs_qsort.h--- linux-2.6.30.orig/fs/yaffs2/yaffs_qsort.h	1970-01-01 01:00:00.000000000 +0100+++ linux-2.6.30/fs/yaffs2/yaffs_qsort.h	2009-06-11 09:21:04.000000000 +0200@@ -0,0 +1,23 @@+/*+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.+ *+ * Copyright (C) 2002-2007 Aleph One Ltd.+ *   for Toby Churchill Ltd and Brightstar Engineering+ *+ * Created by Charles Manning <charles@aleph1.co.uk>+ *+ * This program is free software; you can redistribute it and/or modify+ * it under the terms of the GNU Lesser General Public License version 2.1 as+ * published by the Free Software Foundation.+ *+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.+ */+++#ifndef __YAFFS_QSORT_H__+#define __YAFFS_QSORT_H__++extern void yaffs_qsort(void *const base, size_t total_elems, size_t size,+			int (*cmp)(const void *, const void *));++#endifdiff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_tagscompat.c linux-2.6.30/fs/yaffs2/yaffs_tagscompat.c--- linux-2.6.30.orig/fs/yaffs2/yaffs_tagscompat.c	1970-01-01 01:00:00.000000000 +0100+++ linux-2.6.30/fs/yaffs2/yaffs_tagscompat.c	2009-06-11 09:21:04.000000000 +0200@@ -0,0 +1,541 @@+/*+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.+ *+ * Copyright (C) 2002-2007 Aleph One Ltd.+ *   for Toby Churchill Ltd and Brightstar Engineering+ *+ * Created by Charles Manning <charles@aleph1.co.uk>+ *+ * This program is free software; you can redistribute it and/or modify+ * it under the terms of the GNU General Public License version 2 as+ * published by the Free Software Foundation.+ */++#include "yaffs_guts.h"+#include "yaffs_tagscompat.h"+#include "yaffs_ecc.h"+#include "yaffs_getblockinfo.h"++static void yaffs_HandleReadDataError(yaffs_Device *dev, int chunkInNAND);+#ifdef NOTYET+static void yaffs_CheckWrittenBlock(yaffs_Device *dev, int chunkInNAND);+static void yaffs_HandleWriteChunkOk(yaffs_Device *dev, int chunkInNAND,+				     const __u8 *data,+				     const yaffs_Spare *spare);+static void yaffs_HandleUpdateChunk(yaffs_Device *dev, int chunkInNAND,+				    const yaffs_Spare *spare);+static void yaffs_HandleWriteChunkError(yaffs_Device *dev, int chunkInNAND);+#endif++static const char yaffs_countBitsTable[256] = {+	0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,+	1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,+	1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,+	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,+	1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,+	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,+	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,+	3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,+	1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,+	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,+	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,+	3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,+	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,+	3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,+	3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,+	4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8+};++int yaffs_CountBits(__u8 x)+{+	int retVal;+	retVal = yaffs_countBitsTable[x];+	return retVal;+}++/********** Tags ECC calculations  *********/++void yaffs_CalcECC(const __u8 *data, yaffs_Spare *spare)+{+	yaffs_ECCCalculate(data, spare->ecc1);+	yaffs_ECCCalculate(&data[256], spare->ecc2);+}++void yaffs_CalcTagsECC(yaffs_Tags *tags)+{+	/* Calculate an ecc */++	unsigned char *b = ((yaffs_TagsUnion *) tags)->asBytes;+	unsigned i, j;+	unsigned ecc = 0;+	unsigned bit = 0;++	tags->ecc = 0;++	for (i = 0; i < 8; i++) {+		for (j = 1; j & 0xff; j <<= 1) {+			bit++;+			if (b[i] & j)+				ecc ^= bit;+		}+	}++	tags->ecc = ecc;++}++int yaffs_CheckECCOnTags(yaffs_Tags *tags)+{+	unsigned ecc = tags->ecc;++	yaffs_CalcTagsECC(tags);++	ecc ^= tags->ecc;++	if (ecc && ecc <= 64) {+		/* TODO: Handle the failure better. Retire? */+		unsigned char *b = ((yaffs_TagsUnion *) tags)->asBytes;++		ecc--;++		b[ecc / 8] ^= (1 << (ecc & 7));++		/* Now recvalc the ecc */+		yaffs_CalcTagsECC(tags);++		return 1;	/* recovered error */+	} else if (ecc) {+		/* Wierd ecc failure value */+		/* TODO Need to do somethiong here */+		return -1;	/* unrecovered error */+	}++	return 0;+}++/********** Tags **********/++static void yaffs_LoadTagsIntoSpare(yaffs_Spare *sparePtr,+				yaffs_Tags *tagsPtr)+{+	yaffs_TagsUnion *tu = (yaffs_TagsUnion *) tagsPtr;++	yaffs_CalcTagsECC(tagsPtr);++	sparePtr->tagByte0 = tu->asBytes[0];+	sparePtr->tagByte1 = tu->asBytes[1];+	sparePtr->tagByte2 = tu->asBytes[2];+	sparePtr->tagByte3 = tu->asBytes[3];+	sparePtr->tagByte4 = tu->asBytes[4];+	sparePtr->tagByte5 = tu->asBytes[5];+	sparePtr->tagByte6 = tu->asBytes[6];+	sparePtr->tagByte7 = tu->asBytes[7];+}++static void yaffs_GetTagsFromSpare(yaffs_Device *dev, yaffs_Spare *sparePtr,+				yaffs_Tags *tagsPtr)+{+	yaffs_TagsUnion *tu = (yaffs_TagsUnion *) tagsPtr;+	int result;++	tu->asBytes[0] = sparePtr->tagByte0;+	tu->asBytes[1] = sparePtr->tagByte1;+	tu->asBytes[2] = sparePtr->tagByte2;+	tu->asBytes[3] = sparePtr->tagByte3;+	tu->asBytes[4] = sparePtr->tagByte4;+	tu->asBytes[5] = sparePtr->tagByte5;+	tu->asBytes[6] = sparePtr->tagByte6;+	tu->asBytes[7] = sparePtr->tagByte7;++	result = yaffs_CheckECCOnTags(tagsPtr);+	if (result > 0)+		dev->tagsEccFixed++;+	else if (result < 0)+		dev->tagsEccUnfixed++;+}++static void yaffs_SpareInitialise(yaffs_Spare *spare)+{+	memset(spare, 0xFF, sizeof(yaffs_Spare));+}++static int yaffs_WriteChunkToNAND(struct yaffs_DeviceStruct *dev,+				int chunkInNAND, const __u8 *data,+				yaffs_Spare *spare)+{+	if (chunkInNAND < dev->startBlock * dev->nChunksPerBlock) {+		T(YAFFS_TRACE_ERROR,+		  (TSTR("**>> yaffs chunk %d is not valid" TENDSTR),+		   chunkInNAND));+		return YAFFS_FAIL;+	}++	dev->nPageWrites++;+	return dev->writeChunkToNAND(dev, chunkInNAND, data, spare);+}++static int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev,+				   int chunkInNAND,+				   __u8 *data,+				   yaffs_Spare *spare,+				   yaffs_ECCResult *eccResult,+				   int doErrorCorrection)+{+	int retVal;+	yaffs_Spare localSpare;++	dev->nPageReads++;++	if (!spare && data) {+		/* If we don't have a real spare, then we use a local one. */+		/* Need this for the calculation of the ecc */+		spare = &localSpare;+	}++	if (!dev->useNANDECC) {+		retVal = dev->readChunkFromNAND(dev, chunkInNAND, data, spare);+		if (data && doErrorCorrection) {+			/* Do ECC correction */+			/* Todo handle any errors */+			int eccResult1, eccResult2;+			__u8 calcEcc[3];++			yaffs_ECCCalculate(data, calcEcc);+			eccResult1 =+			    yaffs_ECCCorrect(data, spare->ecc1, calcEcc);+			yaffs_ECCCalculate(&data[256], calcEcc);+			eccResult2 =+			    yaffs_ECCCorrect(&data[256], spare->ecc2, calcEcc);++			if (eccResult1 > 0) {+				T(YAFFS_TRACE_ERROR,+				  (TSTR+				   ("**>>yaffs ecc error fix performed on chunk %d:0"+				    TENDSTR), chunkInNAND));+				dev->eccFixed++;+			} else if (eccResult1 < 0) {+				T(YAFFS_TRACE_ERROR,+				  (TSTR+				   ("**>>yaffs ecc error unfixed on chunk %d:0"+				    TENDSTR), chunkInNAND));+				dev->eccUnfixed++;+			}++			if (eccResult2 > 0) {+				T(YAFFS_TRACE_ERROR,+				  (TSTR+				   ("**>>yaffs ecc error fix performed on chunk %d:1"+				    TENDSTR), chunkInNAND));+				dev->eccFixed++;+			} else if (eccResult2 < 0) {+				T(YAFFS_TRACE_ERROR,+				  (TSTR+				   ("**>>yaffs ecc error unfixed on chunk %d:1"+				    TENDSTR), chunkInNAND));+				dev->eccUnfixed++;+			}++			if (eccResult1 || eccResult2) {+				/* We had a data problem on this page */+				yaffs_HandleReadDataError(dev, chunkInNAND);+			}++			if (eccResult1 < 0 || eccResult2 < 0)+				*eccResult = YAFFS_ECC_RESULT_UNFIXED;+			else if (eccResult1 > 0 || eccResult2 > 0)+				*eccResult = YAFFS_ECC_RESULT_FIXED;+			else+				*eccResult = YAFFS_ECC_RESULT_NO_ERROR;+		}+	} else {+		/* Must allocate enough memory for spare+2*sizeof(int) */+		/* for ecc results from device. */+		struct yaffs_NANDSpare nspare;++		memset(&nspare, 0, sizeof(nspare));++		retVal = dev->readChunkFromNAND(dev, chunkInNAND, data,+					(yaffs_Spare *) &nspare);+		memcpy(spare, &nspare, sizeof(yaffs_Spare));+		if (data && doErrorCorrection) {+			if (nspare.eccres1 > 0) {+				T(YAFFS_TRACE_ERROR,+				  (TSTR+				   ("**>>mtd ecc error fix performed on chunk %d:0"+				    TENDSTR), chunkInNAND));+			} else if (nspare.eccres1 < 0) {+				T(YAFFS_TRACE_ERROR,+				  (TSTR+				   ("**>>mtd ecc error unfixed on chunk %d:0"+				    TENDSTR), chunkInNAND));+			}++			if (nspare.eccres2 > 0) {+				T(YAFFS_TRACE_ERROR,+				  (TSTR+				   ("**>>mtd ecc error fix performed on chunk %d:1"+				    TENDSTR), chunkInNAND));+			} else if (nspare.eccres2 < 0) {+				T(YAFFS_TRACE_ERROR,+				  (TSTR+				   ("**>>mtd ecc error unfixed on chunk %d:1"+				    TENDSTR), chunkInNAND));+			}++			if (nspare.eccres1 || nspare.eccres2) {+				/* We had a data problem on this page */+				yaffs_HandleReadDataError(dev, chunkInNAND);+			}++			if (nspare.eccres1 < 0 || nspare.eccres2 < 0)+				*eccResult = YAFFS_ECC_RESULT_UNFIXED;+			else if (nspare.eccres1 > 0 || nspare.eccres2 > 0)+				*eccResult = YAFFS_ECC_RESULT_FIXED;+			else+				*eccResult = YAFFS_ECC_RESULT_NO_ERROR;++		}+	}+	return retVal;+}++#ifdef NOTYET+static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,+				  int chunkInNAND)+{+	static int init;+	static __u8 cmpbuf[YAFFS_BYTES_PER_CHUNK];+	static __u8 data[YAFFS_BYTES_PER_CHUNK];+	/* Might as well always allocate the larger size for */+	/* dev->useNANDECC == true; */+	static __u8 spare[sizeof(struct yaffs_NANDSpare)];++	dev->readChunkFromNAND(dev, chunkInNAND, data, (yaffs_Spare *) spare);++	if (!init) {+		memset(cmpbuf, 0xff, YAFFS_BYTES_PER_CHUNK);+		init = 1;+	}++	if (memcmp(cmpbuf, data, YAFFS_BYTES_PER_CHUNK))+		return YAFFS_FAIL;+	if (memcmp(cmpbuf, spare, 16))+		return YAFFS_FAIL;++	return YAFFS_OK;++}+#endif++/*+ * Functions for robustisizing+ */++static void yaffs_HandleReadDataError(yaffs_Device *dev, int chunkInNAND)+{+	int blockInNAND = chunkInNAND / dev->nChunksPerBlock;++	/* Mark the block for retirement */+	yaffs_GetBlockInfo(dev, blockInNAND + dev->blockOffset)->needsRetiring = 1;+	T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,+	  (TSTR("**>>Block %d marked for retirement" TENDSTR), blockInNAND));++	/* TODO:+	 * Just do a garbage collection on the affected block+	 * then retire the block+	 * NB recursion+	 */+}++#ifdef NOTYET+static void yaffs_CheckWrittenBlock(yaffs_Device *dev, int chunkInNAND)+{+}++static void yaffs_HandleWriteChunkOk(yaffs_Device *dev, int chunkInNAND,+				     const __u8 *data,+				     const yaffs_Spare *spare)+{+}++static void yaffs_HandleUpdateChunk(yaffs_Device *dev, int chunkInNAND,+				    const yaffs_Spare *spare)+{+}++static void yaffs_HandleWriteChunkError(yaffs_Device *dev, int chunkInNAND)+{+	int blockInNAND = chunkInNAND / dev->nChunksPerBlock;++	/* Mark the block for retirement */+	yaffs_GetBlockInfo(dev, blockInNAND)->needsRetiring = 1;+	/* Delete the chunk */+	yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__);+}++static int yaffs_VerifyCompare(const __u8 *d0, const __u8 *d1,+			       const yaffs_Spare *s0, const yaffs_Spare *s1)+{++	if (memcmp(d0, d1, YAFFS_BYTES_PER_CHUNK) != 0 ||+	    s0->tagByte0 != s1->tagByte0 ||+	    s0->tagByte1 != s1->tagByte1 ||+	    s0->tagByte2 != s1->tagByte2 ||+	    s0->tagByte3 != s1->tagByte3 ||+	    s0->tagByte4 != s1->tagByte4 ||+	    s0->tagByte5 != s1->tagByte5 ||+	    s0->tagByte6 != s1->tagByte6 ||+	    s0->tagByte7 != s1->tagByte7 ||+	    s0->ecc1[0] != s1->ecc1[0] ||+	    s0->ecc1[1] != s1->ecc1[1] ||+	    s0->ecc1[2] != s1->ecc1[2] ||+	    s0->ecc2[0] != s1->ecc2[0] ||+	    s0->ecc2[1] != s1->ecc2[1] || s0->ecc2[2] != s1->ecc2[2]) {+		return 0;+	}++	return 1;+}+#endif				/* NOTYET */++int yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(yaffs_Device *dev,+						int chunkInNAND,+						const __u8 *data,+						const yaffs_ExtendedTags *eTags)+{+	yaffs_Spare spare;+	yaffs_Tags tags;++	yaffs_SpareInitialise(&spare);++	if (eTags->chunkDeleted)+		spare.pageStatus = 0;+	else {+		tags.objectId = eTags->objectId;+		tags.chunkId = eTags->chunkId;++		tags.byteCountLSB = eTags->byteCount & 0x3ff;++		if (dev->nDataBytesPerChunk >= 1024)+			tags.byteCountMSB = (eTags->byteCount >> 10) & 3;+		else+			tags.byteCountMSB = 3;+++		tags.serialNumber = eTags->serialNumber;++		if (!dev->useNANDECC && data)+			yaffs_CalcECC(data, &spare);++		yaffs_LoadTagsIntoSpare(&spare, &tags);++	}++	return yaffs_WriteChunkToNAND(dev, chunkInNAND, data, &spare);+}++int yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(yaffs_Device *dev,+						     int chunkInNAND,+						     __u8 *data,+						     yaffs_ExtendedTags *eTags)+{++	yaffs_Spare spare;+	yaffs_Tags tags;+	yaffs_ECCResult eccResult = YAFFS_ECC_RESULT_UNKNOWN;++	static yaffs_Spare spareFF;+	static int init;++	if (!init) {+		memset(&spareFF, 0xFF, sizeof(spareFF));+		init = 1;+	}++	if (yaffs_ReadChunkFromNAND+	    (dev, chunkInNAND, data, &spare, &eccResult, 1)) {+		/* eTags may be NULL */+		if (eTags) {++			int deleted =+			    (yaffs_CountBits(spare.pageStatus) < 7) ? 1 : 0;++			eTags->chunkDeleted = deleted;+			eTags->eccResult = eccResult;+			eTags->blockBad = 0;	/* We're reading it */+			/* therefore it is not a bad block */+			eTags->chunkUsed =+			    (memcmp(&spareFF, &spare, sizeof(spareFF)) !=+			     0) ? 1 : 0;++			if (eTags->chunkUsed) {+				yaffs_GetTagsFromSpare(dev, &spare, &tags);++				eTags->objectId = tags.objectId;+				eTags->chunkId = tags.chunkId;+				eTags->byteCount = tags.byteCountLSB;++				if (dev->nDataBytesPerChunk >= 1024)+					eTags->byteCount |= (((unsigned) tags.byteCountMSB) << 10);++				eTags->serialNumber = tags.serialNumber;+			}+		}++		return YAFFS_OK;+	} else {+		return YAFFS_FAIL;+	}+}++int yaffs_TagsCompatabilityMarkNANDBlockBad(struct yaffs_DeviceStruct *dev,+					    int blockInNAND)+{++	yaffs_Spare spare;++	memset(&spare, 0xff, sizeof(yaffs_Spare));++	spare.blockStatus = 'Y';++	yaffs_WriteChunkToNAND(dev, blockInNAND * dev->nChunksPerBlock, NULL,+			       &spare);+	yaffs_WriteChunkToNAND(dev, blockInNAND * dev->nChunksPerBlock + 1,+			       NULL, &spare);++	return YAFFS_OK;++}++int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev,+					  int blockNo,+					  yaffs_BlockState *state,+					  __u32 *sequenceNumber)+{++	yaffs_Spare spare0, spare1;+	static yaffs_Spare spareFF;+	static int init;+	yaffs_ECCResult dummy;++	if (!init) {+		memset(&spareFF, 0xFF, sizeof(spareFF));+		init = 1;+	}++	*sequenceNumber = 0;++	yaffs_ReadChunkFromNAND(dev, blockNo * dev->nChunksPerBlock, NULL,+				&spare0, &dummy, 1);+	yaffs_ReadChunkFromNAND(dev, blockNo * dev->nChunksPerBlock + 1, NULL,+				&spare1, &dummy, 1);++	if (yaffs_CountBits(spare0.blockStatus & spare1.blockStatus) < 7)+		*state = YAFFS_BLOCK_STATE_DEAD;+	else if (memcmp(&spareFF, &spare0, sizeof(spareFF)) == 0)+		*state = YAFFS_BLOCK_STATE_EMPTY;+	else+		*state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;++	return YAFFS_OK;+}diff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_tagscompat.h linux-2.6.30/fs/yaffs2/yaffs_tagscompat.h--- linux-2.6.30.orig/fs/yaffs2/yaffs_tagscompat.h	1970-01-01 01:00:00.000000000 +0100+++ linux-2.6.30/fs/yaffs2/yaffs_tagscompat.h	2009-06-11 09:21:04.000000000 +0200@@ -0,0 +1,39 @@+/*+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.+ *+ * Copyright (C) 2002-2007 Aleph One Ltd.+ *   for Toby Churchill Ltd and Brightstar Engineering+ *+ * Created by Charles Manning <charles@aleph1.co.uk>+ *+ * This program is free software; you can redistribute it and/or modify+ * it under the terms of the GNU Lesser General Public License version 2.1 as+ * published by the Free Software Foundation.+ *+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.+ */++#ifndef __YAFFS_TAGSCOMPAT_H__+#define __YAFFS_TAGSCOMPAT_H__++#include "yaffs_guts.h"+int yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(yaffs_Device *dev,+						int chunkInNAND,+						const __u8 *data,+						const yaffs_ExtendedTags *tags);+int yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(yaffs_Device *dev,+						int chunkInNAND,+						__u8 *data,+						yaffs_ExtendedTags *tags);+int yaffs_TagsCompatabilityMarkNANDBlockBad(struct yaffs_DeviceStruct *dev,+					    int blockNo);+int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev,+					  int blockNo,+					  yaffs_BlockState *state,+					  __u32 *sequenceNumber);++void yaffs_CalcTagsECC(yaffs_Tags *tags);+int yaffs_CheckECCOnTags(yaffs_Tags *tags);+int yaffs_CountBits(__u8 byte);++#endifdiff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_tagsvalidity.c linux-2.6.30/fs/yaffs2/yaffs_tagsvalidity.c--- linux-2.6.30.orig/fs/yaffs2/yaffs_tagsvalidity.c	1970-01-01 01:00:00.000000000 +0100+++ linux-2.6.30/fs/yaffs2/yaffs_tagsvalidity.c	2009-06-11 09:21:04.000000000 +0200@@ -0,0 +1,28 @@+/*+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.+ *+ * Copyright (C) 2002-2007 Aleph One Ltd.+ *   for Toby Churchill Ltd and Brightstar Engineering+ *+ * Created by Charles Manning <charles@aleph1.co.uk>+ *+ * This program is free software; you can redistribute it and/or modify+ * it under the terms of the GNU General Public License version 2 as+ * published by the Free Software Foundation.+ */++#include "yaffs_tagsvalidity.h"++void yaffs_InitialiseTags(yaffs_ExtendedTags *tags)+{+	memset(tags, 0, sizeof(yaffs_ExtendedTags));+	tags->validMarker0 = 0xAAAAAAAA;+	tags->validMarker1 = 0x55555555;+}++int yaffs_ValidateTags(yaffs_ExtendedTags *tags)+{+	return (tags->validMarker0 == 0xAAAAAAAA &&+		tags->validMarker1 == 0x55555555);++}diff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_tagsvalidity.h linux-2.6.30/fs/yaffs2/yaffs_tagsvalidity.h--- linux-2.6.30.orig/fs/yaffs2/yaffs_tagsvalidity.h	1970-01-01 01:00:00.000000000 +0100+++ linux-2.6.30/fs/yaffs2/yaffs_tagsvalidity.h	2009-06-11 09:21:04.000000000 +0200@@ -0,0 +1,24 @@+/*+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.+ *+ * Copyright (C) 2002-2007 Aleph One Ltd.+ *   for Toby Churchill Ltd and Brightstar Engineering+ *+ * Created by Charles Manning <charles@aleph1.co.uk>+ *+ * This program is free software; you can redistribute it and/or modify+ * it under the terms of the GNU Lesser General Public License version 2.1 as+ * published by the Free Software Foundation.+ *+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.+ */+++#ifndef __YAFFS_TAGS_VALIDITY_H__+#define __YAFFS_TAGS_VALIDITY_H__++#include "yaffs_guts.h"++void yaffs_InitialiseTags(yaffs_ExtendedTags *tags);+int yaffs_ValidateTags(yaffs_ExtendedTags *tags);+#endifdiff -Nur linux-2.6.30.orig/fs/yaffs2/yportenv.h linux-2.6.30/fs/yaffs2/yportenv.h--- linux-2.6.30.orig/fs/yaffs2/yportenv.h	1970-01-01 01:00:00.000000000 +0100+++ linux-2.6.30/fs/yaffs2/yportenv.h	2009-06-11 09:21:04.000000000 +0200@@ -0,0 +1,203 @@+/*+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.+ *+ * Copyright (C) 2002-2007 Aleph One Ltd.+ *   for Toby Churchill Ltd and Brightstar Engineering+ *+ * Created by Charles Manning <charles@aleph1.co.uk>+ *+ * This program is free software; you can redistribute it and/or modify+ * it under the terms of the GNU Lesser General Public License version 2.1 as+ * published by the Free Software Foundation.+ *+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.+ */+++#ifndef __YPORTENV_H__+#define __YPORTENV_H__++/*+ * Define the MTD version in terms of Linux Kernel versions+ * This allows yaffs to be used independantly of the kernel+ * as well as with it.+ */++#define MTD_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + (c))++#if defined CONFIG_YAFFS_WINCE++#include "ywinceenv.h"++#elif defined __KERNEL__++#include "moduleconfig.h"++/* Linux kernel */++#include <linux/version.h>+#define MTD_VERSION_CODE LINUX_VERSION_CODE++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))+#include <linux/config.h>+#endif+#include <linux/kernel.h>+#include <linux/mm.h>+#include <linux/sched.h>+#include <linux/string.h>+#include <linux/slab.h>+#include <linux/vmalloc.h>++#define YCHAR char+#define YUCHAR unsigned char+#define _Y(x)     x+#define yaffs_strcat(a, b)     strcat(a, b)+#define yaffs_strcpy(a, b)     strcpy(a, b)+#define yaffs_strncpy(a, b, c) strncpy(a, b, c)+#define yaffs_strncmp(a, b, c) strncmp(a, b, c)+#define yaffs_strlen(s)	       strlen(s)+#define yaffs_sprintf	       sprintf+#define yaffs_toupper(a)       toupper(a)++#define Y_INLINE inline++#define YAFFS_LOSTNFOUND_NAME		"lost+found"+#define YAFFS_LOSTNFOUND_PREFIX		"obj"++/* #define YPRINTF(x) printk x */+#define YMALLOC(x) kmalloc(x, GFP_NOFS)+#define YFREE(x)   kfree(x)+#define YMALLOC_ALT(x) vmalloc(x)+#define YFREE_ALT(x)   vfree(x)+#define YMALLOC_DMA(x) YMALLOC(x)++/* KR - added for use in scan so processes aren't blocked indefinitely. */+#define YYIELD() schedule()++#define YAFFS_ROOT_MODE			0666+#define YAFFS_LOSTNFOUND_MODE		0666++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))+#define Y_CURRENT_TIME CURRENT_TIME.tv_sec+#define Y_TIME_CONVERT(x) (x).tv_sec+#else+#define Y_CURRENT_TIME CURRENT_TIME+#define Y_TIME_CONVERT(x) (x)+#endif++#define yaffs_SumCompare(x, y) ((x) == (y))+#define yaffs_strcmp(a, b) strcmp(a, b)++#define TENDSTR "\n"+#define TSTR(x) KERN_WARNING x+#define TCONT(x) x+#define TOUT(p) printk p++#define yaffs_trace(mask, fmt, args...) \+	do { if ((mask) & (yaffs_traceMask|YAFFS_TRACE_ERROR)) \+		printk(KERN_WARNING "yaffs: " fmt, ## args); \+	} while (0)++#define compile_time_assertion(assertion) \+	({ int x = __builtin_choose_expr(assertion, 0, (void)0); (void) x; })++#elif defined CONFIG_YAFFS_DIRECT++#define MTD_VERSION_CODE MTD_VERSION(2, 6, 22)++/* Direct interface */+#include "ydirectenv.h"++#elif defined CONFIG_YAFFS_UTIL++/* Stuff for YAFFS utilities */++#include "stdlib.h"+#include "stdio.h"+#include "string.h"++#include "devextras.h"++#define YMALLOC(x) malloc(x)+#define YFREE(x)   free(x)+#define YMALLOC_ALT(x) malloc(x)+#define YFREE_ALT(x) free(x)++#define YCHAR char+#define YUCHAR unsigned char+#define _Y(x)     x+#define yaffs_strcat(a, b)     strcat(a, b)+#define yaffs_strcpy(a, b)     strcpy(a, b)+#define yaffs_strncpy(a, b, c) strncpy(a, b, c)+#define yaffs_strlen(s)	       strlen(s)+#define yaffs_sprintf	       sprintf+#define yaffs_toupper(a)       toupper(a)++#define Y_INLINE inline++/* #define YINFO(s) YPRINTF(( __FILE__ " %d %s\n",__LINE__,s)) */+/* #define YALERT(s) YINFO(s) */++#define TENDSTR "\n"+#define TSTR(x) x+#define TOUT(p) printf p++#define YAFFS_LOSTNFOUND_NAME		"lost+found"+#define YAFFS_LOSTNFOUND_PREFIX		"obj"+/* #define YPRINTF(x) printf x */++#define YAFFS_ROOT_MODE				0666+#define YAFFS_LOSTNFOUND_MODE		0666++#define yaffs_SumCompare(x, y) ((x) == (y))+#define yaffs_strcmp(a, b) strcmp(a, b)++#else+/* Should have specified a configuration type */+#error Unknown configuration++#endif++/* see yaffs_fs.c */+extern unsigned int yaffs_traceMask;+extern unsigned int yaffs_wr_attempts;++/*+ * Tracing flags.+ * The flags masked in YAFFS_TRACE_ALWAYS are always traced.+ */++#define YAFFS_TRACE_OS			0x00000002+#define YAFFS_TRACE_ALLOCATE		0x00000004+#define YAFFS_TRACE_SCAN		0x00000008+#define YAFFS_TRACE_BAD_BLOCKS		0x00000010+#define YAFFS_TRACE_ERASE		0x00000020+#define YAFFS_TRACE_GC			0x00000040+#define YAFFS_TRACE_WRITE		0x00000080+#define YAFFS_TRACE_TRACING		0x00000100+#define YAFFS_TRACE_DELETION		0x00000200+#define YAFFS_TRACE_BUFFERS		0x00000400+#define YAFFS_TRACE_NANDACCESS		0x00000800+#define YAFFS_TRACE_GC_DETAIL		0x00001000+#define YAFFS_TRACE_SCAN_DEBUG		0x00002000+#define YAFFS_TRACE_MTD			0x00004000+#define YAFFS_TRACE_CHECKPOINT		0x00008000++#define YAFFS_TRACE_VERIFY		0x00010000+#define YAFFS_TRACE_VERIFY_NAND		0x00020000+#define YAFFS_TRACE_VERIFY_FULL		0x00040000+#define YAFFS_TRACE_VERIFY_ALL		0x000F0000+++#define YAFFS_TRACE_ERROR		0x40000000+#define YAFFS_TRACE_BUG			0x80000000+#define YAFFS_TRACE_ALWAYS		0xF0000000+++#define T(mask, p) do { if ((mask) & (yaffs_traceMask | YAFFS_TRACE_ALWAYS)) TOUT(p); } while (0)++#ifndef YBUG+#define YBUG() do {T(YAFFS_TRACE_BUG, (TSTR("==>> yaffs bug: " __FILE__ " %d" TENDSTR), __LINE__)); } while (0)+#endif++#endif
 |