| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453945494559456945794589459946094619462946394649465946694679468946994709471947294739474947594769477947894799480948194829483948494859486948794889489949094919492949394949495949694979498949995009501950295039504950595069507950895099510951195129513951495159516951795189519952095219522952395249525952695279528952995309531953295339534953595369537953895399540954195429543954495459546954795489549955095519552955395549555955695579558955995609561956295639564956595669567956895699570957195729573957495759576957795789579958095819582958395849585958695879588958995909591959295939594959595969597959895999600960196029603960496059606960796089609961096119612961396149615961696179618961996209621962296239624962596269627962896299630963196329633963496359636963796389639964096419642964396449645964696479648964996509651965296539654965596569657965896599660966196629663966496659666966796689669967096719672967396749675967696779678967996809681968296839684968596869687968896899690969196929693969496959696969796989699970097019702970397049705970697079708970997109711971297139714971597169717971897199720972197229723972497259726972797289729973097319732973397349735973697379738973997409741974297439744974597469747974897499750975197529753975497559756975797589759976097619762976397649765976697679768976997709771977297739774977597769777977897799780978197829783978497859786978797889789979097919792979397949795979697979798979998009801980298039804980598069807980898099810981198129813981498159816981798189819982098219822982398249825982698279828982998309831983298339834983598369837983898399840984198429843984498459846984798489849985098519852985398549855985698579858985998609861986298639864986598669867986898699870987198729873987498759876987798789879988098819882988398849885988698879888988998909891989298939894989598969897989898999900990199029903990499059906990799089909991099119912991399149915991699179918991999209921992299239924992599269927992899299930993199329933993499359936993799389939994099419942994399449945994699479948994999509951995299539954995599569957995899599960996199629963996499659966996799689969997099719972997399749975997699779978997999809981998299839984998599869987998899899990999199929993999499959996999799989999100001000110002100031000410005100061000710008100091001010011100121001310014100151001610017100181001910020100211002210023100241002510026100271002810029100301003110032100331003410035100361003710038100391004010041100421004310044100451004610047100481004910050100511005210053100541005510056100571005810059100601006110062100631006410065100661006710068100691007010071100721007310074100751007610077100781007910080100811008210083100841008510086100871008810089100901009110092100931009410095100961009710098100991010010101101021010310104101051010610107101081010910110101111011210113101141011510116101171011810119101201012110122101231012410125101261012710128101291013010131101321013310134101351013610137101381013910140101411014210143101441014510146101471014810149101501015110152101531015410155101561015710158101591016010161101621016310164101651016610167101681016910170101711017210173101741017510176101771017810179101801018110182101831018410185101861018710188101891019010191101921019310194101951019610197101981019910200102011020210203102041020510206102071020810209102101021110212102131021410215102161021710218102191022010221102221022310224102251022610227102281022910230102311023210233102341023510236102371023810239102401024110242102431024410245102461024710248102491025010251102521025310254102551025610257102581025910260102611026210263102641026510266102671026810269102701027110272102731027410275102761027710278102791028010281102821028310284102851028610287102881028910290102911029210293102941029510296102971029810299103001030110302103031030410305103061030710308103091031010311103121031310314103151031610317103181031910320103211032210323103241032510326103271032810329103301033110332103331033410335103361033710338103391034010341103421034310344103451034610347103481034910350103511035210353103541035510356103571035810359103601036110362103631036410365103661036710368103691037010371103721037310374103751037610377103781037910380103811038210383103841038510386103871038810389103901039110392103931039410395103961039710398103991040010401104021040310404104051040610407104081040910410104111041210413104141041510416104171041810419104201042110422104231042410425104261042710428104291043010431104321043310434104351043610437104381043910440104411044210443104441044510446104471044810449104501045110452104531045410455104561045710458104591046010461104621046310464104651046610467104681046910470104711047210473104741047510476104771047810479104801048110482104831048410485104861048710488104891049010491104921049310494104951049610497104981049910500105011050210503105041050510506105071050810509105101051110512105131051410515105161051710518105191052010521105221052310524105251052610527105281052910530105311053210533105341053510536105371053810539105401054110542105431054410545105461054710548105491055010551105521055310554105551055610557105581055910560105611056210563105641056510566105671056810569105701057110572105731057410575105761057710578105791058010581105821058310584105851058610587105881058910590105911059210593105941059510596105971059810599106001060110602106031060410605106061060710608106091061010611106121061310614106151061610617106181061910620106211062210623106241062510626106271062810629106301063110632106331063410635106361063710638106391064010641106421064310644106451064610647106481064910650106511065210653106541065510656106571065810659106601066110662106631066410665106661066710668106691067010671106721067310674106751067610677106781067910680106811068210683106841068510686106871068810689106901069110692106931069410695106961069710698106991070010701107021070310704107051070610707107081070910710107111071210713107141071510716107171071810719107201072110722107231072410725107261072710728107291073010731107321073310734107351073610737107381073910740107411074210743107441074510746107471074810749107501075110752107531075410755107561075710758107591076010761107621076310764107651076610767107681076910770107711077210773107741077510776107771077810779107801078110782107831078410785107861078710788107891079010791107921079310794107951079610797107981079910800108011080210803108041080510806108071080810809108101081110812108131081410815108161081710818108191082010821108221082310824108251082610827108281082910830108311083210833108341083510836108371083810839108401084110842108431084410845108461084710848108491085010851108521085310854108551085610857108581085910860108611086210863108641086510866108671086810869108701087110872108731087410875108761087710878108791088010881108821088310884108851088610887108881088910890108911089210893108941089510896108971089810899109001090110902109031090410905109061090710908109091091010911109121091310914109151091610917109181091910920109211092210923109241092510926109271092810929109301093110932109331093410935109361093710938109391094010941109421094310944109451094610947109481094910950109511095210953109541095510956109571095810959109601096110962109631096410965109661096710968109691097010971109721097310974109751097610977109781097910980109811098210983109841098510986109871098810989109901099110992109931099410995109961099710998109991100011001110021100311004110051100611007110081100911010110111101211013110141101511016110171101811019110201102111022110231102411025110261102711028110291103011031110321103311034110351103611037110381103911040110411104211043110441104511046110471104811049110501105111052110531105411055110561105711058110591106011061110621106311064110651106611067110681106911070110711107211073110741107511076110771107811079110801108111082110831108411085110861108711088110891109011091110921109311094110951109611097110981109911100111011110211103111041110511106111071110811109111101111111112111131111411115111161111711118111191112011121111221112311124111251112611127111281112911130111311113211133111341113511136111371113811139111401114111142111431114411145111461114711148111491115011151111521115311154111551115611157111581115911160111611116211163111641116511166111671116811169111701117111172111731117411175111761117711178111791118011181111821118311184111851118611187111881118911190111911119211193111941119511196111971119811199112001120111202112031120411205112061120711208112091121011211112121121311214112151121611217112181121911220112211122211223112241122511226112271122811229112301123111232112331123411235112361123711238112391124011241112421124311244112451124611247112481124911250112511125211253112541125511256112571125811259112601126111262112631126411265112661126711268112691127011271112721127311274112751127611277112781127911280112811128211283112841128511286112871128811289112901129111292112931129411295112961129711298112991130011301113021130311304113051130611307113081130911310113111131211313113141131511316113171131811319113201132111322113231132411325113261132711328113291133011331113321133311334113351133611337113381133911340113411134211343113441134511346113471134811349113501135111352113531135411355113561135711358113591136011361113621136311364113651136611367113681136911370113711137211373113741137511376113771137811379113801138111382113831138411385113861138711388113891139011391113921139311394113951139611397113981139911400114011140211403114041140511406114071140811409114101141111412114131141411415114161141711418114191142011421114221142311424114251142611427114281142911430114311143211433114341143511436114371143811439114401144111442114431144411445114461144711448114491145011451114521145311454114551145611457114581145911460114611146211463114641146511466114671146811469114701147111472114731147411475114761147711478114791148011481114821148311484114851148611487114881148911490114911149211493114941149511496114971149811499115001150111502115031150411505115061150711508115091151011511115121151311514115151151611517115181151911520115211152211523115241152511526115271152811529115301153111532115331153411535115361153711538115391154011541115421154311544115451154611547115481154911550115511155211553115541155511556115571155811559115601156111562115631156411565115661156711568115691157011571115721157311574115751157611577115781157911580115811158211583115841158511586115871158811589115901159111592115931159411595115961159711598115991160011601116021160311604116051160611607116081160911610116111161211613116141161511616116171161811619116201162111622116231162411625116261162711628116291163011631116321163311634116351163611637116381163911640116411164211643116441164511646116471164811649116501165111652116531165411655116561165711658116591166011661116621166311664116651166611667116681166911670116711167211673116741167511676116771167811679116801168111682116831168411685116861168711688116891169011691116921169311694116951169611697116981169911700117011170211703117041170511706117071170811709117101171111712117131171411715117161171711718117191172011721117221172311724117251172611727117281172911730117311173211733117341173511736117371173811739117401174111742117431174411745117461174711748117491175011751117521175311754117551175611757117581175911760117611176211763117641176511766117671176811769117701177111772117731177411775117761177711778117791178011781117821178311784117851178611787117881178911790117911179211793117941179511796117971179811799118001180111802118031180411805118061180711808118091181011811118121181311814118151181611817118181181911820118211182211823118241182511826118271182811829118301183111832118331183411835118361183711838118391184011841118421184311844118451184611847118481184911850118511185211853118541185511856118571185811859118601186111862118631186411865118661186711868118691187011871118721187311874118751187611877118781187911880118811188211883118841188511886118871188811889118901189111892118931189411895118961189711898118991190011901119021190311904119051190611907119081190911910119111191211913119141191511916119171191811919119201192111922119231192411925119261192711928119291193011931119321193311934119351193611937119381193911940119411194211943119441194511946119471194811949119501195111952119531195411955119561195711958119591196011961119621196311964119651196611967119681196911970119711197211973119741197511976119771197811979119801198111982119831198411985119861198711988119891199011991119921199311994119951199611997119981199912000120011200212003120041200512006120071200812009120101201112012120131201412015120161201712018120191202012021120221202312024120251202612027120281202912030120311203212033120341203512036120371203812039120401204112042120431204412045120461204712048120491205012051120521205312054120551205612057120581205912060120611206212063120641206512066120671206812069120701207112072120731207412075120761207712078120791208012081120821208312084120851208612087120881208912090120911209212093120941209512096120971209812099121001210112102121031210412105121061210712108121091211012111121121211312114121151211612117121181211912120121211212212123121241212512126121271212812129121301213112132121331213412135121361213712138121391214012141121421214312144121451214612147121481214912150121511215212153121541215512156121571215812159121601216112162121631216412165121661216712168121691217012171121721217312174121751217612177121781217912180121811218212183121841218512186121871218812189121901219112192121931219412195121961219712198121991220012201122021220312204122051220612207122081220912210122111221212213122141221512216122171221812219122201222112222122231222412225122261222712228122291223012231122321223312234122351223612237122381223912240122411224212243122441224512246122471224812249122501225112252122531225412255122561225712258122591226012261122621226312264122651226612267122681226912270122711227212273122741227512276122771227812279122801228112282122831228412285122861228712288122891229012291122921229312294122951229612297122981229912300123011230212303123041230512306123071230812309123101231112312123131231412315123161231712318123191232012321123221232312324123251232612327123281232912330123311233212333123341233512336123371233812339123401234112342123431234412345123461234712348123491235012351123521235312354123551235612357123581235912360123611236212363123641236512366123671236812369123701237112372123731237412375123761237712378123791238012381123821238312384123851238612387123881238912390123911239212393123941239512396123971239812399124001240112402124031240412405124061240712408124091241012411124121241312414124151241612417124181241912420124211242212423124241242512426124271242812429124301243112432124331243412435124361243712438124391244012441124421244312444124451244612447124481244912450124511245212453124541245512456124571245812459124601246112462124631246412465124661246712468124691247012471124721247312474124751247612477124781247912480124811248212483124841248512486124871248812489124901249112492124931249412495124961249712498124991250012501125021250312504125051250612507125081250912510125111251212513125141251512516125171251812519125201252112522125231252412525125261252712528125291253012531125321253312534125351253612537125381253912540125411254212543125441254512546125471254812549125501255112552125531255412555125561255712558125591256012561125621256312564125651256612567125681256912570125711257212573125741257512576125771257812579125801258112582125831258412585125861258712588125891259012591125921259312594125951259612597125981259912600126011260212603126041260512606126071260812609126101261112612126131261412615126161261712618126191262012621126221262312624126251262612627126281262912630126311263212633126341263512636126371263812639126401264112642126431264412645126461264712648126491265012651126521265312654126551265612657126581265912660126611266212663126641266512666126671266812669126701267112672126731267412675126761267712678126791268012681126821268312684126851268612687126881268912690126911269212693126941269512696126971269812699127001270112702127031270412705127061270712708127091271012711127121271312714127151271612717127181271912720127211272212723127241272512726127271272812729127301273112732127331273412735127361273712738127391274012741127421274312744127451274612747127481274912750127511275212753127541275512756127571275812759127601276112762127631276412765127661276712768127691277012771127721277312774127751277612777127781277912780127811278212783127841278512786127871278812789127901279112792127931279412795127961279712798127991280012801128021280312804128051280612807128081280912810128111281212813128141281512816128171281812819128201282112822128231282412825128261282712828128291283012831128321283312834128351283612837128381283912840128411284212843128441284512846128471284812849128501285112852128531285412855128561285712858128591286012861128621286312864128651286612867128681286912870128711287212873128741287512876128771287812879128801288112882128831288412885128861288712888128891289012891128921289312894128951289612897128981289912900129011290212903129041290512906129071290812909129101291112912129131291412915129161291712918129191292012921129221292312924129251292612927129281292912930129311293212933129341293512936129371293812939129401294112942129431294412945129461294712948129491295012951129521295312954129551295612957129581295912960129611296212963129641296512966129671296812969129701297112972129731297412975129761297712978129791298012981129821298312984129851298612987129881298912990129911299212993129941299512996129971299812999130001300113002130031300413005130061300713008130091301013011130121301313014130151301613017130181301913020130211302213023130241302513026130271302813029130301303113032130331303413035130361303713038130391304013041130421304313044130451304613047130481304913050130511305213053130541305513056130571305813059130601306113062130631306413065130661306713068130691307013071130721307313074130751307613077130781307913080130811308213083130841308513086130871308813089130901309113092130931309413095130961309713098130991310013101131021310313104131051310613107131081310913110131111311213113131141311513116131171311813119131201312113122131231312413125131261312713128131291313013131131321313313134131351313613137131381313913140131411314213143131441314513146131471314813149131501315113152131531315413155131561315713158131591316013161131621316313164131651316613167131681316913170131711317213173131741317513176131771317813179131801318113182131831318413185131861318713188131891319013191131921319313194131951319613197131981319913200132011320213203132041320513206132071320813209132101321113212132131321413215132161321713218132191322013221132221322313224132251322613227132281322913230132311323213233132341323513236132371323813239132401324113242132431324413245132461324713248132491325013251132521325313254132551325613257132581325913260132611326213263132641326513266132671326813269132701327113272132731327413275132761327713278132791328013281132821328313284132851328613287132881328913290132911329213293132941329513296132971329813299133001330113302133031330413305133061330713308133091331013311133121331313314133151331613317133181331913320133211332213323133241332513326133271332813329133301333113332133331333413335133361333713338133391334013341133421334313344133451334613347133481334913350133511335213353133541335513356133571335813359133601336113362133631336413365133661336713368133691337013371133721337313374133751337613377133781337913380133811338213383133841338513386133871338813389133901339113392133931339413395133961339713398133991340013401134021340313404134051340613407134081340913410134111341213413134141341513416134171341813419134201342113422134231342413425134261342713428134291343013431134321343313434134351343613437134381343913440134411344213443134441344513446134471344813449134501345113452134531345413455134561345713458134591346013461134621346313464134651346613467134681346913470134711347213473134741347513476134771347813479134801348113482134831348413485134861348713488134891349013491134921349313494134951349613497134981349913500135011350213503135041350513506135071350813509135101351113512135131351413515135161351713518135191352013521135221352313524135251352613527135281352913530135311353213533135341353513536135371353813539135401354113542135431354413545135461354713548135491355013551135521355313554135551355613557135581355913560135611356213563135641356513566135671356813569135701357113572135731357413575135761357713578135791358013581135821358313584135851358613587135881358913590135911359213593135941359513596135971359813599136001360113602136031360413605136061360713608136091361013611136121361313614136151361613617136181361913620136211362213623136241362513626136271362813629136301363113632136331363413635136361363713638136391364013641136421364313644136451364613647136481364913650136511365213653136541365513656136571365813659136601366113662136631366413665136661366713668136691367013671136721367313674136751367613677136781367913680136811368213683136841368513686136871368813689136901369113692136931369413695136961369713698136991370013701137021370313704137051370613707137081370913710137111371213713137141371513716137171371813719137201372113722137231372413725137261372713728137291373013731137321373313734137351373613737137381373913740137411374213743137441374513746137471374813749137501375113752137531375413755137561375713758137591376013761137621376313764137651376613767137681376913770137711377213773137741377513776137771377813779137801378113782137831378413785137861378713788137891379013791137921379313794137951379613797137981379913800138011380213803138041380513806138071380813809138101381113812138131381413815138161381713818138191382013821138221382313824138251382613827138281382913830138311383213833138341383513836138371383813839138401384113842138431384413845138461384713848138491385013851138521385313854138551385613857138581385913860138611386213863138641386513866138671386813869138701387113872138731387413875138761387713878138791388013881138821388313884138851388613887138881388913890138911389213893138941389513896138971389813899139001390113902139031390413905139061390713908139091391013911139121391313914139151391613917139181391913920139211392213923139241392513926139271392813929139301393113932139331393413935139361393713938139391394013941139421394313944139451394613947139481394913950139511395213953139541395513956139571395813959139601396113962139631396413965139661396713968139691397013971139721397313974139751397613977139781397913980139811398213983139841398513986139871398813989139901399113992139931399413995139961399713998139991400014001140021400314004140051400614007140081400914010140111401214013140141401514016140171401814019140201402114022140231402414025140261402714028140291403014031140321403314034140351403614037140381403914040140411404214043140441404514046140471404814049140501405114052140531405414055140561405714058140591406014061140621406314064140651406614067140681406914070140711407214073140741407514076140771407814079140801408114082140831408414085140861408714088140891409014091140921409314094140951409614097140981409914100141011410214103141041410514106141071410814109141101411114112141131411414115141161411714118141191412014121141221412314124141251412614127141281412914130141311413214133141341413514136141371413814139141401414114142141431414414145141461414714148141491415014151141521415314154141551415614157141581415914160141611416214163141641416514166141671416814169141701417114172141731417414175141761417714178141791418014181141821418314184141851418614187141881418914190141911419214193141941419514196141971419814199142001420114202142031420414205142061420714208142091421014211142121421314214142151421614217142181421914220142211422214223142241422514226142271422814229142301423114232142331423414235142361423714238142391424014241142421424314244142451424614247142481424914250142511425214253142541425514256142571425814259142601426114262142631426414265142661426714268142691427014271142721427314274142751427614277142781427914280142811428214283142841428514286142871428814289142901429114292142931429414295142961429714298142991430014301143021430314304143051430614307143081430914310143111431214313143141431514316143171431814319143201432114322143231432414325143261432714328143291433014331143321433314334143351433614337143381433914340143411434214343143441434514346143471434814349143501435114352143531435414355143561435714358143591436014361143621436314364143651436614367143681436914370143711437214373143741437514376143771437814379143801438114382143831438414385143861438714388143891439014391143921439314394143951439614397143981439914400144011440214403144041440514406144071440814409144101441114412144131441414415144161441714418144191442014421144221442314424144251442614427144281442914430144311443214433144341443514436144371443814439144401444114442144431444414445144461444714448144491445014451144521445314454144551445614457144581445914460144611446214463144641446514466144671446814469144701447114472144731447414475144761447714478144791448014481144821448314484144851448614487144881448914490144911449214493144941449514496144971449814499145001450114502145031450414505145061450714508145091451014511145121451314514145151451614517145181451914520145211452214523145241452514526145271452814529145301453114532145331453414535145361453714538145391454014541145421454314544145451454614547145481454914550145511455214553145541455514556145571455814559145601456114562145631456414565145661456714568145691457014571145721457314574145751457614577145781457914580145811458214583145841458514586145871458814589145901459114592145931459414595145961459714598145991460014601146021460314604146051460614607146081460914610146111461214613146141461514616146171461814619146201462114622146231462414625146261462714628146291463014631146321463314634146351463614637146381463914640146411464214643146441464514646146471464814649146501465114652146531465414655146561465714658146591466014661146621466314664146651466614667146681466914670146711467214673146741467514676146771467814679146801468114682146831468414685146861468714688146891469014691146921469314694146951469614697146981469914700147011470214703147041470514706147071470814709147101471114712147131471414715147161471714718147191472014721147221472314724147251472614727147281472914730147311473214733147341473514736147371473814739147401474114742147431474414745147461474714748147491475014751147521475314754147551475614757147581475914760147611476214763147641476514766147671476814769147701477114772147731477414775147761477714778147791478014781147821478314784147851478614787147881478914790147911479214793147941479514796147971479814799148001480114802148031480414805148061480714808148091481014811148121481314814148151481614817148181481914820148211482214823148241482514826148271482814829148301483114832148331483414835148361483714838148391484014841148421484314844148451484614847148481484914850148511485214853148541485514856148571485814859148601486114862148631486414865148661486714868148691487014871148721487314874148751487614877148781487914880148811488214883148841488514886148871488814889148901489114892148931489414895148961489714898148991490014901149021490314904149051490614907149081490914910149111491214913149141491514916149171491814919149201492114922149231492414925149261492714928149291493014931149321493314934149351493614937149381493914940149411494214943149441494514946149471494814949149501495114952149531495414955149561495714958149591496014961149621496314964149651496614967149681496914970149711497214973149741497514976149771497814979149801498114982149831498414985149861498714988149891499014991149921499314994149951499614997149981499915000150011500215003150041500515006150071500815009150101501115012150131501415015150161501715018150191502015021150221502315024150251502615027150281502915030150311503215033150341503515036150371503815039150401504115042150431504415045150461504715048150491505015051150521505315054150551505615057150581505915060150611506215063150641506515066150671506815069150701507115072150731507415075150761507715078150791508015081150821508315084150851508615087150881508915090150911509215093150941509515096150971509815099151001510115102151031510415105151061510715108151091511015111151121511315114151151511615117151181511915120151211512215123151241512515126151271512815129151301513115132151331513415135151361513715138151391514015141151421514315144151451514615147151481514915150151511515215153151541515515156151571515815159151601516115162151631516415165151661516715168151691517015171151721517315174151751517615177151781517915180151811518215183151841518515186151871518815189151901519115192151931519415195151961519715198151991520015201152021520315204152051520615207152081520915210152111521215213152141521515216152171521815219152201522115222152231522415225152261522715228152291523015231152321523315234152351523615237152381523915240152411524215243152441524515246152471524815249152501525115252152531525415255152561525715258152591526015261152621526315264152651526615267152681526915270152711527215273152741527515276152771527815279152801528115282152831528415285152861528715288152891529015291152921529315294152951529615297152981529915300153011530215303153041530515306153071530815309153101531115312153131531415315153161531715318153191532015321153221532315324153251532615327153281532915330153311533215333153341533515336153371533815339153401534115342153431534415345153461534715348153491535015351153521535315354153551535615357153581535915360153611536215363153641536515366153671536815369153701537115372153731537415375153761537715378153791538015381153821538315384153851538615387153881538915390153911539215393153941539515396153971539815399154001540115402154031540415405154061540715408154091541015411154121541315414154151541615417154181541915420154211542215423154241542515426154271542815429154301543115432154331543415435154361543715438154391544015441154421544315444154451544615447154481544915450154511545215453154541545515456154571545815459154601546115462154631546415465154661546715468154691547015471154721547315474154751547615477154781547915480154811548215483154841548515486154871548815489154901549115492154931549415495154961549715498154991550015501155021550315504155051550615507155081550915510155111551215513155141551515516155171551815519155201552115522155231552415525155261552715528155291553015531155321553315534155351553615537155381553915540155411554215543155441554515546155471554815549155501555115552155531555415555155561555715558155591556015561155621556315564155651556615567155681556915570155711557215573155741557515576155771557815579155801558115582155831558415585155861558715588155891559015591155921559315594155951559615597155981559915600156011560215603156041560515606156071560815609156101561115612156131561415615156161561715618156191562015621156221562315624156251562615627156281562915630156311563215633156341563515636156371563815639156401564115642156431564415645156461564715648156491565015651156521565315654156551565615657156581565915660156611566215663156641566515666156671566815669156701567115672156731567415675156761567715678156791568015681156821568315684156851568615687156881568915690156911569215693156941569515696156971569815699157001570115702157031570415705157061570715708157091571015711157121571315714157151571615717157181571915720157211572215723157241572515726157271572815729157301573115732157331573415735157361573715738157391574015741157421574315744157451574615747157481574915750157511575215753157541575515756157571575815759157601576115762157631576415765157661576715768157691577015771157721577315774157751577615777157781577915780157811578215783157841578515786157871578815789157901579115792157931579415795157961579715798157991580015801158021580315804158051580615807158081580915810158111581215813158141581515816158171581815819158201582115822158231582415825158261582715828158291583015831158321583315834158351583615837158381583915840158411584215843158441584515846158471584815849158501585115852158531585415855158561585715858158591586015861158621586315864158651586615867158681586915870158711587215873158741587515876158771587815879158801588115882158831588415885158861588715888158891589015891158921589315894158951589615897158981589915900159011590215903159041590515906159071590815909159101591115912159131591415915159161591715918159191592015921159221592315924159251592615927159281592915930159311593215933159341593515936159371593815939159401594115942159431594415945159461594715948159491595015951159521595315954159551595615957159581595915960159611596215963159641596515966159671596815969159701597115972159731597415975159761597715978159791598015981159821598315984159851598615987159881598915990159911599215993159941599515996159971599815999160001600116002160031600416005160061600716008160091601016011160121601316014160151601616017160181601916020160211602216023160241602516026160271602816029160301603116032160331603416035160361603716038160391604016041160421604316044160451604616047160481604916050160511605216053160541605516056160571605816059160601606116062160631606416065160661606716068160691607016071160721607316074160751607616077160781607916080160811608216083160841608516086160871608816089160901609116092160931609416095160961609716098160991610016101161021610316104161051610616107161081610916110161111611216113161141611516116161171611816119161201612116122161231612416125161261612716128161291613016131161321613316134161351613616137161381613916140161411614216143161441614516146161471614816149161501615116152161531615416155161561615716158161591616016161161621616316164161651616616167161681616916170161711617216173161741617516176161771617816179161801618116182161831618416185161861618716188161891619016191161921619316194161951619616197161981619916200162011620216203162041620516206162071620816209162101621116212162131621416215162161621716218162191622016221162221622316224162251622616227162281622916230162311623216233162341623516236162371623816239162401624116242162431624416245162461624716248162491625016251162521625316254162551625616257162581625916260162611626216263162641626516266162671626816269162701627116272162731627416275162761627716278162791628016281162821628316284162851628616287162881628916290162911629216293162941629516296162971629816299163001630116302163031630416305163061630716308163091631016311163121631316314163151631616317163181631916320163211632216323163241632516326163271632816329163301633116332163331633416335163361633716338163391634016341163421634316344163451634616347163481634916350163511635216353163541635516356163571635816359163601636116362163631636416365163661636716368163691637016371163721637316374163751637616377163781637916380163811638216383163841638516386163871638816389163901639116392163931639416395163961639716398163991640016401164021640316404164051640616407164081640916410164111641216413164141641516416164171641816419164201642116422164231642416425164261642716428164291643016431164321643316434164351643616437164381643916440164411644216443164441644516446164471644816449164501645116452164531645416455164561645716458164591646016461164621646316464164651646616467164681646916470164711647216473164741647516476164771647816479164801648116482164831648416485164861648716488164891649016491164921649316494164951649616497164981649916500165011650216503165041650516506165071650816509165101651116512165131651416515165161651716518165191652016521165221652316524165251652616527165281652916530165311653216533165341653516536165371653816539165401654116542165431654416545165461654716548165491655016551 | diff -Nur linux-3.15-rc5.orig/fs/Kconfig linux-3.15-rc5/fs/Kconfig--- linux-3.15-rc5.orig/fs/Kconfig	2014-05-09 22:10:52.000000000 +0200+++ linux-3.15-rc5/fs/Kconfig	2014-05-17 01:53:17.000000000 +0200@@ -190,6 +190,7 @@ source "fs/befs/Kconfig" source "fs/bfs/Kconfig" source "fs/efs/Kconfig"+source "fs/yaffs2/Kconfig" source "fs/jffs2/Kconfig" # UBIFS File system configuration source "fs/ubifs/Kconfig"diff -Nur linux-3.15-rc5.orig/fs/Makefile linux-3.15-rc5/fs/Makefile--- linux-3.15-rc5.orig/fs/Makefile	2014-05-09 22:10:52.000000000 +0200+++ linux-3.15-rc5/fs/Makefile	2014-05-17 01:53:25.000000000 +0200@@ -126,3 +126,4 @@ obj-$(CONFIG_CEPH_FS)		+= ceph/ obj-$(CONFIG_PSTORE)		+= pstore/ obj-$(CONFIG_EFIVAR_FS)		+= efivarfs/+obj-$(CONFIG_YAFFS_FS)		+= yaffs2/diff -Nur linux-3.15-rc5.orig/fs/yaffs2/Kconfig linux-3.15-rc5/fs/yaffs2/Kconfig--- linux-3.15-rc5.orig/fs/yaffs2/Kconfig	1970-01-01 01:00:00.000000000 +0100+++ linux-3.15-rc5/fs/yaffs2/Kconfig	2014-05-17 01:53:27.000000000 +0200@@ -0,0 +1,171 @@+#+# 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 File System, is a file 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_TAGS_ECC+	bool "Disable yaffs from doing ECC on tags by default"+	depends on YAFFS_FS && YAFFS_YAFFS2+	default n+	help+	  This defaults yaffs to using its own ECC calculations on tags instead of+	  just relying on the MTD.+	  This behavior can also be overridden with tags_ecc_on and+	  tags_ecc_off mount options.++	  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_EMPTY_LOST_AND_FOUND+	bool "Empty lost and found on boot"+	depends on YAFFS_FS+	default n+	help+	  If this is enabled then the contents of lost and found is+	  automatically dumped at mount.++	  If unsure, say N.++config YAFFS_DISABLE_BLOCK_REFRESHING+	bool "Disable yaffs2 block refreshing"+	depends on YAFFS_FS+	default n+	help+	 If this is set, then block refreshing is disabled.+	 Block refreshing infrequently refreshes the oldest block in+	 a yaffs2 file system. This mechanism helps to refresh flash to+	 mitigate against data loss. This is particularly useful for MLC.++	  If unsure, say N.++config YAFFS_DISABLE_BACKGROUND+	bool "Disable yaffs2 background processing"+	depends on YAFFS_FS+	default n+	help+	 If this is set, then background processing is disabled.+	 Background processing makes many foreground activities faster.++	 If unsure, say N.++config YAFFS_DISABLE_BAD_BLOCK_MARKING+	bool "Disable yaffs2 bad block marking"+	depends on YAFFS_FS+	default n+	help+	 Useful during early flash bring up to prevent problems causing+	 lots of bad block marking.++	 If unsure, say N.++config YAFFS_XATTR+	bool "Enable yaffs2 xattr support"+	depends on YAFFS_FS+	default y+	help+	 If this is set then yaffs2 will provide xattr support.+	 If unsure, say Y.diff -Nur linux-3.15-rc5.orig/fs/yaffs2/Makefile linux-3.15-rc5/fs/yaffs2/Makefile--- linux-3.15-rc5.orig/fs/yaffs2/Makefile	1970-01-01 01:00:00.000000000 +0100+++ linux-3.15-rc5/fs/yaffs2/Makefile	2014-05-17 01:53:27.000000000 +0200@@ -0,0 +1,18 @@+#+# Makefile for the linux YAFFS filesystem routines.+#++obj-$(CONFIG_YAFFS_FS) += yaffs.o++yaffs-y := yaffs_ecc.o yaffs_vfs.o yaffs_guts.o yaffs_checkptrw.o+yaffs-y += yaffs_packedtags1.o yaffs_packedtags2.o yaffs_nand.o+yaffs-y += yaffs_tagscompat.o yaffs_tagsmarshall.o+yaffs-y += yaffs_mtdif.o+yaffs-y += yaffs_nameval.o yaffs_attribs.o+yaffs-y += yaffs_allocator.o+yaffs-y += yaffs_yaffs1.o+yaffs-y += yaffs_yaffs2.o+yaffs-y += yaffs_bitmap.o+yaffs-y += yaffs_summary.o+yaffs-y += yaffs_verify.o+diff -Nur linux-3.15-rc5.orig/fs/yaffs2/yaffs_allocator.c linux-3.15-rc5/fs/yaffs2/yaffs_allocator.c--- linux-3.15-rc5.orig/fs/yaffs2/yaffs_allocator.c	1970-01-01 01:00:00.000000000 +0100+++ linux-3.15-rc5/fs/yaffs2/yaffs_allocator.c	2014-05-17 01:53:27.000000000 +0200@@ -0,0 +1,357 @@+/*+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.+ *+ * Copyright (C) 2002-2011 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_allocator.h"+#include "yaffs_guts.h"+#include "yaffs_trace.h"+#include "yportenv.h"++/*+ * Each entry in yaffs_tnode_list and yaffs_obj_list hold blocks+ * of approx 100 objects that are themn allocated singly.+ * This is basically a simplified slab allocator.+ *+ * We don't use the Linux slab allocator because slab does not allow+ * us to dump all the objects in one hit when we do a umount and tear+ * down  all the tnodes and objects. slab requires that we first free+ * the individual objects.+ *+ * Once yaffs has been mainlined I shall try to motivate for a change+ * to slab to provide the extra features we need here.+ */++struct yaffs_tnode_list {+	struct yaffs_tnode_list *next;+	struct yaffs_tnode *tnodes;+};++struct yaffs_obj_list {+	struct yaffs_obj_list *next;+	struct yaffs_obj *objects;+};++struct yaffs_allocator {+	int n_tnodes_created;+	struct yaffs_tnode *free_tnodes;+	int n_free_tnodes;+	struct yaffs_tnode_list *alloc_tnode_list;++	int n_obj_created;+	struct list_head free_objs;+	int n_free_objects;++	struct yaffs_obj_list *allocated_obj_list;+};++static void yaffs_deinit_raw_tnodes(struct yaffs_dev *dev)+{+	struct yaffs_allocator *allocator =+	    (struct yaffs_allocator *)dev->allocator;+	struct yaffs_tnode_list *tmp;++	if (!allocator) {+		BUG();+		return;+	}++	while (allocator->alloc_tnode_list) {+		tmp = allocator->alloc_tnode_list->next;++		kfree(allocator->alloc_tnode_list->tnodes);+		kfree(allocator->alloc_tnode_list);+		allocator->alloc_tnode_list = tmp;+	}++	allocator->free_tnodes = NULL;+	allocator->n_free_tnodes = 0;+	allocator->n_tnodes_created = 0;+}++static void yaffs_init_raw_tnodes(struct yaffs_dev *dev)+{+	struct yaffs_allocator *allocator = dev->allocator;++	if (!allocator) {+		BUG();+		return;+	}++	allocator->alloc_tnode_list = NULL;+	allocator->free_tnodes = NULL;+	allocator->n_free_tnodes = 0;+	allocator->n_tnodes_created = 0;+}++static int yaffs_create_tnodes(struct yaffs_dev *dev, int n_tnodes)+{+	struct yaffs_allocator *allocator =+	    (struct yaffs_allocator *)dev->allocator;+	int i;+	struct yaffs_tnode *new_tnodes;+	u8 *mem;+	struct yaffs_tnode *curr;+	struct yaffs_tnode *next;+	struct yaffs_tnode_list *tnl;++	if (!allocator) {+		BUG();+		return YAFFS_FAIL;+	}++	if (n_tnodes < 1)+		return YAFFS_OK;++	/* make these things */+	new_tnodes = kmalloc(n_tnodes * dev->tnode_size, GFP_NOFS);+	mem = (u8 *) new_tnodes;++	if (!new_tnodes) {+		yaffs_trace(YAFFS_TRACE_ERROR,+			"yaffs: Could not allocate Tnodes");+		return YAFFS_FAIL;+	}++	/* New hookup for wide tnodes */+	for (i = 0; i < n_tnodes - 1; i++) {+		curr = (struct yaffs_tnode *)&mem[i * dev->tnode_size];+		next = (struct yaffs_tnode *)&mem[(i + 1) * dev->tnode_size];+		curr->internal[0] = next;+	}++	curr = (struct yaffs_tnode *)&mem[(n_tnodes - 1) * dev->tnode_size];+	curr->internal[0] = allocator->free_tnodes;+	allocator->free_tnodes = (struct yaffs_tnode *)mem;++	allocator->n_free_tnodes += n_tnodes;+	allocator->n_tnodes_created += n_tnodes;++	/* 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 = kmalloc(sizeof(struct yaffs_tnode_list), GFP_NOFS);+	if (!tnl) {+		yaffs_trace(YAFFS_TRACE_ERROR,+			"Could not add tnodes to management list");+		return YAFFS_FAIL;+	} else {+		tnl->tnodes = new_tnodes;+		tnl->next = allocator->alloc_tnode_list;+		allocator->alloc_tnode_list = tnl;+	}++	yaffs_trace(YAFFS_TRACE_ALLOCATE, "Tnodes added");++	return YAFFS_OK;+}++struct yaffs_tnode *yaffs_alloc_raw_tnode(struct yaffs_dev *dev)+{+	struct yaffs_allocator *allocator =+	    (struct yaffs_allocator *)dev->allocator;+	struct yaffs_tnode *tn = NULL;++	if (!allocator) {+		BUG();+		return NULL;+	}++	/* If there are none left make more */+	if (!allocator->free_tnodes)+		yaffs_create_tnodes(dev, YAFFS_ALLOCATION_NTNODES);++	if (allocator->free_tnodes) {+		tn = allocator->free_tnodes;+		allocator->free_tnodes = allocator->free_tnodes->internal[0];+		allocator->n_free_tnodes--;+	}++	return tn;+}++/* FreeTnode frees up a tnode and puts it back on the free list */+void yaffs_free_raw_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn)+{+	struct yaffs_allocator *allocator = dev->allocator;++	if (!allocator) {+		BUG();+		return;+	}++	if (tn) {+		tn->internal[0] = allocator->free_tnodes;+		allocator->free_tnodes = tn;+		allocator->n_free_tnodes++;+	}+	dev->checkpoint_blocks_required = 0;	/* force recalculation */+}++/*--------------- yaffs_obj alloaction ------------------------+ *+ * Free yaffs_objs are stored in a list using obj->siblings.+ * The blocks of allocated objects are stored in a linked list.+ */++static void yaffs_init_raw_objs(struct yaffs_dev *dev)+{+	struct yaffs_allocator *allocator = dev->allocator;++	if (!allocator) {+		BUG();+		return;+	}++	allocator->allocated_obj_list = NULL;+	INIT_LIST_HEAD(&allocator->free_objs);+	allocator->n_free_objects = 0;+}++static void yaffs_deinit_raw_objs(struct yaffs_dev *dev)+{+	struct yaffs_allocator *allocator = dev->allocator;+	struct yaffs_obj_list *tmp;++	if (!allocator) {+		BUG();+		return;+	}++	while (allocator->allocated_obj_list) {+		tmp = allocator->allocated_obj_list->next;+		kfree(allocator->allocated_obj_list->objects);+		kfree(allocator->allocated_obj_list);+		allocator->allocated_obj_list = tmp;+	}++	INIT_LIST_HEAD(&allocator->free_objs);+	allocator->n_free_objects = 0;+	allocator->n_obj_created = 0;+}++static int yaffs_create_free_objs(struct yaffs_dev *dev, int n_obj)+{+	struct yaffs_allocator *allocator = dev->allocator;+	int i;+	struct yaffs_obj *new_objs;+	struct yaffs_obj_list *list;++	if (!allocator) {+		BUG();+		return YAFFS_FAIL;+	}++	if (n_obj < 1)+		return YAFFS_OK;++	/* make these things */+	new_objs = kmalloc(n_obj * sizeof(struct yaffs_obj), GFP_NOFS);+	list = kmalloc(sizeof(struct yaffs_obj_list), GFP_NOFS);++	if (!new_objs || !list) {+		kfree(new_objs);+		new_objs = NULL;+		kfree(list);+		list = NULL;+		yaffs_trace(YAFFS_TRACE_ALLOCATE,+			"Could not allocate more objects");+		return YAFFS_FAIL;+	}++	/* Hook them into the free list */+	for (i = 0; i < n_obj; i++)+		list_add(&new_objs[i].siblings, &allocator->free_objs);++	allocator->n_free_objects += n_obj;+	allocator->n_obj_created += n_obj;++	/* Now add this bunch of Objects to a list for freeing up. */++	list->objects = new_objs;+	list->next = allocator->allocated_obj_list;+	allocator->allocated_obj_list = list;++	return YAFFS_OK;+}++struct yaffs_obj *yaffs_alloc_raw_obj(struct yaffs_dev *dev)+{+	struct yaffs_obj *obj = NULL;+	struct list_head *lh;+	struct yaffs_allocator *allocator = dev->allocator;++	if (!allocator) {+		BUG();+		return obj;+	}++	/* If there are none left make more */+	if (list_empty(&allocator->free_objs))+		yaffs_create_free_objs(dev, YAFFS_ALLOCATION_NOBJECTS);++	if (!list_empty(&allocator->free_objs)) {+		lh = allocator->free_objs.next;+		obj = list_entry(lh, struct yaffs_obj, siblings);+		list_del_init(lh);+		allocator->n_free_objects--;+	}++	return obj;+}++void yaffs_free_raw_obj(struct yaffs_dev *dev, struct yaffs_obj *obj)+{++	struct yaffs_allocator *allocator = dev->allocator;++	if (!allocator) {+		BUG();+		return;+	}++	/* Link into the free list. */+	list_add(&obj->siblings, &allocator->free_objs);+	allocator->n_free_objects++;+}++void yaffs_deinit_raw_tnodes_and_objs(struct yaffs_dev *dev)+{++	if (!dev->allocator) {+		BUG();+		return;+	}++	yaffs_deinit_raw_tnodes(dev);+	yaffs_deinit_raw_objs(dev);+	kfree(dev->allocator);+	dev->allocator = NULL;+}++void yaffs_init_raw_tnodes_and_objs(struct yaffs_dev *dev)+{+	struct yaffs_allocator *allocator;++	if (dev->allocator) {+		BUG();+		return;+	}++	allocator = kmalloc(sizeof(struct yaffs_allocator), GFP_NOFS);+	if (allocator) {+		dev->allocator = allocator;+		yaffs_init_raw_tnodes(dev);+		yaffs_init_raw_objs(dev);+	}+}+diff -Nur linux-3.15-rc5.orig/fs/yaffs2/yaffs_allocator.h linux-3.15-rc5/fs/yaffs2/yaffs_allocator.h--- linux-3.15-rc5.orig/fs/yaffs2/yaffs_allocator.h	1970-01-01 01:00:00.000000000 +0100+++ linux-3.15-rc5/fs/yaffs2/yaffs_allocator.h	2014-05-17 01:53:27.000000000 +0200@@ -0,0 +1,30 @@+/*+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.+ *+ * Copyright (C) 2002-2011 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_ALLOCATOR_H__+#define __YAFFS_ALLOCATOR_H__++#include "yaffs_guts.h"++void yaffs_init_raw_tnodes_and_objs(struct yaffs_dev *dev);+void yaffs_deinit_raw_tnodes_and_objs(struct yaffs_dev *dev);++struct yaffs_tnode *yaffs_alloc_raw_tnode(struct yaffs_dev *dev);+void yaffs_free_raw_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn);++struct yaffs_obj *yaffs_alloc_raw_obj(struct yaffs_dev *dev);+void yaffs_free_raw_obj(struct yaffs_dev *dev, struct yaffs_obj *obj);++#endifdiff -Nur linux-3.15-rc5.orig/fs/yaffs2/yaffs_attribs.c linux-3.15-rc5/fs/yaffs2/yaffs_attribs.c--- linux-3.15-rc5.orig/fs/yaffs2/yaffs_attribs.c	1970-01-01 01:00:00.000000000 +0100+++ linux-3.15-rc5/fs/yaffs2/yaffs_attribs.c	2014-05-17 01:53:27.000000000 +0200@@ -0,0 +1,166 @@+/*+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.+ *+ * Copyright (C) 2002-2011 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_attribs.h"++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))+static inline uid_t ia_uid_read(const struct iattr *iattr)+{+	return from_kuid(&init_user_ns, iattr->ia_uid);+}++static inline gid_t ia_gid_read(const struct iattr *iattr)+{+	return from_kgid(&init_user_ns, iattr->ia_gid);+}++static inline void ia_uid_write(struct iattr *iattr, uid_t uid)+{+	iattr->ia_uid = make_kuid(&init_user_ns, uid);+}++static inline void ia_gid_write(struct iattr *iattr, gid_t gid)+{+	iattr->ia_gid = make_kgid(&init_user_ns, gid);+}+#else+static inline uid_t ia_uid_read(const struct iattr *iattr)+{+	return iattr->ia_uid;+}++static inline gid_t ia_gid_read(const struct iattr *inode)+{+	return iattr->ia_gid;+}++static inline void ia_uid_write(struct iattr *iattr, uid_t uid)+{+	iattr->ia_uid = uid;+}++static inline void ia_gid_write(struct iattr *iattr, gid_t gid)+{+	iattr->ia_gid = gid;+}+#endif++void yaffs_load_attribs(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh)+{+	obj->yst_uid = oh->yst_uid;+	obj->yst_gid = oh->yst_gid;+	obj->yst_atime = oh->yst_atime;+	obj->yst_mtime = oh->yst_mtime;+	obj->yst_ctime = oh->yst_ctime;+	obj->yst_rdev = oh->yst_rdev;+}++void yaffs_load_attribs_oh(struct yaffs_obj_hdr *oh, struct yaffs_obj *obj)+{+	oh->yst_uid = obj->yst_uid;+	oh->yst_gid = obj->yst_gid;+	oh->yst_atime = obj->yst_atime;+	oh->yst_mtime = obj->yst_mtime;+	oh->yst_ctime = obj->yst_ctime;+	oh->yst_rdev = obj->yst_rdev;++}++void yaffs_load_current_time(struct yaffs_obj *obj, int do_a, int do_c)+{+	obj->yst_mtime = Y_CURRENT_TIME;+	if (do_a)+		obj->yst_atime = obj->yst_mtime;+	if (do_c)+		obj->yst_ctime = obj->yst_mtime;+}++void yaffs_attribs_init(struct yaffs_obj *obj, u32 gid, u32 uid, u32 rdev)+{+	yaffs_load_current_time(obj, 1, 1);+	obj->yst_rdev = rdev;+	obj->yst_uid = uid;+	obj->yst_gid = gid;+}++static loff_t yaffs_get_file_size(struct yaffs_obj *obj)+{+	YCHAR *alias = NULL;+	obj = yaffs_get_equivalent_obj(obj);++	switch (obj->variant_type) {+	case YAFFS_OBJECT_TYPE_FILE:+		return obj->variant.file_variant.file_size;+	case YAFFS_OBJECT_TYPE_SYMLINK:+		alias = obj->variant.symlink_variant.alias;+		if (!alias)+			return 0;+		return strnlen(alias, YAFFS_MAX_ALIAS_LENGTH);+	default:+		return 0;+	}+}++int yaffs_set_attribs(struct yaffs_obj *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 =  ia_uid_read(attr);+	if (valid & ATTR_GID)+		obj->yst_gid =  ia_gid_read(attr);++	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_resize_file(obj, attr->ia_size);++	yaffs_update_oh(obj, NULL, 1, 0, 0, NULL);++	return YAFFS_OK;++}++int yaffs_get_attribs(struct yaffs_obj *obj, struct iattr *attr)+{+	unsigned int valid = 0;++	attr->ia_mode = obj->yst_mode;+	valid |= ATTR_MODE;+	ia_uid_write(attr, obj->yst_uid);+	valid |= ATTR_UID;+	ia_gid_write(attr, 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_get_file_size(obj);+	valid |= ATTR_SIZE;++	attr->ia_valid = valid;++	return YAFFS_OK;+}diff -Nur linux-3.15-rc5.orig/fs/yaffs2/yaffs_attribs.h linux-3.15-rc5/fs/yaffs2/yaffs_attribs.h--- linux-3.15-rc5.orig/fs/yaffs2/yaffs_attribs.h	1970-01-01 01:00:00.000000000 +0100+++ linux-3.15-rc5/fs/yaffs2/yaffs_attribs.h	2014-05-17 01:53:27.000000000 +0200@@ -0,0 +1,28 @@+/*+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.+ *+ * Copyright (C) 2002-2011 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_ATTRIBS_H__+#define __YAFFS_ATTRIBS_H__++#include "yaffs_guts.h"++void yaffs_load_attribs(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh);+void yaffs_load_attribs_oh(struct yaffs_obj_hdr *oh, struct yaffs_obj *obj);+void yaffs_attribs_init(struct yaffs_obj *obj, u32 gid, u32 uid, u32 rdev);+void yaffs_load_current_time(struct yaffs_obj *obj, int do_a, int do_c);+int yaffs_set_attribs(struct yaffs_obj *obj, struct iattr *attr);+int yaffs_get_attribs(struct yaffs_obj *obj, struct iattr *attr);++#endifdiff -Nur linux-3.15-rc5.orig/fs/yaffs2/yaffs_bitmap.c linux-3.15-rc5/fs/yaffs2/yaffs_bitmap.c--- linux-3.15-rc5.orig/fs/yaffs2/yaffs_bitmap.c	1970-01-01 01:00:00.000000000 +0100+++ linux-3.15-rc5/fs/yaffs2/yaffs_bitmap.c	2014-05-17 01:53:27.000000000 +0200@@ -0,0 +1,97 @@+/*+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.+ *+ * Copyright (C) 2002-2011 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_bitmap.h"+#include "yaffs_trace.h"+/*+ * Chunk bitmap manipulations+ */++static inline u8 *yaffs_block_bits(struct yaffs_dev *dev, int blk)+{+	if (blk < dev->internal_start_block || blk > dev->internal_end_block) {+		yaffs_trace(YAFFS_TRACE_ERROR,+			"BlockBits block %d is not valid",+			blk);+		BUG();+	}+	return dev->chunk_bits ++	    (dev->chunk_bit_stride * (blk - dev->internal_start_block));+}++void yaffs_verify_chunk_bit_id(struct yaffs_dev *dev, int blk, int chunk)+{+	if (blk < dev->internal_start_block || blk > dev->internal_end_block ||+	    chunk < 0 || chunk >= dev->param.chunks_per_block) {+		yaffs_trace(YAFFS_TRACE_ERROR,+			"Chunk Id (%d:%d) invalid",+			blk, chunk);+		BUG();+	}+}++void yaffs_clear_chunk_bits(struct yaffs_dev *dev, int blk)+{+	u8 *blk_bits = yaffs_block_bits(dev, blk);++	memset(blk_bits, 0, dev->chunk_bit_stride);+}++void yaffs_clear_chunk_bit(struct yaffs_dev *dev, int blk, int chunk)+{+	u8 *blk_bits = yaffs_block_bits(dev, blk);++	yaffs_verify_chunk_bit_id(dev, blk, chunk);+	blk_bits[chunk / 8] &= ~(1 << (chunk & 7));+}++void yaffs_set_chunk_bit(struct yaffs_dev *dev, int blk, int chunk)+{+	u8 *blk_bits = yaffs_block_bits(dev, blk);++	yaffs_verify_chunk_bit_id(dev, blk, chunk);+	blk_bits[chunk / 8] |= (1 << (chunk & 7));+}++int yaffs_check_chunk_bit(struct yaffs_dev *dev, int blk, int chunk)+{+	u8 *blk_bits = yaffs_block_bits(dev, blk);++	yaffs_verify_chunk_bit_id(dev, blk, chunk);+	return (blk_bits[chunk / 8] & (1 << (chunk & 7))) ? 1 : 0;+}++int yaffs_still_some_chunks(struct yaffs_dev *dev, int blk)+{+	u8 *blk_bits = yaffs_block_bits(dev, blk);+	int i;++	for (i = 0; i < dev->chunk_bit_stride; i++) {+		if (*blk_bits)+			return 1;+		blk_bits++;+	}+	return 0;+}++int yaffs_count_chunk_bits(struct yaffs_dev *dev, int blk)+{+	u8 *blk_bits = yaffs_block_bits(dev, blk);+	int i;+	int n = 0;++	for (i = 0; i < dev->chunk_bit_stride; i++, blk_bits++)+		n += hweight8(*blk_bits);++	return n;+}diff -Nur linux-3.15-rc5.orig/fs/yaffs2/yaffs_bitmap.h linux-3.15-rc5/fs/yaffs2/yaffs_bitmap.h--- linux-3.15-rc5.orig/fs/yaffs2/yaffs_bitmap.h	1970-01-01 01:00:00.000000000 +0100+++ linux-3.15-rc5/fs/yaffs2/yaffs_bitmap.h	2014-05-17 01:53:27.000000000 +0200@@ -0,0 +1,33 @@+/*+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.+ *+ * Copyright (C) 2002-2011 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.+ */++/*+ * Chunk bitmap manipulations+ */++#ifndef __YAFFS_BITMAP_H__+#define __YAFFS_BITMAP_H__++#include "yaffs_guts.h"++void yaffs_verify_chunk_bit_id(struct yaffs_dev *dev, int blk, int chunk);+void yaffs_clear_chunk_bits(struct yaffs_dev *dev, int blk);+void yaffs_clear_chunk_bit(struct yaffs_dev *dev, int blk, int chunk);+void yaffs_set_chunk_bit(struct yaffs_dev *dev, int blk, int chunk);+int yaffs_check_chunk_bit(struct yaffs_dev *dev, int blk, int chunk);+int yaffs_still_some_chunks(struct yaffs_dev *dev, int blk);+int yaffs_count_chunk_bits(struct yaffs_dev *dev, int blk);++#endifdiff -Nur linux-3.15-rc5.orig/fs/yaffs2/yaffs_checkptrw.c linux-3.15-rc5/fs/yaffs2/yaffs_checkptrw.c--- linux-3.15-rc5.orig/fs/yaffs2/yaffs_checkptrw.c	1970-01-01 01:00:00.000000000 +0100+++ linux-3.15-rc5/fs/yaffs2/yaffs_checkptrw.c	2014-05-17 01:53:27.000000000 +0200@@ -0,0 +1,474 @@+/*+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.+ *+ * Copyright (C) 2002-2011 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_checkptrw.h"+#include "yaffs_getblockinfo.h"++struct yaffs_checkpt_chunk_hdr {+	int version;+	int seq;+	u32 sum;+	u32 xor;+} ;+++static int apply_chunk_offset(struct yaffs_dev *dev, int chunk)+{+	return chunk - dev->chunk_offset;+}++static int apply_block_offset(struct yaffs_dev *dev, int block)+{+	return block - dev->block_offset;+}++static void yaffs2_checkpt_init_chunk_hdr(struct yaffs_dev *dev)+{+	struct yaffs_checkpt_chunk_hdr hdr;++	hdr.version = YAFFS_CHECKPOINT_VERSION;+	hdr.seq = dev->checkpt_page_seq;+	hdr.sum = dev->checkpt_sum;+	hdr.xor = dev->checkpt_xor;++	dev->checkpt_byte_offs = sizeof(hdr);++	memcpy(dev->checkpt_buffer, &hdr, sizeof(hdr));+}++static int yaffs2_checkpt_check_chunk_hdr(struct yaffs_dev *dev)+{+	struct yaffs_checkpt_chunk_hdr hdr;++	memcpy(&hdr, dev->checkpt_buffer, sizeof(hdr));++	dev->checkpt_byte_offs = sizeof(hdr);++	return hdr.version == YAFFS_CHECKPOINT_VERSION &&+		hdr.seq == dev->checkpt_page_seq &&+		hdr.sum == dev->checkpt_sum &&+		hdr.xor == dev->checkpt_xor;+}++static int yaffs2_checkpt_space_ok(struct yaffs_dev *dev)+{+	int blocks_avail = dev->n_erased_blocks - dev->param.n_reserved_blocks;++	yaffs_trace(YAFFS_TRACE_CHECKPOINT,+		"checkpt blocks_avail = %d", blocks_avail);++	return (blocks_avail <= 0) ? 0 : 1;+}++static int yaffs_checkpt_erase(struct yaffs_dev *dev)+{+	int i;++	if (!dev->drv.drv_erase_fn)+		return 0;+	yaffs_trace(YAFFS_TRACE_CHECKPOINT,+		"checking blocks %d to %d",+		dev->internal_start_block, dev->internal_end_block);++	for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {+		struct yaffs_block_info *bi = yaffs_get_block_info(dev, i);+		int offset_i = apply_block_offset(dev, i);+		int result;++		if (bi->block_state == YAFFS_BLOCK_STATE_CHECKPOINT) {+			yaffs_trace(YAFFS_TRACE_CHECKPOINT,+			"erasing checkpt block %d", i);++			dev->n_erasures++;++			result = dev->drv.drv_erase_fn(dev, offset_i);+			if(result) {+				bi->block_state = YAFFS_BLOCK_STATE_EMPTY;+				dev->n_erased_blocks++;+				dev->n_free_chunks +=+				    dev->param.chunks_per_block;+			} else {+				dev->drv.drv_mark_bad_fn(dev, offset_i);+				bi->block_state = YAFFS_BLOCK_STATE_DEAD;+			}+		}+	}++	dev->blocks_in_checkpt = 0;++	return 1;+}++static void yaffs2_checkpt_find_erased_block(struct yaffs_dev *dev)+{+	int i;+	int blocks_avail = dev->n_erased_blocks - dev->param.n_reserved_blocks;++	yaffs_trace(YAFFS_TRACE_CHECKPOINT,+		"allocating checkpt block: erased %d reserved %d avail %d next %d ",+		dev->n_erased_blocks, dev->param.n_reserved_blocks,+		blocks_avail, dev->checkpt_next_block);++	if (dev->checkpt_next_block >= 0 &&+	    dev->checkpt_next_block <= dev->internal_end_block &&+	    blocks_avail > 0) {++		for (i = dev->checkpt_next_block; i <= dev->internal_end_block;+		     i++) {+			struct yaffs_block_info *bi;++			bi = yaffs_get_block_info(dev, i);+			if (bi->block_state == YAFFS_BLOCK_STATE_EMPTY) {+				dev->checkpt_next_block = i + 1;+				dev->checkpt_cur_block = i;+				yaffs_trace(YAFFS_TRACE_CHECKPOINT,+					"allocating checkpt block %d", i);+				return;+			}+		}+	}+	yaffs_trace(YAFFS_TRACE_CHECKPOINT, "out of checkpt blocks");++	dev->checkpt_next_block = -1;+	dev->checkpt_cur_block = -1;+}++static void yaffs2_checkpt_find_block(struct yaffs_dev *dev)+{+	int i;+	struct yaffs_ext_tags tags;++	yaffs_trace(YAFFS_TRACE_CHECKPOINT,+		"find next checkpt block: start:  blocks %d next %d",+		dev->blocks_in_checkpt, dev->checkpt_next_block);++	if (dev->blocks_in_checkpt < dev->checkpt_max_blocks)+		for (i = dev->checkpt_next_block; i <= dev->internal_end_block;+		     i++) {+			int chunk = i * dev->param.chunks_per_block;+			enum yaffs_block_state state;+			u32 seq;++			dev->tagger.read_chunk_tags_fn(dev,+					apply_chunk_offset(dev, chunk),+					NULL, &tags);+			yaffs_trace(YAFFS_TRACE_CHECKPOINT,+				"find next checkpt block: search: block %d state %d oid %d seq %d eccr %d",+				i, (int) state,+				tags.obj_id, tags.seq_number,+				tags.ecc_result);++			if (tags.seq_number != YAFFS_SEQUENCE_CHECKPOINT_DATA)+				continue;++			dev->tagger.query_block_fn(dev,+						apply_block_offset(dev, i),+						&state, &seq);+			if (state == YAFFS_BLOCK_STATE_DEAD)+				continue;++			/* Right kind of block */+			dev->checkpt_next_block = tags.obj_id;+			dev->checkpt_cur_block = i;+			dev->checkpt_block_list[dev->blocks_in_checkpt] = i;+			dev->blocks_in_checkpt++;+			yaffs_trace(YAFFS_TRACE_CHECKPOINT,+				"found checkpt block %d", i);+			return;+		}++	yaffs_trace(YAFFS_TRACE_CHECKPOINT, "found no more checkpt blocks");++	dev->checkpt_next_block = -1;+	dev->checkpt_cur_block = -1;+}++int yaffs2_checkpt_open(struct yaffs_dev *dev, int writing)+{+	int i;++	dev->checkpt_open_write = writing;++	/* Got the functions we need? */+	if (!dev->tagger.write_chunk_tags_fn ||+	    !dev->tagger.read_chunk_tags_fn ||+	    !dev->drv.drv_erase_fn ||+	    !dev->drv.drv_mark_bad_fn)+		return 0;++	if (writing && !yaffs2_checkpt_space_ok(dev))+		return 0;++	if (!dev->checkpt_buffer)+		dev->checkpt_buffer =+		    kmalloc(dev->param.total_bytes_per_chunk, GFP_NOFS);+	if (!dev->checkpt_buffer)+		return 0;++	dev->checkpt_page_seq = 0;+	dev->checkpt_byte_count = 0;+	dev->checkpt_sum = 0;+	dev->checkpt_xor = 0;+	dev->checkpt_cur_block = -1;+	dev->checkpt_cur_chunk = -1;+	dev->checkpt_next_block = dev->internal_start_block;++	if (writing) {+		memset(dev->checkpt_buffer, 0, dev->data_bytes_per_chunk);+		yaffs2_checkpt_init_chunk_hdr(dev);+		return yaffs_checkpt_erase(dev);+	}++	/* Opening for a read */+	/* Set to a value that will kick off a read */+	dev->checkpt_byte_offs = dev->data_bytes_per_chunk;+	/* A checkpoint block list of 1 checkpoint block per 16 block is+	 * (hopefully) going to be way more than we need */+	dev->blocks_in_checkpt = 0;+	dev->checkpt_max_blocks =+	    (dev->internal_end_block - dev->internal_start_block) / 16 + 2;+	dev->checkpt_block_list =+	    kmalloc(sizeof(int) * dev->checkpt_max_blocks, GFP_NOFS);++	if (!dev->checkpt_block_list)+		return 0;++	for (i = 0; i < dev->checkpt_max_blocks; i++)+		dev->checkpt_block_list[i] = -1;++	return 1;+}++int yaffs2_get_checkpt_sum(struct yaffs_dev *dev, u32 * sum)+{+	u32 composite_sum;++	composite_sum = (dev->checkpt_sum << 8) | (dev->checkpt_xor & 0xff);+	*sum = composite_sum;+	return 1;+}++static int yaffs2_checkpt_flush_buffer(struct yaffs_dev *dev)+{+	int chunk;+	int offset_chunk;+	struct yaffs_ext_tags tags;++	if (dev->checkpt_cur_block < 0) {+		yaffs2_checkpt_find_erased_block(dev);+		dev->checkpt_cur_chunk = 0;+	}++	if (dev->checkpt_cur_block < 0)+		return 0;++	tags.is_deleted = 0;+	tags.obj_id = dev->checkpt_next_block;	/* Hint to next place to look */+	tags.chunk_id = dev->checkpt_page_seq + 1;+	tags.seq_number = YAFFS_SEQUENCE_CHECKPOINT_DATA;+	tags.n_bytes = dev->data_bytes_per_chunk;+	if (dev->checkpt_cur_chunk == 0) {+		/* First chunk we write for the block? Set block state to+		   checkpoint */+		struct yaffs_block_info *bi =+		    yaffs_get_block_info(dev, dev->checkpt_cur_block);+		bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT;+		dev->blocks_in_checkpt++;+	}++	chunk =+	    dev->checkpt_cur_block * dev->param.chunks_per_block ++	    dev->checkpt_cur_chunk;++	yaffs_trace(YAFFS_TRACE_CHECKPOINT,+		"checkpoint wite buffer nand %d(%d:%d) objid %d chId %d",+		chunk, dev->checkpt_cur_block, dev->checkpt_cur_chunk,+		tags.obj_id, tags.chunk_id);++	offset_chunk = apply_chunk_offset(dev, chunk);++	dev->n_page_writes++;++	dev->tagger.write_chunk_tags_fn(dev, offset_chunk,+				       dev->checkpt_buffer, &tags);+	dev->checkpt_page_seq++;+	dev->checkpt_cur_chunk++;+	if (dev->checkpt_cur_chunk >= dev->param.chunks_per_block) {+		dev->checkpt_cur_chunk = 0;+		dev->checkpt_cur_block = -1;+	}+	memset(dev->checkpt_buffer, 0, dev->data_bytes_per_chunk);++	yaffs2_checkpt_init_chunk_hdr(dev);+++	return 1;+}++int yaffs2_checkpt_wr(struct yaffs_dev *dev, const void *data, int n_bytes)+{+	int i = 0;+	int ok = 1;+	u8 *data_bytes = (u8 *) data;++	if (!dev->checkpt_buffer)+		return 0;++	if (!dev->checkpt_open_write)+		return -1;++	while (i < n_bytes && ok) {+		dev->checkpt_buffer[dev->checkpt_byte_offs] = *data_bytes;+		dev->checkpt_sum += *data_bytes;+		dev->checkpt_xor ^= *data_bytes;++		dev->checkpt_byte_offs++;+		i++;+		data_bytes++;+		dev->checkpt_byte_count++;++		if (dev->checkpt_byte_offs < 0 ||+		    dev->checkpt_byte_offs >= dev->data_bytes_per_chunk)+			ok = yaffs2_checkpt_flush_buffer(dev);+	}++	return i;+}++int yaffs2_checkpt_rd(struct yaffs_dev *dev, void *data, int n_bytes)+{+	int i = 0;+	int ok = 1;+	struct yaffs_ext_tags tags;+	int chunk;+	int offset_chunk;+	u8 *data_bytes = (u8 *) data;++	if (!dev->checkpt_buffer)+		return 0;++	if (dev->checkpt_open_write)+		return -1;++	while (i < n_bytes && ok) {++		if (dev->checkpt_byte_offs < 0 ||+		    dev->checkpt_byte_offs >= dev->data_bytes_per_chunk) {++			if (dev->checkpt_cur_block < 0) {+				yaffs2_checkpt_find_block(dev);+				dev->checkpt_cur_chunk = 0;+			}++			if (dev->checkpt_cur_block < 0) {+				ok = 0;+				break;+			}++			chunk = dev->checkpt_cur_block *+			    dev->param.chunks_per_block ++			    dev->checkpt_cur_chunk;++			offset_chunk = apply_chunk_offset(dev, chunk);+			dev->n_page_reads++;++			/* read in the next chunk */+			dev->tagger.read_chunk_tags_fn(dev,+						offset_chunk,+						dev->checkpt_buffer,+						&tags);++			if (tags.chunk_id != (dev->checkpt_page_seq + 1) ||+			    tags.ecc_result > YAFFS_ECC_RESULT_FIXED ||+			    tags.seq_number != YAFFS_SEQUENCE_CHECKPOINT_DATA) {+				ok = 0;+				break;+			}+			if(!yaffs2_checkpt_check_chunk_hdr(dev)) {+				ok = 0;+				break;+			}++			dev->checkpt_page_seq++;+			dev->checkpt_cur_chunk++;++			if (dev->checkpt_cur_chunk >=+					dev->param.chunks_per_block)+				dev->checkpt_cur_block = -1;++		}++		*data_bytes = dev->checkpt_buffer[dev->checkpt_byte_offs];+		dev->checkpt_sum += *data_bytes;+		dev->checkpt_xor ^= *data_bytes;+		dev->checkpt_byte_offs++;+		i++;+		data_bytes++;+		dev->checkpt_byte_count++;+	}++	return i;+}++int yaffs_checkpt_close(struct yaffs_dev *dev)+{+	int i;++	if (dev->checkpt_open_write) {+		if (dev->checkpt_byte_offs !=+			sizeof(sizeof(struct yaffs_checkpt_chunk_hdr)))+			yaffs2_checkpt_flush_buffer(dev);+	} else if (dev->checkpt_block_list) {+		for (i = 0;+		     i < dev->blocks_in_checkpt &&+		     dev->checkpt_block_list[i] >= 0; i++) {+			int blk = dev->checkpt_block_list[i];+			struct yaffs_block_info *bi = NULL;++			if (dev->internal_start_block <= blk &&+			    blk <= dev->internal_end_block)+				bi = yaffs_get_block_info(dev, blk);+			if (bi && bi->block_state == YAFFS_BLOCK_STATE_EMPTY)+				bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT;+		}+		kfree(dev->checkpt_block_list);+		dev->checkpt_block_list = NULL;+	}++	dev->n_free_chunks -=+		dev->blocks_in_checkpt * dev->param.chunks_per_block;+	dev->n_erased_blocks -= dev->blocks_in_checkpt;++	yaffs_trace(YAFFS_TRACE_CHECKPOINT, "checkpoint byte count %d",+		dev->checkpt_byte_count);++	if (dev->checkpt_buffer) {+		/* free the buffer */+		kfree(dev->checkpt_buffer);+		dev->checkpt_buffer = NULL;+		return 1;+	} else {+		return 0;+	}+}++int yaffs2_checkpt_invalidate_stream(struct yaffs_dev *dev)+{+	/* Erase the checkpoint data */++	yaffs_trace(YAFFS_TRACE_CHECKPOINT,+		"checkpoint invalidate of %d blocks",+		dev->blocks_in_checkpt);++	return yaffs_checkpt_erase(dev);+}diff -Nur linux-3.15-rc5.orig/fs/yaffs2/yaffs_checkptrw.h linux-3.15-rc5/fs/yaffs2/yaffs_checkptrw.h--- linux-3.15-rc5.orig/fs/yaffs2/yaffs_checkptrw.h	1970-01-01 01:00:00.000000000 +0100+++ linux-3.15-rc5/fs/yaffs2/yaffs_checkptrw.h	2014-05-17 01:53:27.000000000 +0200@@ -0,0 +1,33 @@+/*+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.+ *+ * Copyright (C) 2002-2011 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 yaffs2_checkpt_open(struct yaffs_dev *dev, int writing);++int yaffs2_checkpt_wr(struct yaffs_dev *dev, const void *data, int n_bytes);++int yaffs2_checkpt_rd(struct yaffs_dev *dev, void *data, int n_bytes);++int yaffs2_get_checkpt_sum(struct yaffs_dev *dev, u32 * sum);++int yaffs_checkpt_close(struct yaffs_dev *dev);++int yaffs2_checkpt_invalidate_stream(struct yaffs_dev *dev);++#endifdiff -Nur linux-3.15-rc5.orig/fs/yaffs2/yaffs_ecc.c linux-3.15-rc5/fs/yaffs2/yaffs_ecc.c--- linux-3.15-rc5.orig/fs/yaffs2/yaffs_ecc.c	1970-01-01 01:00:00.000000000 +0100+++ linux-3.15-rc5/fs/yaffs2/yaffs_ecc.c	2014-05-17 01:53:27.000000000 +0200@@ -0,0 +1,281 @@+/*+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.+ *+ * Copyright (C) 2002-2011 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.+ *+ */++#include "yportenv.h"++#include "yaffs_ecc.h"++/* 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.+ */++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,+};+++/* Calculate the ECC for a 256-byte block of data */+void yaffs_ecc_calc(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;++}++/* Correct the ECC on a 256 byte block of data */++int yaffs_ecc_correct(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;++		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 ((hweight8(d0) + hweight8(d1) + hweight8(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_ecc_calc_other(const unsigned char *data, unsigned n_bytes,+			  struct yaffs_ecc_other *ecc_other)+{+	unsigned int i;+	unsigned char col_parity = 0;+	unsigned line_parity = 0;+	unsigned line_parity_prime = 0;+	unsigned char b;++	for (i = 0; i < n_bytes; 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_other->col_parity = (col_parity >> 2) & 0x3f;+	ecc_other->line_parity = line_parity;+	ecc_other->line_parity_prime = line_parity_prime;+}++int yaffs_ecc_correct_other(unsigned char *data, unsigned n_bytes,+			    struct yaffs_ecc_other *read_ecc,+			    const struct yaffs_ecc_other *test_ecc)+{+	unsigned char delta_col;	/* column parity delta */+	unsigned delta_line;	/* line parity delta */+	unsigned delta_line_prime;	/* line parity delta */+	unsigned bit;++	delta_col = read_ecc->col_parity ^ test_ecc->col_parity;+	delta_line = read_ecc->line_parity ^ test_ecc->line_parity;+	delta_line_prime =+	    read_ecc->line_parity_prime ^ test_ecc->line_parity_prime;++	if ((delta_col | delta_line | delta_line_prime) == 0)+		return 0;	/* no error */++	if (delta_line == ~delta_line_prime &&+	    (((delta_col ^ (delta_col >> 1)) & 0x15) == 0x15)) {+		/* Single bit (recoverable) error in data */++		bit = 0;++		if (delta_col & 0x20)+			bit |= 0x04;+		if (delta_col & 0x08)+			bit |= 0x02;+		if (delta_col & 0x02)+			bit |= 0x01;++		if (delta_line >= n_bytes)+			return -1;++		data[delta_line] ^= (1 << bit);++		return 1;	/* corrected */+	}++	if ((hweight32(delta_line) ++	     hweight32(delta_line_prime) ++	     hweight8(delta_col)) == 1) {+		/* Reccoverable error in ecc */++		*read_ecc = *test_ecc;+		return 1;	/* corrected */+	}++	/* Unrecoverable error */++	return -1;+}diff -Nur linux-3.15-rc5.orig/fs/yaffs2/yaffs_ecc.h linux-3.15-rc5/fs/yaffs2/yaffs_ecc.h--- linux-3.15-rc5.orig/fs/yaffs2/yaffs_ecc.h	1970-01-01 01:00:00.000000000 +0100+++ linux-3.15-rc5/fs/yaffs2/yaffs_ecc.h	2014-05-17 01:53:27.000000000 +0200@@ -0,0 +1,44 @@+/*+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.+ *+ * Copyright (C) 2002-2011 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__++struct yaffs_ecc_other {+	unsigned char col_parity;+	unsigned line_parity;+	unsigned line_parity_prime;+};++void yaffs_ecc_calc(const unsigned char *data, unsigned char *ecc);+int yaffs_ecc_correct(unsigned char *data, unsigned char *read_ecc,+		      const unsigned char *test_ecc);++void yaffs_ecc_calc_other(const unsigned char *data, unsigned n_bytes,+			  struct yaffs_ecc_other *ecc);+int yaffs_ecc_correct_other(unsigned char *data, unsigned n_bytes,+			    struct yaffs_ecc_other *read_ecc,+			    const struct yaffs_ecc_other *test_ecc);+#endifdiff -Nur linux-3.15-rc5.orig/fs/yaffs2/yaffs_getblockinfo.h linux-3.15-rc5/fs/yaffs2/yaffs_getblockinfo.h--- linux-3.15-rc5.orig/fs/yaffs2/yaffs_getblockinfo.h	1970-01-01 01:00:00.000000000 +0100+++ linux-3.15-rc5/fs/yaffs2/yaffs_getblockinfo.h	2014-05-17 01:53:27.000000000 +0200@@ -0,0 +1,35 @@+/*+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.+ *+ * Copyright (C) 2002-2011 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"+#include "yaffs_trace.h"++/* Function to manipulate block info */+static inline struct yaffs_block_info *yaffs_get_block_info(struct yaffs_dev+							      *dev, int blk)+{+	if (blk < dev->internal_start_block || blk > dev->internal_end_block) {+		yaffs_trace(YAFFS_TRACE_ERROR,+			"**>> yaffs: get_block_info block %d is not valid",+			blk);+		BUG();+	}+	return &dev->block_info[blk - dev->internal_start_block];+}++#endifdiff -Nur linux-3.15-rc5.orig/fs/yaffs2/yaffs_guts.c linux-3.15-rc5/fs/yaffs2/yaffs_guts.c--- linux-3.15-rc5.orig/fs/yaffs2/yaffs_guts.c	1970-01-01 01:00:00.000000000 +0100+++ linux-3.15-rc5/fs/yaffs2/yaffs_guts.c	2014-05-17 01:53:27.000000000 +0200@@ -0,0 +1,5146 @@+/*+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.+ *+ * Copyright (C) 2002-2011 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 "yportenv.h"+#include "yaffs_trace.h"++#include "yaffs_guts.h"+#include "yaffs_getblockinfo.h"+#include "yaffs_tagscompat.h"+#include "yaffs_tagsmarshall.h"+#include "yaffs_nand.h"+#include "yaffs_yaffs1.h"+#include "yaffs_yaffs2.h"+#include "yaffs_bitmap.h"+#include "yaffs_verify.h"+#include "yaffs_nand.h"+#include "yaffs_packedtags2.h"+#include "yaffs_nameval.h"+#include "yaffs_allocator.h"+#include "yaffs_attribs.h"+#include "yaffs_summary.h"++/* Note YAFFS_GC_GOOD_ENOUGH must be <= YAFFS_GC_PASSIVE_THRESHOLD */+#define YAFFS_GC_GOOD_ENOUGH 2+#define YAFFS_GC_PASSIVE_THRESHOLD 4++#include "yaffs_ecc.h"++/* Forward declarations */++static int yaffs_wr_data_obj(struct yaffs_obj *in, int inode_chunk,+			     const u8 *buffer, int n_bytes, int use_reserve);++static void yaffs_fix_null_name(struct yaffs_obj *obj, YCHAR *name,+				int buffer_size);++/* Function to calculate chunk and offset */++void yaffs_addr_to_chunk(struct yaffs_dev *dev, loff_t addr,+				int *chunk_out, u32 *offset_out)+{+	int chunk;+	u32 offset;++	chunk = (u32) (addr >> dev->chunk_shift);++	if (dev->chunk_div == 1) {+		/* easy power of 2 case */+		offset = (u32) (addr & dev->chunk_mask);+	} else {+		/* Non power-of-2 case */++		loff_t chunk_base;++		chunk /= dev->chunk_div;++		chunk_base = ((loff_t) chunk) * dev->data_bytes_per_chunk;+		offset = (u32) (addr - chunk_base);+	}++	*chunk_out = chunk;+	*offset_out = 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 inline u32 calc_shifts_ceiling(u32 x)+{+	int extra_bits;+	int shifts;++	shifts = extra_bits = 0;++	while (x > 1) {+		if (x & 1)+			extra_bits++;+		x >>= 1;+		shifts++;+	}++	if (extra_bits)+		shifts++;++	return shifts;+}++/* Function to return the number of shifts to get a 1 in bit 0+ */++static inline u32 calc_shifts(u32 x)+{+	u32 shifts;++	shifts = 0;++	if (!x)+		return 0;++	while (!(x & 1)) {+		x >>= 1;+		shifts++;+	}++	return shifts;+}++/*+ * Temporary buffer manipulations.+ */++static int yaffs_init_tmp_buffers(struct yaffs_dev *dev)+{+	int i;+	u8 *buf = (u8 *) 1;++	memset(dev->temp_buffer, 0, sizeof(dev->temp_buffer));++	for (i = 0; buf && i < YAFFS_N_TEMP_BUFFERS; i++) {+		dev->temp_buffer[i].in_use = 0;+		buf = kmalloc(dev->param.total_bytes_per_chunk, GFP_NOFS);+		dev->temp_buffer[i].buffer = buf;+	}++	return buf ? YAFFS_OK : YAFFS_FAIL;+}++u8 *yaffs_get_temp_buffer(struct yaffs_dev * dev)+{+	int i;++	dev->temp_in_use++;+	if (dev->temp_in_use > dev->max_temp)+		dev->max_temp = dev->temp_in_use;++	for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {+		if (dev->temp_buffer[i].in_use == 0) {+			dev->temp_buffer[i].in_use = 1;+			return dev->temp_buffer[i].buffer;+		}+	}++	yaffs_trace(YAFFS_TRACE_BUFFERS, "Out of temp buffers");+	/*+	 * If we got here then we have to allocate an unmanaged one+	 * This is not good.+	 */++	dev->unmanaged_buffer_allocs++;+	return kmalloc(dev->data_bytes_per_chunk, GFP_NOFS);++}++void yaffs_release_temp_buffer(struct yaffs_dev *dev, u8 *buffer)+{+	int i;++	dev->temp_in_use--;++	for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {+		if (dev->temp_buffer[i].buffer == buffer) {+			dev->temp_buffer[i].in_use = 0;+			return;+		}+	}++	if (buffer) {+		/* assume it is an unmanaged one. */+		yaffs_trace(YAFFS_TRACE_BUFFERS,+			"Releasing unmanaged temp buffer");+		kfree(buffer);+		dev->unmanaged_buffer_deallocs++;+	}++}++/*+ * Functions for robustisizing TODO+ *+ */++static void yaffs_handle_chunk_wr_ok(struct yaffs_dev *dev, int nand_chunk,+				     const u8 *data,+				     const struct yaffs_ext_tags *tags)+{+	(void) dev;+	(void) nand_chunk;+	(void) data;+	(void) tags;+}++static void yaffs_handle_chunk_update(struct yaffs_dev *dev, int nand_chunk,+				      const struct yaffs_ext_tags *tags)+{+	(void) dev;+	(void) nand_chunk;+	(void) tags;+}++void yaffs_handle_chunk_error(struct yaffs_dev *dev,+			      struct yaffs_block_info *bi)+{+	if (!bi->gc_prioritise) {+		bi->gc_prioritise = 1;+		dev->has_pending_prioritised_gc = 1;+		bi->chunk_error_strikes++;++		if (bi->chunk_error_strikes > 3) {+			bi->needs_retiring = 1;	/* Too many stikes, so retire */+			yaffs_trace(YAFFS_TRACE_ALWAYS,+				"yaffs: Block struck out");++		}+	}+}++static void yaffs_handle_chunk_wr_error(struct yaffs_dev *dev, int nand_chunk,+					int erased_ok)+{+	int flash_block = nand_chunk / dev->param.chunks_per_block;+	struct yaffs_block_info *bi = yaffs_get_block_info(dev, flash_block);++	yaffs_handle_chunk_error(dev, bi);++	if (erased_ok) {+		/* Was an actual write failure,+		 * so mark the block for retirement.*/+		bi->needs_retiring = 1;+		yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,+		  "**>> Block %d needs retiring", flash_block);+	}++	/* Delete the chunk */+	yaffs_chunk_del(dev, nand_chunk, 1, __LINE__);+	yaffs_skip_rest_of_block(dev);+}++/*+ * Verification code+ */++/*+ *  Simple hash function. Needs to have a reasonable spread+ */++static inline int yaffs_hash_fn(int n)+{+	if (n < 0)+		n = -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.+ */++struct yaffs_obj *yaffs_root(struct yaffs_dev *dev)+{+	return dev->root_dir;+}++struct yaffs_obj *yaffs_lost_n_found(struct yaffs_dev *dev)+{+	return dev->lost_n_found;+}++/*+ *  Erased NAND checking functions+ */++int yaffs_check_ff(u8 *buffer, int n_bytes)+{+	/* Horrible, slow implementation */+	while (n_bytes--) {+		if (*buffer != 0xff)+			return 0;+		buffer++;+	}+	return 1;+}++static int yaffs_check_chunk_erased(struct yaffs_dev *dev, int nand_chunk)+{+	int retval = YAFFS_OK;+	u8 *data = yaffs_get_temp_buffer(dev);+	struct yaffs_ext_tags tags;+	int result;++	result = yaffs_rd_chunk_tags_nand(dev, nand_chunk, data, &tags);++	if (tags.ecc_result > YAFFS_ECC_RESULT_NO_ERROR)+		retval = YAFFS_FAIL;++	if (!yaffs_check_ff(data, dev->data_bytes_per_chunk) ||+		tags.chunk_used) {+		yaffs_trace(YAFFS_TRACE_NANDACCESS,+			"Chunk %d not erased", nand_chunk);+		retval = YAFFS_FAIL;+	}++	yaffs_release_temp_buffer(dev, data);++	return retval;++}++static int yaffs_verify_chunk_written(struct yaffs_dev *dev,+				      int nand_chunk,+				      const u8 *data,+				      struct yaffs_ext_tags *tags)+{+	int retval = YAFFS_OK;+	struct yaffs_ext_tags temp_tags;+	u8 *buffer = yaffs_get_temp_buffer(dev);+	int result;++	result = yaffs_rd_chunk_tags_nand(dev, nand_chunk, buffer, &temp_tags);+	if (memcmp(buffer, data, dev->data_bytes_per_chunk) ||+	    temp_tags.obj_id != tags->obj_id ||+	    temp_tags.chunk_id != tags->chunk_id ||+	    temp_tags.n_bytes != tags->n_bytes)+		retval = YAFFS_FAIL;++	yaffs_release_temp_buffer(dev, buffer);++	return retval;+}+++int yaffs_check_alloc_available(struct yaffs_dev *dev, int n_chunks)+{+	int reserved_chunks;+	int reserved_blocks = dev->param.n_reserved_blocks;+	int checkpt_blocks;++	checkpt_blocks = yaffs_calc_checkpt_blocks_required(dev);++	reserved_chunks =+	    (reserved_blocks + checkpt_blocks) * dev->param.chunks_per_block;++	return (dev->n_free_chunks > (reserved_chunks + n_chunks));+}++static int yaffs_find_alloc_block(struct yaffs_dev *dev)+{+	int i;+	struct yaffs_block_info *bi;++	if (dev->n_erased_blocks < 1) {+		/* Hoosterman we've got a problem.+		 * Can't get space to gc+		 */+		yaffs_trace(YAFFS_TRACE_ERROR,+		  "yaffs tragedy: no more erased blocks");++		return -1;+	}++	/* Find an empty block. */++	for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {+		dev->alloc_block_finder++;+		if (dev->alloc_block_finder < dev->internal_start_block+		    || dev->alloc_block_finder > dev->internal_end_block) {+			dev->alloc_block_finder = dev->internal_start_block;+		}++		bi = yaffs_get_block_info(dev, dev->alloc_block_finder);++		if (bi->block_state == YAFFS_BLOCK_STATE_EMPTY) {+			bi->block_state = YAFFS_BLOCK_STATE_ALLOCATING;+			dev->seq_number++;+			bi->seq_number = dev->seq_number;+			dev->n_erased_blocks--;+			yaffs_trace(YAFFS_TRACE_ALLOCATE,+			  "Allocated block %d, seq  %d, %d left" ,+			   dev->alloc_block_finder, dev->seq_number,+			   dev->n_erased_blocks);+			return dev->alloc_block_finder;+		}+	}++	yaffs_trace(YAFFS_TRACE_ALWAYS,+		"yaffs tragedy: no more erased blocks, but there should have been %d",+		dev->n_erased_blocks);++	return -1;+}++static int yaffs_alloc_chunk(struct yaffs_dev *dev, int use_reserver,+			     struct yaffs_block_info **block_ptr)+{+	int ret_val;+	struct yaffs_block_info *bi;++	if (dev->alloc_block < 0) {+		/* Get next block to allocate off */+		dev->alloc_block = yaffs_find_alloc_block(dev);+		dev->alloc_page = 0;+	}++	if (!use_reserver && !yaffs_check_alloc_available(dev, 1)) {+		/* No space unless we're allowed to use the reserve. */+		return -1;+	}++	if (dev->n_erased_blocks < dev->param.n_reserved_blocks+	    && dev->alloc_page == 0)+		yaffs_trace(YAFFS_TRACE_ALLOCATE, "Allocating reserve");++	/* Next page please.... */+	if (dev->alloc_block >= 0) {+		bi = yaffs_get_block_info(dev, dev->alloc_block);++		ret_val = (dev->alloc_block * dev->param.chunks_per_block) ++		    dev->alloc_page;+		bi->pages_in_use++;+		yaffs_set_chunk_bit(dev, dev->alloc_block, dev->alloc_page);++		dev->alloc_page++;++		dev->n_free_chunks--;++		/* If the block is full set the state to full */+		if (dev->alloc_page >= dev->param.chunks_per_block) {+			bi->block_state = YAFFS_BLOCK_STATE_FULL;+			dev->alloc_block = -1;+		}++		if (block_ptr)+			*block_ptr = bi;++		return ret_val;+	}++	yaffs_trace(YAFFS_TRACE_ERROR,+		"!!!!!!!!! Allocator out !!!!!!!!!!!!!!!!!");++	return -1;+}++static int yaffs_get_erased_chunks(struct yaffs_dev *dev)+{+	int n;++	n = dev->n_erased_blocks * dev->param.chunks_per_block;++	if (dev->alloc_block > 0)+		n += (dev->param.chunks_per_block - dev->alloc_page);++	return n;++}++/*+ * yaffs_skip_rest_of_block() skips over the rest of the allocation block+ * if we don't want to write to it.+ */+void yaffs_skip_rest_of_block(struct yaffs_dev *dev)+{+	struct yaffs_block_info *bi;++	if (dev->alloc_block > 0) {+		bi = yaffs_get_block_info(dev, dev->alloc_block);+		if (bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING) {+			bi->block_state = YAFFS_BLOCK_STATE_FULL;+			dev->alloc_block = -1;+		}+	}+}++static int yaffs_write_new_chunk(struct yaffs_dev *dev,+				 const u8 *data,+				 struct yaffs_ext_tags *tags, int use_reserver)+{+	int attempts = 0;+	int write_ok = 0;+	int chunk;++	yaffs2_checkpt_invalidate(dev);++	do {+		struct yaffs_block_info *bi = 0;+		int erased_ok = 0;++		chunk = yaffs_alloc_chunk(dev, use_reserver, &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.+		 *+		 * Mods to the above+		 * If an erase check fails or the write fails we skip the+		 * rest of the block.+		 */++		/* let's give it a try */+		attempts++;++		if (dev->param.always_check_erased)+			bi->skip_erased_check = 0;++		if (!bi->skip_erased_check) {+			erased_ok = yaffs_check_chunk_erased(dev, chunk);+			if (erased_ok != YAFFS_OK) {+				yaffs_trace(YAFFS_TRACE_ERROR,+				  "**>> yaffs chunk %d was not erased",+				  chunk);++				/* If not erased, delete this one,+				 * skip rest of block and+				 * try another chunk */+				yaffs_chunk_del(dev, chunk, 1, __LINE__);+				yaffs_skip_rest_of_block(dev);+				continue;+			}+		}++		write_ok = yaffs_wr_chunk_tags_nand(dev, chunk, data, tags);++		if (!bi->skip_erased_check)+			write_ok =+			    yaffs_verify_chunk_written(dev, chunk, data, tags);++		if (write_ok != YAFFS_OK) {+			/* Clean up aborted write, skip to next block and+			 * try another chunk */+			yaffs_handle_chunk_wr_error(dev, chunk, erased_ok);+			continue;+		}++		bi->skip_erased_check = 1;++		/* Copy the data into the robustification buffer */+		yaffs_handle_chunk_wr_ok(dev, chunk, data, tags);++	} while (write_ok != YAFFS_OK &&+		 (yaffs_wr_attempts <= 0 || attempts <= yaffs_wr_attempts));++	if (!write_ok)+		chunk = -1;++	if (attempts > 1) {+		yaffs_trace(YAFFS_TRACE_ERROR,+			"**>> yaffs write required %d attempts",+			attempts);+		dev->n_retried_writes += (attempts - 1);+	}++	return chunk;+}++/*+ * Block retiring for handling a broken block.+ */++static void yaffs_retire_block(struct yaffs_dev *dev, int flash_block)+{+	struct yaffs_block_info *bi = yaffs_get_block_info(dev, flash_block);++	yaffs2_checkpt_invalidate(dev);++	yaffs2_clear_oldest_dirty_seq(dev, bi);++	if (yaffs_mark_bad(dev, flash_block) != YAFFS_OK) {+		if (yaffs_erase_block(dev, flash_block) != YAFFS_OK) {+			yaffs_trace(YAFFS_TRACE_ALWAYS,+				"yaffs: Failed to mark bad and erase block %d",+				flash_block);+		} else {+			struct yaffs_ext_tags tags;+			int chunk_id =+			    flash_block * dev->param.chunks_per_block;++			u8 *buffer = yaffs_get_temp_buffer(dev);++			memset(buffer, 0xff, dev->data_bytes_per_chunk);+			memset(&tags, 0, sizeof(tags));+			tags.seq_number = YAFFS_SEQUENCE_BAD_BLOCK;+			if (dev->tagger.write_chunk_tags_fn(dev, chunk_id -+							dev->chunk_offset,+							buffer,+							&tags) != YAFFS_OK)+				yaffs_trace(YAFFS_TRACE_ALWAYS,+					"yaffs: Failed to write bad block marker to block %d",+					flash_block);++			yaffs_release_temp_buffer(dev, buffer);+		}+	}++	bi->block_state = YAFFS_BLOCK_STATE_DEAD;+	bi->gc_prioritise = 0;+	bi->needs_retiring = 0;++	dev->n_retired_blocks++;+}++/*---------------- Name handling functions ------------*/++static u16 yaffs_calc_name_sum(const YCHAR *name)+{+	u16 sum = 0;+	u16 i = 1;++	if (!name)+		return 0;++	while ((*name) && i < (YAFFS_MAX_NAME_LENGTH / 2)) {++		/* 0x1f mask is case insensitive */+		sum += ((*name) & 0x1f) * i;+		i++;+		name++;+	}+	return sum;+}+++void yaffs_set_obj_name(struct yaffs_obj *obj, const YCHAR * name)+{+	memset(obj->short_name, 0, sizeof(obj->short_name));++	if (name && !name[0]) {+		yaffs_fix_null_name(obj, obj->short_name,+				YAFFS_SHORT_NAME_LENGTH);+		name = obj->short_name;+	} else if (name &&+		strnlen(name, YAFFS_SHORT_NAME_LENGTH + 1) <=+		YAFFS_SHORT_NAME_LENGTH)  {+		strcpy(obj->short_name, name);+	}++	obj->sum = yaffs_calc_name_sum(name);+}++void yaffs_set_obj_name_from_oh(struct yaffs_obj *obj,+				const struct yaffs_obj_hdr *oh)+{+#ifdef CONFIG_YAFFS_AUTO_UNICODE+	YCHAR tmp_name[YAFFS_MAX_NAME_LENGTH + 1];+	memset(tmp_name, 0, sizeof(tmp_name));+	yaffs_load_name_from_oh(obj->my_dev, tmp_name, oh->name,+				YAFFS_MAX_NAME_LENGTH + 1);+	yaffs_set_obj_name(obj, tmp_name);+#else+	yaffs_set_obj_name(obj, oh->name);+#endif+}++loff_t yaffs_max_file_size(struct yaffs_dev *dev)+{+	if(sizeof(loff_t) < 8)+		return YAFFS_MAX_FILE_SIZE_32;+	else+		return ((loff_t) YAFFS_MAX_CHUNK_ID) * dev->data_bytes_per_chunk;+}++/*-------------------- TNODES -------------------++ * List of spare tnodes+ * The list is hooked together using the first pointer+ * in the tnode.+ */++struct yaffs_tnode *yaffs_get_tnode(struct yaffs_dev *dev)+{+	struct yaffs_tnode *tn = yaffs_alloc_raw_tnode(dev);++	if (tn) {+		memset(tn, 0, dev->tnode_size);+		dev->n_tnodes++;+	}++	dev->checkpoint_blocks_required = 0;	/* force recalculation */++	return tn;+}++/* FreeTnode frees up a tnode and puts it back on the free list */+static void yaffs_free_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn)+{+	yaffs_free_raw_tnode(dev, tn);+	dev->n_tnodes--;+	dev->checkpoint_blocks_required = 0;	/* force recalculation */+}++static void yaffs_deinit_tnodes_and_objs(struct yaffs_dev *dev)+{+	yaffs_deinit_raw_tnodes_and_objs(dev);+	dev->n_obj = 0;+	dev->n_tnodes = 0;+}++static void yaffs_load_tnode_0(struct yaffs_dev *dev, struct yaffs_tnode *tn,+			unsigned pos, unsigned val)+{+	u32 *map = (u32 *) tn;+	u32 bit_in_map;+	u32 bit_in_word;+	u32 word_in_map;+	u32 mask;++	pos &= YAFFS_TNODES_LEVEL0_MASK;+	val >>= dev->chunk_grp_bits;++	bit_in_map = pos * dev->tnode_width;+	word_in_map = bit_in_map / 32;+	bit_in_word = bit_in_map & (32 - 1);++	mask = dev->tnode_mask << bit_in_word;++	map[word_in_map] &= ~mask;+	map[word_in_map] |= (mask & (val << bit_in_word));++	if (dev->tnode_width > (32 - bit_in_word)) {+		bit_in_word = (32 - bit_in_word);+		word_in_map++;+		mask =+		    dev->tnode_mask >> bit_in_word;+		map[word_in_map] &= ~mask;+		map[word_in_map] |= (mask & (val >> bit_in_word));+	}+}++u32 yaffs_get_group_base(struct yaffs_dev *dev, struct yaffs_tnode *tn,+			 unsigned pos)+{+	u32 *map = (u32 *) tn;+	u32 bit_in_map;+	u32 bit_in_word;+	u32 word_in_map;+	u32 val;++	pos &= YAFFS_TNODES_LEVEL0_MASK;++	bit_in_map = pos * dev->tnode_width;+	word_in_map = bit_in_map / 32;+	bit_in_word = bit_in_map & (32 - 1);++	val = map[word_in_map] >> bit_in_word;++	if (dev->tnode_width > (32 - bit_in_word)) {+		bit_in_word = (32 - bit_in_word);+		word_in_map++;+		val |= (map[word_in_map] << bit_in_word);+	}++	val &= dev->tnode_mask;+	val <<= dev->chunk_grp_bits;++	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 top_level+ * in the tree. 0 means only the level 0 tnode is in the tree.+ */++/* FindLevel0Tnode finds the level 0 tnode, if one exists. */+struct yaffs_tnode *yaffs_find_tnode_0(struct yaffs_dev *dev,+				       struct yaffs_file_var *file_struct,+				       u32 chunk_id)+{+	struct yaffs_tnode *tn = file_struct->top;+	u32 i;+	int required_depth;+	int level = file_struct->top_level;++	(void) dev;++	/* Check sane level and chunk Id */+	if (level < 0 || level > YAFFS_TNODES_MAX_LEVEL)+		return NULL;++	if (chunk_id > YAFFS_MAX_CHUNK_ID)+		return NULL;++	/* First check we're tall enough (ie enough top_level) */++	i = chunk_id >> YAFFS_TNODES_LEVEL0_BITS;+	required_depth = 0;+	while (i) {+		i >>= YAFFS_TNODES_INTERNAL_BITS;+		required_depth++;+	}++	if (required_depth > file_struct->top_level)+		return NULL;	/* Not tall enough, so we can't find it */++	/* Traverse down to level 0 */+	while (level > 0 && tn) {+		tn = tn->internal[(chunk_id >>+				   (YAFFS_TNODES_LEVEL0_BITS ++				    (level - 1) *+				    YAFFS_TNODES_INTERNAL_BITS)) &+				  YAFFS_TNODES_INTERNAL_MASK];+		level--;+	}++	return tn;+}++/* add_find_tnode_0 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.+ */++struct yaffs_tnode *yaffs_add_find_tnode_0(struct yaffs_dev *dev,+					   struct yaffs_file_var *file_struct,+					   u32 chunk_id,+					   struct yaffs_tnode *passed_tn)+{+	int required_depth;+	int i;+	int l;+	struct yaffs_tnode *tn;+	u32 x;++	/* Check sane level and page Id */+	if (file_struct->top_level < 0 ||+	    file_struct->top_level > YAFFS_TNODES_MAX_LEVEL)+		return NULL;++	if (chunk_id > YAFFS_MAX_CHUNK_ID)+		return NULL;++	/* First check we're tall enough (ie enough top_level) */++	x = chunk_id >> YAFFS_TNODES_LEVEL0_BITS;+	required_depth = 0;+	while (x) {+		x >>= YAFFS_TNODES_INTERNAL_BITS;+		required_depth++;+	}++	if (required_depth > file_struct->top_level) {+		/* Not tall enough, gotta make the tree taller */+		for (i = file_struct->top_level; i < required_depth; i++) {++			tn = yaffs_get_tnode(dev);++			if (tn) {+				tn->internal[0] = file_struct->top;+				file_struct->top = tn;+				file_struct->top_level++;+			} else {+				yaffs_trace(YAFFS_TRACE_ERROR,+					"yaffs: no more tnodes");+				return NULL;+			}+		}+	}++	/* Traverse down to level 0, adding anything we need */++	l = file_struct->top_level;+	tn = file_struct->top;++	if (l > 0) {+		while (l > 0 && tn) {+			x = (chunk_id >>+			     (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_get_tnode(dev);+				if (!tn->internal[x])+					return NULL;+			} else if (l == 1) {+				/* Looking from level 1 at level 0 */+				if (passed_tn) {+					/* If we already have one, release it */+					if (tn->internal[x])+						yaffs_free_tnode(dev,+							tn->internal[x]);+					tn->internal[x] = passed_tn;++				} else if (!tn->internal[x]) {+					/* Don't have one, none passed in */+					tn->internal[x] = yaffs_get_tnode(dev);+					if (!tn->internal[x])+						return NULL;+				}+			}++			tn = tn->internal[x];+			l--;+		}+	} else {+		/* top is level 0 */+		if (passed_tn) {+			memcpy(tn, passed_tn,+			       (dev->tnode_width * YAFFS_NTNODES_LEVEL0) / 8);+			yaffs_free_tnode(dev, passed_tn);+		}+	}++	return tn;+}++static int yaffs_tags_match(const struct yaffs_ext_tags *tags, int obj_id,+			    int chunk_obj)+{+	return (tags->chunk_id == chunk_obj &&+		tags->obj_id == obj_id &&+		!tags->is_deleted) ? 1 : 0;++}++static int yaffs_find_chunk_in_group(struct yaffs_dev *dev, int the_chunk,+					struct yaffs_ext_tags *tags, int obj_id,+					int inode_chunk)+{+	int j;++	for (j = 0; the_chunk && j < dev->chunk_grp_size; j++) {+		if (yaffs_check_chunk_bit+		    (dev, the_chunk / dev->param.chunks_per_block,+		     the_chunk % dev->param.chunks_per_block)) {++			if (dev->chunk_grp_size == 1)+				return the_chunk;+			else {+				yaffs_rd_chunk_tags_nand(dev, the_chunk, NULL,+							 tags);+				if (yaffs_tags_match(tags,+							obj_id, inode_chunk)) {+					/* found it; */+					return the_chunk;+				}+			}+		}+		the_chunk++;+	}+	return -1;+}++int yaffs_find_chunk_in_file(struct yaffs_obj *in, int inode_chunk,+				    struct yaffs_ext_tags *tags)+{+	/*Get the Tnode, then get the level 0 offset chunk offset */+	struct yaffs_tnode *tn;+	int the_chunk = -1;+	struct yaffs_ext_tags local_tags;+	int ret_val = -1;+	struct yaffs_dev *dev = in->my_dev;++	if (!tags) {+		/* Passed a NULL, so use our own tags space */+		tags = &local_tags;+	}++	tn = yaffs_find_tnode_0(dev, &in->variant.file_variant, inode_chunk);++	if (!tn)+		return ret_val;++	the_chunk = yaffs_get_group_base(dev, tn, inode_chunk);++	ret_val = yaffs_find_chunk_in_group(dev, the_chunk, tags, in->obj_id,+					      inode_chunk);+	return ret_val;+}++static int yaffs_find_del_file_chunk(struct yaffs_obj *in, int inode_chunk,+				     struct yaffs_ext_tags *tags)+{+	/* Get the Tnode, then get the level 0 offset chunk offset */+	struct yaffs_tnode *tn;+	int the_chunk = -1;+	struct yaffs_ext_tags local_tags;+	struct yaffs_dev *dev = in->my_dev;+	int ret_val = -1;++	if (!tags) {+		/* Passed a NULL, so use our own tags space */+		tags = &local_tags;+	}++	tn = yaffs_find_tnode_0(dev, &in->variant.file_variant, inode_chunk);++	if (!tn)+		return ret_val;++	the_chunk = yaffs_get_group_base(dev, tn, inode_chunk);++	ret_val = yaffs_find_chunk_in_group(dev, the_chunk, tags, in->obj_id,+					      inode_chunk);++	/* Delete the entry in the filestructure (if found) */+	if (ret_val != -1)+		yaffs_load_tnode_0(dev, tn, inode_chunk, 0);++	return ret_val;+}++int yaffs_put_chunk_in_file(struct yaffs_obj *in, int inode_chunk,+			    int nand_chunk, int in_scan)+{+	/* NB in_scan is zero unless scanning.+	 * For forward scanning, in_scan is > 0;+	 * for backward scanning in_scan is < 0+	 *+	 * nand_chunk = 0 is a dummy insert to make sure the tnodes are there.+	 */++	struct yaffs_tnode *tn;+	struct yaffs_dev *dev = in->my_dev;+	int existing_cunk;+	struct yaffs_ext_tags existing_tags;+	struct yaffs_ext_tags new_tags;+	unsigned existing_serial, new_serial;++	if (in->variant_type != 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 (!in_scan) {+			yaffs_trace(YAFFS_TRACE_ERROR,+				"yaffs tragedy:attempt to put data chunk into a non-file"+				);+			BUG();+		}++		yaffs_chunk_del(dev, nand_chunk, 1, __LINE__);+		return YAFFS_OK;+	}++	tn = yaffs_add_find_tnode_0(dev,+				    &in->variant.file_variant,+				    inode_chunk, NULL);+	if (!tn)+		return YAFFS_FAIL;++	if (!nand_chunk)+		/* Dummy insert, bail now */+		return YAFFS_OK;++	existing_cunk = yaffs_get_group_base(dev, tn, inode_chunk);++	if (in_scan != 0) {+		/* If we're scanning then we need to test for duplicates+		 * NB This does not need to be efficient since it should only+		 * 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 (existing_cunk > 0) {+			/* NB Right now existing chunk will not be real+			 * chunk_id if the chunk group size > 1+			 * 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.+			 * YAFFS1: Get both sets of tags and compare serial+			 * numbers.+			 */++			if (in_scan > 0) {+				/* Only do this for forward scanning */+				yaffs_rd_chunk_tags_nand(dev,+							 nand_chunk,+							 NULL, &new_tags);++				/* Do a proper find */+				existing_cunk =+				    yaffs_find_chunk_in_file(in, inode_chunk,+							     &existing_tags);+			}++			if (existing_cunk <= 0) {+				/*Hoosterman - how did this happen? */++				yaffs_trace(YAFFS_TRACE_ERROR,+					"yaffs tragedy: existing chunk < 0 in scan"+					);++			}++			/* NB The deleted flags should be false, otherwise+			 * the chunks will not be loaded during a scan+			 */++			if (in_scan > 0) {+				new_serial = new_tags.serial_number;+				existing_serial = existing_tags.serial_number;+			}++			if ((in_scan > 0) &&+			    (existing_cunk <= 0 ||+			     ((existing_serial + 1) & 3) == new_serial)) {+				/* Forward scanning.+				 * Use new+				 * Delete the old one and drop through to+				 * update the tnode+				 */+				yaffs_chunk_del(dev, existing_cunk, 1,+						__LINE__);+			} else {+				/* Backward scanning or we want to use the+				 * existing one+				 * Delete the new one and return early so that+				 * the tnode isn't changed+				 */+				yaffs_chunk_del(dev, nand_chunk, 1, __LINE__);+				return YAFFS_OK;+			}+		}++	}++	if (existing_cunk == 0)+		in->n_data_chunks++;++	yaffs_load_tnode_0(dev, tn, inode_chunk, nand_chunk);++	return YAFFS_OK;+}++static void yaffs_soft_del_chunk(struct yaffs_dev *dev, int chunk)+{+	struct yaffs_block_info *the_block;+	unsigned block_no;++	yaffs_trace(YAFFS_TRACE_DELETION, "soft delete chunk %d", chunk);++	block_no = chunk / dev->param.chunks_per_block;+	the_block = yaffs_get_block_info(dev, block_no);+	if (the_block) {+		the_block->soft_del_pages++;+		dev->n_free_chunks++;+		yaffs2_update_oldest_dirty_seq(dev, block_no, the_block);+	}+}++/* 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_soft_del_worker(struct yaffs_obj *in, struct yaffs_tnode *tn,+				 u32 level, int chunk_offset)+{+	int i;+	int the_chunk;+	int all_done = 1;+	struct yaffs_dev *dev = in->my_dev;++	if (!tn)+		return 1;++	if (level > 0) {+		for (i = YAFFS_NTNODES_INTERNAL - 1;+			all_done && i >= 0;+			i--) {+			if (tn->internal[i]) {+				all_done =+				    yaffs_soft_del_worker(in,+					tn->internal[i],+					level - 1,+					(chunk_offset <<+					YAFFS_TNODES_INTERNAL_BITS)+					+ i);+				if (all_done) {+					yaffs_free_tnode(dev,+						tn->internal[i]);+					tn->internal[i] = NULL;+				} else {+					/* Can this happen? */+				}+			}+		}+		return (all_done) ? 1 : 0;+	}++	/* level 0 */+	 for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0; i--) {+		the_chunk = yaffs_get_group_base(dev, tn, i);+		if (the_chunk) {+			yaffs_soft_del_chunk(dev, the_chunk);+			yaffs_load_tnode_0(dev, tn, i, 0);+		}+	}+	return 1;+}++static void yaffs_remove_obj_from_dir(struct yaffs_obj *obj)+{+	struct yaffs_dev *dev = obj->my_dev;+	struct yaffs_obj *parent;++	yaffs_verify_obj_in_dir(obj);+	parent = obj->parent;++	yaffs_verify_dir(parent);++	if (dev && dev->param.remove_obj_fn)+		dev->param.remove_obj_fn(obj);++	list_del_init(&obj->siblings);+	obj->parent = NULL;++	yaffs_verify_dir(parent);+}++void yaffs_add_obj_to_dir(struct yaffs_obj *directory, struct yaffs_obj *obj)+{+	if (!directory) {+		yaffs_trace(YAFFS_TRACE_ALWAYS,+			"tragedy: Trying to add an object to a null pointer directory"+			);+		BUG();+		return;+	}+	if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {+		yaffs_trace(YAFFS_TRACE_ALWAYS,+			"tragedy: Trying to add an object to a non-directory"+			);+		BUG();+	}++	if (obj->siblings.prev == NULL) {+		/* Not initialised */+		BUG();+	}++	yaffs_verify_dir(directory);++	yaffs_remove_obj_from_dir(obj);++	/* Now add it */+	list_add(&obj->siblings, &directory->variant.dir_variant.children);+	obj->parent = directory;++	if (directory == obj->my_dev->unlinked_dir+	    || directory == obj->my_dev->del_dir) {+		obj->unlinked = 1;+		obj->my_dev->n_unlinked_files++;+		obj->rename_allowed = 0;+	}++	yaffs_verify_dir(directory);+	yaffs_verify_obj_in_dir(obj);+}++static int yaffs_change_obj_name(struct yaffs_obj *obj,+				 struct yaffs_obj *new_dir,+				 const YCHAR *new_name, int force, int shadows)+{+	int unlink_op;+	int del_op;+	struct yaffs_obj *existing_target;++	if (new_dir == NULL)+		new_dir = obj->parent;	/* use the old directory */++	if (new_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {+		yaffs_trace(YAFFS_TRACE_ALWAYS,+			"tragedy: yaffs_change_obj_name: new_dir is not a directory"+			);+		BUG();+	}++	unlink_op = (new_dir == obj->my_dev->unlinked_dir);+	del_op = (new_dir == obj->my_dev->del_dir);++	existing_target = yaffs_find_by_name(new_dir, new_name);++	/* If the object is a file going into the unlinked directory,+	 *   then it is OK to just stuff it in since duplicate names are OK.+	 *   else only proceed if the new name does not exist and we're putting+	 *   it into a directory.+	 */+	if (!(unlink_op || del_op || force ||+	      shadows > 0 || !existing_target) ||+	      new_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)+		return YAFFS_FAIL;++	yaffs_set_obj_name(obj, new_name);+	obj->dirty = 1;+	yaffs_add_obj_to_dir(new_dir, obj);++	if (unlink_op)+		obj->unlinked = 1;++	/* If it is a deletion then we mark it as a shrink for gc  */+	if (yaffs_update_oh(obj, new_name, 0, del_op, shadows, NULL) >= 0)+		return YAFFS_OK;++	return YAFFS_FAIL;+}++/*------------------------ Short Operations Cache ------------------------------+ *   In many situations where there is no high level buffering  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 and the short op cache+ *   provides write buffering.+ *+ *   There are a small number (~10) of cache chunks per device so that we don't+ *   need a very intelligent search.+ */++static int yaffs_obj_cache_dirty(struct yaffs_obj *obj)+{+	struct yaffs_dev *dev = obj->my_dev;+	int i;+	struct yaffs_cache *cache;+	int n_caches = obj->my_dev->param.n_caches;++	for (i = 0; i < n_caches; i++) {+		cache = &dev->cache[i];+		if (cache->object == obj && cache->dirty)+			return 1;+	}++	return 0;+}++static void yaffs_flush_file_cache(struct yaffs_obj *obj)+{+	struct yaffs_dev *dev = obj->my_dev;+	int lowest = -99;	/* Stop compiler whining. */+	int i;+	struct yaffs_cache *cache;+	int chunk_written = 0;+	int n_caches = obj->my_dev->param.n_caches;++	if (n_caches < 1)+		return;+	do {+		cache = NULL;++		/* Find the lowest dirty chunk for this object */+		for (i = 0; i < n_caches; i++) {+			if (dev->cache[i].object == obj &&+			    dev->cache[i].dirty) {+				if (!cache ||+				    dev->cache[i].chunk_id < lowest) {+					cache = &dev->cache[i];+					lowest = cache->chunk_id;+				}+			}+		}++		if (cache && !cache->locked) {+			/* Write it out and free it up */+			chunk_written =+			    yaffs_wr_data_obj(cache->object,+					      cache->chunk_id,+					      cache->data,+					      cache->n_bytes, 1);+			cache->dirty = 0;+			cache->object = NULL;+		}+	} while (cache && chunk_written > 0);++	if (cache)+		/* Hoosterman, disk full while writing cache out. */+		yaffs_trace(YAFFS_TRACE_ERROR,+			"yaffs tragedy: no space during cache write");+}++/*yaffs_flush_whole_cache(dev)+ *+ *+ */++void yaffs_flush_whole_cache(struct yaffs_dev *dev)+{+	struct yaffs_obj *obj;+	int n_caches = dev->param.n_caches;+	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 < n_caches && !obj; i++) {+			if (dev->cache[i].object && dev->cache[i].dirty)+				obj = dev->cache[i].object;+		}+		if (obj)+			yaffs_flush_file_cache(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 struct yaffs_cache *yaffs_grab_chunk_worker(struct yaffs_dev *dev)+{+	int i;++	if (dev->param.n_caches > 0) {+		for (i = 0; i < dev->param.n_caches; i++) {+			if (!dev->cache[i].object)+				return &dev->cache[i];+		}+	}+	return NULL;+}++static struct yaffs_cache *yaffs_grab_chunk_cache(struct yaffs_dev *dev)+{+	struct yaffs_cache *cache;+	struct yaffs_obj *the_obj;+	int usage;+	int i;+	int pushout;++	if (dev->param.n_caches < 1)+		return NULL;++	/* Try find a non-dirty one... */++	cache = yaffs_grab_chunk_worker(dev);++	if (!cache) {+		/* They were all dirty, find the LRU object and flush+		 * its cache, then  find again.+		 * NB what's here is not very accurate,+		 * we actually flush the object with the LRU chunk.+		 */++		/* With locking we can't assume we can use entry zero,+		 * Set the_obj to a valid pointer for Coverity. */+		the_obj = dev->cache[0].object;+		usage = -1;+		cache = NULL;+		pushout = -1;++		for (i = 0; i < dev->param.n_caches; i++) {+			if (dev->cache[i].object &&+			    !dev->cache[i].locked &&+			    (dev->cache[i].last_use < usage ||+			    !cache)) {+				usage = dev->cache[i].last_use;+				the_obj = dev->cache[i].object;+				cache = &dev->cache[i];+				pushout = i;+			}+		}++		if (!cache || cache->dirty) {+			/* Flush and try again */+			yaffs_flush_file_cache(the_obj);+			cache = yaffs_grab_chunk_worker(dev);+		}+	}+	return cache;+}++/* Find a cached chunk */+static struct yaffs_cache *yaffs_find_chunk_cache(const struct yaffs_obj *obj,+						  int chunk_id)+{+	struct yaffs_dev *dev = obj->my_dev;+	int i;++	if (dev->param.n_caches < 1)+		return NULL;++	for (i = 0; i < dev->param.n_caches; i++) {+		if (dev->cache[i].object == obj &&+		    dev->cache[i].chunk_id == chunk_id) {+			dev->cache_hits++;++			return &dev->cache[i];+		}+	}+	return NULL;+}++/* Mark the chunk for the least recently used algorithym */+static void yaffs_use_cache(struct yaffs_dev *dev, struct yaffs_cache *cache,+			    int is_write)+{+	int i;++	if (dev->param.n_caches < 1)+		return;++	if (dev->cache_last_use < 0 ||+		dev->cache_last_use > 100000000) {+		/* Reset the cache usages */+		for (i = 1; i < dev->param.n_caches; i++)+			dev->cache[i].last_use = 0;++		dev->cache_last_use = 0;+	}+	dev->cache_last_use++;+	cache->last_use = dev->cache_last_use;++	if (is_write)+		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_invalidate_chunk_cache(struct yaffs_obj *object, int chunk_id)+{+	struct yaffs_cache *cache;++	if (object->my_dev->param.n_caches > 0) {+		cache = yaffs_find_chunk_cache(object, chunk_id);++		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_invalidate_whole_cache(struct yaffs_obj *in)+{+	int i;+	struct yaffs_dev *dev = in->my_dev;++	if (dev->param.n_caches > 0) {+		/* Invalidate it. */+		for (i = 0; i < dev->param.n_caches; i++) {+			if (dev->cache[i].object == in)+				dev->cache[i].object = NULL;+		}+	}+}++static void yaffs_unhash_obj(struct yaffs_obj *obj)+{+	int bucket;+	struct yaffs_dev *dev = obj->my_dev;++	/* If it is still linked into the bucket list, free from the list */+	if (!list_empty(&obj->hash_link)) {+		list_del_init(&obj->hash_link);+		bucket = yaffs_hash_fn(obj->obj_id);+		dev->obj_bucket[bucket].count--;+	}+}++/*  FreeObject frees up a Object and puts it back on the free list */+static void yaffs_free_obj(struct yaffs_obj *obj)+{+	struct yaffs_dev *dev;++	if (!obj) {+		BUG();+		return;+	}+	dev = obj->my_dev;+	yaffs_trace(YAFFS_TRACE_OS, "FreeObject %p inode %p",+		obj, obj->my_inode);+	if (obj->parent)+		BUG();+	if (!list_empty(&obj->siblings))+		BUG();++	if (obj->my_inode) {+		/* We're still hooked up to a cached inode.+		 * Don't delete now, but mark for later deletion+		 */+		obj->defered_free = 1;+		return;+	}++	yaffs_unhash_obj(obj);++	yaffs_free_raw_obj(dev, obj);+	dev->n_obj--;+	dev->checkpoint_blocks_required = 0;	/* force recalculation */+}++void yaffs_handle_defered_free(struct yaffs_obj *obj)+{+	if (obj->defered_free)+		yaffs_free_obj(obj);+}++static int yaffs_generic_obj_del(struct yaffs_obj *in)+{+	/* Iinvalidate the file's data in the cache, without flushing. */+	yaffs_invalidate_whole_cache(in);++	if (in->my_dev->param.is_yaffs2 && in->parent != in->my_dev->del_dir) {+		/* Move to unlinked directory so we have a deletion record */+		yaffs_change_obj_name(in, in->my_dev->del_dir, _Y("deleted"), 0,+				      0);+	}++	yaffs_remove_obj_from_dir(in);+	yaffs_chunk_del(in->my_dev, in->hdr_chunk, 1, __LINE__);+	in->hdr_chunk = 0;++	yaffs_free_obj(in);+	return YAFFS_OK;++}++static void yaffs_soft_del_file(struct yaffs_obj *obj)+{+	if (!obj->deleted ||+	    obj->variant_type != YAFFS_OBJECT_TYPE_FILE ||+	    obj->soft_del)+		return;++	if (obj->n_data_chunks <= 0) {+		/* Empty file with no duplicate object headers,+		 * just delete it immediately */+		yaffs_free_tnode(obj->my_dev, obj->variant.file_variant.top);+		obj->variant.file_variant.top = NULL;+		yaffs_trace(YAFFS_TRACE_TRACING,+			"yaffs: Deleting empty file %d",+			obj->obj_id);+		yaffs_generic_obj_del(obj);+	} else {+		yaffs_soft_del_worker(obj,+				      obj->variant.file_variant.top,+				      obj->variant.+				      file_variant.top_level, 0);+		obj->soft_del = 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.+ *+ * This function is recursive. For levels > 0 the function is called again on+ * any sub-tree. For level == 0 we just check if the sub-tree has data.+ * If there is no data in a subtree then it is pruned.+ */++static struct yaffs_tnode *yaffs_prune_worker(struct yaffs_dev *dev,+					      struct yaffs_tnode *tn, u32 level,+					      int del0)+{+	int i;+	int has_data;++	if (!tn)+		return tn;++	has_data = 0;++	if (level > 0) {+		for (i = 0; i < YAFFS_NTNODES_INTERNAL; i++) {+			if (tn->internal[i]) {+				tn->internal[i] =+				    yaffs_prune_worker(dev,+						tn->internal[i],+						level - 1,+						(i == 0) ? del0 : 1);+			}++			if (tn->internal[i])+				has_data++;+		}+	} else {+		int tnode_size_u32 = dev->tnode_size / sizeof(u32);+		u32 *map = (u32 *) tn;++		for (i = 0; !has_data && i < tnode_size_u32; i++) {+			if (map[i])+				has_data++;+		}+	}++	if (has_data == 0 && del0) {+		/* Free and return NULL */+		yaffs_free_tnode(dev, tn);+		tn = NULL;+	}+	return tn;+}++static int yaffs_prune_tree(struct yaffs_dev *dev,+			    struct yaffs_file_var *file_struct)+{+	int i;+	int has_data;+	int done = 0;+	struct yaffs_tnode *tn;++	if (file_struct->top_level < 1)+		return YAFFS_OK;++	file_struct->top =+	   yaffs_prune_worker(dev, file_struct->top, file_struct->top_level, 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 (file_struct->top_level && !done) {+		tn = file_struct->top;++		has_data = 0;+		for (i = 1; i < YAFFS_NTNODES_INTERNAL; i++) {+			if (tn->internal[i])+				has_data++;+		}++		if (!has_data) {+			file_struct->top = tn->internal[0];+			file_struct->top_level--;+			yaffs_free_tnode(dev, tn);+		} else {+			done = 1;+		}+	}++	return YAFFS_OK;+}++/*-------------------- End of File Structure functions.-------------------*/++/* alloc_empty_obj gets us a clean Object.*/+static struct yaffs_obj *yaffs_alloc_empty_obj(struct yaffs_dev *dev)+{+	struct yaffs_obj *obj = yaffs_alloc_raw_obj(dev);++	if (!obj)+		return obj;++	dev->n_obj++;++	/* Now sweeten it up... */++	memset(obj, 0, sizeof(struct yaffs_obj));+	obj->being_created = 1;++	obj->my_dev = dev;+	obj->hdr_chunk = 0;+	obj->variant_type = YAFFS_OBJECT_TYPE_UNKNOWN;+	INIT_LIST_HEAD(&(obj->hard_links));+	INIT_LIST_HEAD(&(obj->hash_link));+	INIT_LIST_HEAD(&obj->siblings);++	/* Now make the directory sane */+	if (dev->root_dir) {+		obj->parent = dev->root_dir;+		list_add(&(obj->siblings),+			 &dev->root_dir->variant.dir_variant.children);+	}++	/* Add it to the lost and found directory.+	 * NB Can't put root or lost-n-found in lost-n-found so+	 * check if lost-n-found exists first+	 */+	if (dev->lost_n_found)+		yaffs_add_obj_to_dir(dev->lost_n_found, obj);++	obj->being_created = 0;++	dev->checkpoint_blocks_required = 0;	/* force recalculation */++	return obj;+}++static int yaffs_find_nice_bucket(struct yaffs_dev *dev)+{+	int i;+	int l = 999;+	int lowest = 999999;++	/* Search for the shortest list or one that+	 * isn't too long.+	 */++	for (i = 0; i < 10 && lowest > 4; i++) {+		dev->bucket_finder++;+		dev->bucket_finder %= YAFFS_NOBJECT_BUCKETS;+		if (dev->obj_bucket[dev->bucket_finder].count < lowest) {+			lowest = dev->obj_bucket[dev->bucket_finder].count;+			l = dev->bucket_finder;+		}+	}++	return l;+}++static int yaffs_new_obj_id(struct yaffs_dev *dev)+{+	int bucket = yaffs_find_nice_bucket(dev);+	int found = 0;+	struct list_head *i;+	u32 n = (u32) bucket;++	/* Now find an object value that has not already been taken+	 * by scanning the list.+	 */++	while (!found) {+		found = 1;+		n += YAFFS_NOBJECT_BUCKETS;+		if (1 || dev->obj_bucket[bucket].count > 0) {+			list_for_each(i, &dev->obj_bucket[bucket].list) {+				/* If there is already one in the list */+				if (i && list_entry(i, struct yaffs_obj,+						    hash_link)->obj_id == n) {+					found = 0;+				}+			}+		}+	}+	return n;+}++static void yaffs_hash_obj(struct yaffs_obj *in)+{+	int bucket = yaffs_hash_fn(in->obj_id);+	struct yaffs_dev *dev = in->my_dev;++	list_add(&in->hash_link, &dev->obj_bucket[bucket].list);+	dev->obj_bucket[bucket].count++;+}++struct yaffs_obj *yaffs_find_by_number(struct yaffs_dev *dev, u32 number)+{+	int bucket = yaffs_hash_fn(number);+	struct list_head *i;+	struct yaffs_obj *in;++	list_for_each(i, &dev->obj_bucket[bucket].list) {+		/* Look if it is in the list */+		in = list_entry(i, struct yaffs_obj, hash_link);+		if (in->obj_id == number) {+			/* Don't show if it is defered free */+			if (in->defered_free)+				return NULL;+			return in;+		}+	}++	return NULL;+}++static struct yaffs_obj *yaffs_new_obj(struct yaffs_dev *dev, int number,+				enum yaffs_obj_type type)+{+	struct yaffs_obj *the_obj = NULL;+	struct yaffs_tnode *tn = NULL;++	if (number < 0)+		number = yaffs_new_obj_id(dev);++	if (type == YAFFS_OBJECT_TYPE_FILE) {+		tn = yaffs_get_tnode(dev);+		if (!tn)+			return NULL;+	}++	the_obj = yaffs_alloc_empty_obj(dev);+	if (!the_obj) {+		if (tn)+			yaffs_free_tnode(dev, tn);+		return NULL;+	}++	the_obj->fake = 0;+	the_obj->rename_allowed = 1;+	the_obj->unlink_allowed = 1;+	the_obj->obj_id = number;+	yaffs_hash_obj(the_obj);+	the_obj->variant_type = type;+	yaffs_load_current_time(the_obj, 1, 1);++	switch (type) {+	case YAFFS_OBJECT_TYPE_FILE:+		the_obj->variant.file_variant.file_size = 0;+		the_obj->variant.file_variant.scanned_size = 0;+		the_obj->variant.file_variant.shrink_size =+						yaffs_max_file_size(dev);+		the_obj->variant.file_variant.top_level = 0;+		the_obj->variant.file_variant.top = tn;+		break;+	case YAFFS_OBJECT_TYPE_DIRECTORY:+		INIT_LIST_HEAD(&the_obj->variant.dir_variant.children);+		INIT_LIST_HEAD(&the_obj->variant.dir_variant.dirty);+		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 the_obj;+}++static struct yaffs_obj *yaffs_create_fake_dir(struct yaffs_dev *dev,+					       int number, u32 mode)+{++	struct yaffs_obj *obj =+	    yaffs_new_obj(dev, number, YAFFS_OBJECT_TYPE_DIRECTORY);++	if (!obj)+		return NULL;++	obj->fake = 1;	/* it is fake so it might not use NAND */+	obj->rename_allowed = 0;+	obj->unlink_allowed = 0;+	obj->deleted = 0;+	obj->unlinked = 0;+	obj->yst_mode = mode;+	obj->my_dev = dev;+	obj->hdr_chunk = 0;	/* Not a valid chunk. */+	return obj;++}+++static void yaffs_init_tnodes_and_objs(struct yaffs_dev *dev)+{+	int i;++	dev->n_obj = 0;+	dev->n_tnodes = 0;+	yaffs_init_raw_tnodes_and_objs(dev);++	for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {+		INIT_LIST_HEAD(&dev->obj_bucket[i].list);+		dev->obj_bucket[i].count = 0;+	}+}++struct yaffs_obj *yaffs_find_or_create_by_number(struct yaffs_dev *dev,+						 int number,+						 enum yaffs_obj_type type)+{+	struct yaffs_obj *the_obj = NULL;++	if (number > 0)+		the_obj = yaffs_find_by_number(dev, number);++	if (!the_obj)+		the_obj = yaffs_new_obj(dev, number, type);++	return the_obj;++}++YCHAR *yaffs_clone_str(const YCHAR *str)+{+	YCHAR *new_str = NULL;+	int len;++	if (!str)+		str = _Y("");++	len = strnlen(str, YAFFS_MAX_ALIAS_LENGTH);+	new_str = kmalloc((len + 1) * sizeof(YCHAR), GFP_NOFS);+	if (new_str) {+		strncpy(new_str, str, len);+		new_str[len] = 0;+	}+	return new_str;++}+/*+ *yaffs_update_parent() handles fixing a directories mtime and ctime when a new+ * link (ie. name) is created or deleted in the directory.+ *+ * ie.+ *   create dir/a : update dir's mtime/ctime+ *   rm dir/a:   update dir's mtime/ctime+ *   modify dir/a: don't update dir's mtimme/ctime+ *+ * This can be handled immediately or defered. Defering helps reduce the number+ * of updates when many files in a directory are changed within a brief period.+ *+ * If the directory updating is defered then yaffs_update_dirty_dirs must be+ * called periodically.+ */++static void yaffs_update_parent(struct yaffs_obj *obj)+{+	struct yaffs_dev *dev;++	if (!obj)+		return;+	dev = obj->my_dev;+	obj->dirty = 1;+	yaffs_load_current_time(obj, 0, 1);+	if (dev->param.defered_dir_update) {+		struct list_head *link = &obj->variant.dir_variant.dirty;++		if (list_empty(link)) {+			list_add(link, &dev->dirty_dirs);+			yaffs_trace(YAFFS_TRACE_BACKGROUND,+			  "Added object %d to dirty directories",+			   obj->obj_id);+		}++	} else {+		yaffs_update_oh(obj, NULL, 0, 0, 0, NULL);+	}+}++void yaffs_update_dirty_dirs(struct yaffs_dev *dev)+{+	struct list_head *link;+	struct yaffs_obj *obj;+	struct yaffs_dir_var *d_s;+	union yaffs_obj_var *o_v;++	yaffs_trace(YAFFS_TRACE_BACKGROUND, "Update dirty directories");++	while (!list_empty(&dev->dirty_dirs)) {+		link = dev->dirty_dirs.next;+		list_del_init(link);++		d_s = list_entry(link, struct yaffs_dir_var, dirty);+		o_v = list_entry(d_s, union yaffs_obj_var, dir_variant);+		obj = list_entry(o_v, struct yaffs_obj, variant);++		yaffs_trace(YAFFS_TRACE_BACKGROUND, "Update directory %d",+			obj->obj_id);++		if (obj->dirty)+			yaffs_update_oh(obj, NULL, 0, 0, 0, NULL);+	}+}++/*+ * Mknod (create) a new object.+ * equiv_obj only has meaning for a hard link;+ * alias_str only has meaning for a symlink.+ * rdev only has meaning for devices (a subset of special objects)+ */++static struct yaffs_obj *yaffs_create_obj(enum yaffs_obj_type type,+					  struct yaffs_obj *parent,+					  const YCHAR *name,+					  u32 mode,+					  u32 uid,+					  u32 gid,+					  struct yaffs_obj *equiv_obj,+					  const YCHAR *alias_str, u32 rdev)+{+	struct yaffs_obj *in;+	YCHAR *str = NULL;+	struct yaffs_dev *dev = parent->my_dev;++	/* Check if the entry exists.+	 * If it does then fail the call since we don't want a dup. */+	if (yaffs_find_by_name(parent, name))+		return NULL;++	if (type == YAFFS_OBJECT_TYPE_SYMLINK) {+		str = yaffs_clone_str(alias_str);+		if (!str)+			return NULL;+	}++	in = yaffs_new_obj(dev, -1, type);++	if (!in) {+		kfree(str);+		return NULL;+	}++	in->hdr_chunk = 0;+	in->valid = 1;+	in->variant_type = type;++	in->yst_mode = mode;++	yaffs_attribs_init(in, gid, uid, rdev);++	in->n_data_chunks = 0;++	yaffs_set_obj_name(in, name);+	in->dirty = 1;++	yaffs_add_obj_to_dir(parent, in);++	in->my_dev = parent->my_dev;++	switch (type) {+	case YAFFS_OBJECT_TYPE_SYMLINK:+		in->variant.symlink_variant.alias = str;+		break;+	case YAFFS_OBJECT_TYPE_HARDLINK:+		in->variant.hardlink_variant.equiv_obj = equiv_obj;+		in->variant.hardlink_variant.equiv_id = equiv_obj->obj_id;+		list_add(&in->hard_links, &equiv_obj->hard_links);+		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_update_oh(in, name, 0, 0, 0, NULL) < 0) {+		/* Could not create the object header, fail */+		yaffs_del_obj(in);+		in = NULL;+	}++	if (in)+		yaffs_update_parent(parent);++	return in;+}++struct yaffs_obj *yaffs_create_file(struct yaffs_obj *parent,+				    const YCHAR *name, u32 mode, u32 uid,+				    u32 gid)+{+	return yaffs_create_obj(YAFFS_OBJECT_TYPE_FILE, parent, name, mode,+				uid, gid, NULL, NULL, 0);+}++struct yaffs_obj *yaffs_create_dir(struct yaffs_obj *parent, const YCHAR *name,+				   u32 mode, u32 uid, u32 gid)+{+	return yaffs_create_obj(YAFFS_OBJECT_TYPE_DIRECTORY, parent, name,+				mode, uid, gid, NULL, NULL, 0);+}++struct yaffs_obj *yaffs_create_special(struct yaffs_obj *parent,+				       const YCHAR *name, u32 mode, u32 uid,+				       u32 gid, u32 rdev)+{+	return yaffs_create_obj(YAFFS_OBJECT_TYPE_SPECIAL, parent, name, mode,+				uid, gid, NULL, NULL, rdev);+}++struct yaffs_obj *yaffs_create_symlink(struct yaffs_obj *parent,+				       const YCHAR *name, u32 mode, u32 uid,+				       u32 gid, const YCHAR *alias)+{+	return yaffs_create_obj(YAFFS_OBJECT_TYPE_SYMLINK, parent, name, mode,+				uid, gid, NULL, alias, 0);+}++/* yaffs_link_obj returns the object id of the equivalent object.*/+struct yaffs_obj *yaffs_link_obj(struct yaffs_obj *parent, const YCHAR * name,+				 struct yaffs_obj *equiv_obj)+{+	/* Get the real object in case we were fed a hard link obj */+	equiv_obj = yaffs_get_equivalent_obj(equiv_obj);++	if (yaffs_create_obj(YAFFS_OBJECT_TYPE_HARDLINK,+			parent, name, 0, 0, 0,+			equiv_obj, NULL, 0))+		return equiv_obj;++	return NULL;++}++++/*---------------------- Block Management and Page Allocation -------------*/++static void yaffs_deinit_blocks(struct yaffs_dev *dev)+{+	if (dev->block_info_alt && dev->block_info)+		vfree(dev->block_info);+	else+		kfree(dev->block_info);++	dev->block_info_alt = 0;++	dev->block_info = NULL;++	if (dev->chunk_bits_alt && dev->chunk_bits)+		vfree(dev->chunk_bits);+	else+		kfree(dev->chunk_bits);+	dev->chunk_bits_alt = 0;+	dev->chunk_bits = NULL;+}++static int yaffs_init_blocks(struct yaffs_dev *dev)+{+	int n_blocks = dev->internal_end_block - dev->internal_start_block + 1;++	dev->block_info = NULL;+	dev->chunk_bits = NULL;+	dev->alloc_block = -1;	/* force it to get a new one */++	/* If the first allocation strategy fails, thry the alternate one */+	dev->block_info =+		kmalloc(n_blocks * sizeof(struct yaffs_block_info), GFP_NOFS);+	if (!dev->block_info) {+		dev->block_info =+		    vmalloc(n_blocks * sizeof(struct yaffs_block_info));+		dev->block_info_alt = 1;+	} else {+		dev->block_info_alt = 0;+	}++	if (!dev->block_info)+		goto alloc_error;++	/* Set up dynamic blockinfo stuff. Round up bytes. */+	dev->chunk_bit_stride = (dev->param.chunks_per_block + 7) / 8;+	dev->chunk_bits =+		kmalloc(dev->chunk_bit_stride * n_blocks, GFP_NOFS);+	if (!dev->chunk_bits) {+		dev->chunk_bits =+		    vmalloc(dev->chunk_bit_stride * n_blocks);+		dev->chunk_bits_alt = 1;+	} else {+		dev->chunk_bits_alt = 0;+	}+	if (!dev->chunk_bits)+		goto alloc_error;+++	memset(dev->block_info, 0, n_blocks * sizeof(struct yaffs_block_info));+	memset(dev->chunk_bits, 0, dev->chunk_bit_stride * n_blocks);+	return YAFFS_OK;++alloc_error:+	yaffs_deinit_blocks(dev);+	return YAFFS_FAIL;+}+++void yaffs_block_became_dirty(struct yaffs_dev *dev, int block_no)+{+	struct yaffs_block_info *bi = yaffs_get_block_info(dev, block_no);+	int erased_ok = 0;+	int i;++	/* If the block is still healthy erase it and mark as clean.+	 * If the block has had a data failure, then retire it.+	 */++	yaffs_trace(YAFFS_TRACE_GC | YAFFS_TRACE_ERASE,+		"yaffs_block_became_dirty block %d state %d %s",+		block_no, bi->block_state,+		(bi->needs_retiring) ? "needs retiring" : "");++	yaffs2_clear_oldest_dirty_seq(dev, bi);++	bi->block_state = YAFFS_BLOCK_STATE_DIRTY;++	/* If this is the block being garbage collected then stop gc'ing */+	if (block_no == dev->gc_block)+		dev->gc_block = 0;++	/* If this block is currently the best candidate for gc+	 * then drop as a candidate */+	if (block_no == dev->gc_dirtiest) {+		dev->gc_dirtiest = 0;+		dev->gc_pages_in_use = 0;+	}++	if (!bi->needs_retiring) {+		yaffs2_checkpt_invalidate(dev);+		erased_ok = yaffs_erase_block(dev, block_no);+		if (!erased_ok) {+			dev->n_erase_failures++;+			yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,+			  "**>> Erasure failed %d", block_no);+		}+	}++	/* Verify erasure if needed */+	if (erased_ok &&+	    ((yaffs_trace_mask & YAFFS_TRACE_ERASE) ||+	     !yaffs_skip_verification(dev))) {+		for (i = 0; i < dev->param.chunks_per_block; i++) {+			if (!yaffs_check_chunk_erased(dev,+				block_no * dev->param.chunks_per_block + i)) {+				yaffs_trace(YAFFS_TRACE_ERROR,+					">>Block %d erasure supposedly OK, but chunk %d not erased",+					block_no, i);+			}+		}+	}++	if (!erased_ok) {+		/* We lost a block of free space */+		dev->n_free_chunks -= dev->param.chunks_per_block;+		yaffs_retire_block(dev, block_no);+		yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,+			"**>> Block %d retired", block_no);+		return;+	}++	/* Clean it up... */+	bi->block_state = YAFFS_BLOCK_STATE_EMPTY;+	bi->seq_number = 0;+	dev->n_erased_blocks++;+	bi->pages_in_use = 0;+	bi->soft_del_pages = 0;+	bi->has_shrink_hdr = 0;+	bi->skip_erased_check = 1;	/* Clean, so no need to check */+	bi->gc_prioritise = 0;+	bi->has_summary = 0;++	yaffs_clear_chunk_bits(dev, block_no);++	yaffs_trace(YAFFS_TRACE_ERASE, "Erased block %d", block_no);+}++static inline int yaffs_gc_process_chunk(struct yaffs_dev *dev,+					struct yaffs_block_info *bi,+					int old_chunk, u8 *buffer)+{+	int new_chunk;+	int mark_flash = 1;+	struct yaffs_ext_tags tags;+	struct yaffs_obj *object;+	int matching_chunk;+	int ret_val = YAFFS_OK;++	memset(&tags, 0, sizeof(tags));+	yaffs_rd_chunk_tags_nand(dev, old_chunk,+				 buffer, &tags);+	object = yaffs_find_by_number(dev, tags.obj_id);++	yaffs_trace(YAFFS_TRACE_GC_DETAIL,+		"Collecting chunk in block %d, %d %d %d ",+		dev->gc_chunk, tags.obj_id,+		tags.chunk_id, tags.n_bytes);++	if (object && !yaffs_skip_verification(dev)) {+		if (tags.chunk_id == 0)+			matching_chunk =+			    object->hdr_chunk;+		else if (object->soft_del)+			/* Defeat the test */+			matching_chunk = old_chunk;+		else+			matching_chunk =+			    yaffs_find_chunk_in_file+			    (object, tags.chunk_id,+			     NULL);++		if (old_chunk != matching_chunk)+			yaffs_trace(YAFFS_TRACE_ERROR,+				"gc: page in gc mismatch: %d %d %d %d",+				old_chunk,+				matching_chunk,+				tags.obj_id,+				tags.chunk_id);+	}++	if (!object) {+		yaffs_trace(YAFFS_TRACE_ERROR,+			"page %d in gc has no object: %d %d %d ",+			old_chunk,+			tags.obj_id, tags.chunk_id,+			tags.n_bytes);+	}++	if (object &&+	    object->deleted &&+	    object->soft_del && tags.chunk_id != 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.+		 */++		/* Free chunks already includes+		 * softdeleted chunks, how ever this+		 * chunk is going to soon be really+		 * deleted which will increment free+		 * chunks. We have to decrement free+		 * chunks so this works out properly.+		 */+		dev->n_free_chunks--;+		bi->soft_del_pages--;++		object->n_data_chunks--;+		if (object->n_data_chunks <= 0) {+			/* remeber to clean up obj */+			dev->gc_cleanup_list[dev->n_clean_ups] = tags.obj_id;+			dev->n_clean_ups++;+		}+		mark_flash = 0;+	} 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.serial_number++;+		dev->n_gc_copies++;++		if (tags.chunk_id == 0) {+			/* It is an object Id,+			 * We need to nuke the+			 * shrinkheader flags since its+			 * work is done.+			 * Also need to clean up+			 * shadowing.+			 */+			struct yaffs_obj_hdr *oh;+			oh = (struct yaffs_obj_hdr *) buffer;++			oh->is_shrink = 0;+			tags.extra_is_shrink = 0;+			oh->shadows_obj = 0;+			oh->inband_shadowed_obj_id = 0;+			tags.extra_shadows = 0;++			/* Update file size */+			if (object->variant_type == YAFFS_OBJECT_TYPE_FILE) {+				yaffs_oh_size_load(oh,+				    object->variant.file_variant.file_size);+				tags.extra_file_size =+				    object->variant.file_variant.file_size;+			}++			yaffs_verify_oh(object, oh, &tags, 1);+			new_chunk =+			    yaffs_write_new_chunk(dev, (u8 *) oh, &tags, 1);+		} else {+			new_chunk =+			    yaffs_write_new_chunk(dev, buffer, &tags, 1);+		}++		if (new_chunk < 0) {+			ret_val = YAFFS_FAIL;+		} else {++			/* Now fix up the Tnodes etc. */++			if (tags.chunk_id == 0) {+				/* It's a header */+				object->hdr_chunk = new_chunk;+				object->serial = tags.serial_number;+			} else {+				/* It's a data chunk */+				yaffs_put_chunk_in_file(object, tags.chunk_id,+							new_chunk, 0);+			}+		}+	}+	if (ret_val == YAFFS_OK)+		yaffs_chunk_del(dev, old_chunk, mark_flash, __LINE__);+	return ret_val;+}++static int yaffs_gc_block(struct yaffs_dev *dev, int block, int whole_block)+{+	int old_chunk;+	int ret_val = YAFFS_OK;+	int i;+	int is_checkpt_block;+	int max_copies;+	int chunks_before = yaffs_get_erased_chunks(dev);+	int chunks_after;+	struct yaffs_block_info *bi = yaffs_get_block_info(dev, block);++	is_checkpt_block = (bi->block_state == YAFFS_BLOCK_STATE_CHECKPOINT);++	yaffs_trace(YAFFS_TRACE_TRACING,+		"Collecting block %d, in use %d, shrink %d, whole_block %d",+		block, bi->pages_in_use, bi->has_shrink_hdr,+		whole_block);++	/*yaffs_verify_free_chunks(dev); */++	if (bi->block_state == YAFFS_BLOCK_STATE_FULL)+		bi->block_state = YAFFS_BLOCK_STATE_COLLECTING;++	bi->has_shrink_hdr = 0;	/* clear the flag so that the block can erase */++	dev->gc_disable = 1;++	yaffs_summary_gc(dev, block);++	if (is_checkpt_block || !yaffs_still_some_chunks(dev, block)) {+		yaffs_trace(YAFFS_TRACE_TRACING,+			"Collecting block %d that has no chunks in use",+			block);+		yaffs_block_became_dirty(dev, block);+	} else {++		u8 *buffer = yaffs_get_temp_buffer(dev);++		yaffs_verify_blk(dev, bi, block);++		max_copies = (whole_block) ? dev->param.chunks_per_block : 5;+		old_chunk = block * dev->param.chunks_per_block + dev->gc_chunk;++		for (/* init already done */ ;+		     ret_val == YAFFS_OK &&+		     dev->gc_chunk < dev->param.chunks_per_block &&+		     (bi->block_state == YAFFS_BLOCK_STATE_COLLECTING) &&+		     max_copies > 0;+		     dev->gc_chunk++, old_chunk++) {+			if (yaffs_check_chunk_bit(dev, block, dev->gc_chunk)) {+				/* Page is in use and might need to be copied */+				max_copies--;+				ret_val = yaffs_gc_process_chunk(dev, bi,+							old_chunk, buffer);+			}+		}+		yaffs_release_temp_buffer(dev, buffer);+	}++	yaffs_verify_collected_blk(dev, bi, block);++	if (bi->block_state == YAFFS_BLOCK_STATE_COLLECTING) {+		/*+		 * The gc did not complete. Set block state back to FULL+		 * because checkpointing does not restore gc.+		 */+		bi->block_state = YAFFS_BLOCK_STATE_FULL;+	} else {+		/* The gc completed. */+		/* Do any required cleanups */+		for (i = 0; i < dev->n_clean_ups; i++) {+			/* Time to delete the file too */+			struct yaffs_obj *object =+			    yaffs_find_by_number(dev, dev->gc_cleanup_list[i]);+			if (object) {+				yaffs_free_tnode(dev,+					  object->variant.file_variant.top);+				object->variant.file_variant.top = NULL;+				yaffs_trace(YAFFS_TRACE_GC,+					"yaffs: About to finally delete object %d",+					object->obj_id);+				yaffs_generic_obj_del(object);+				object->my_dev->n_deleted_files--;+			}++		}+		chunks_after = yaffs_get_erased_chunks(dev);+		if (chunks_before >= chunks_after)+			yaffs_trace(YAFFS_TRACE_GC,+				"gc did not increase free chunks before %d after %d",+				chunks_before, chunks_after);+		dev->gc_block = 0;+		dev->gc_chunk = 0;+		dev->n_clean_ups = 0;+	}++	dev->gc_disable = 0;++	return ret_val;+}++/*+ * find_gc_block() selects the dirtiest block (or close enough)+ * for garbage collection.+ */++static unsigned yaffs_find_gc_block(struct yaffs_dev *dev,+				    int aggressive, int background)+{+	int i;+	int iterations;+	unsigned selected = 0;+	int prioritised = 0;+	int prioritised_exist = 0;+	struct yaffs_block_info *bi;+	int threshold;++	/* First let's see if we need to grab a prioritised block */+	if (dev->has_pending_prioritised_gc && !aggressive) {+		dev->gc_dirtiest = 0;+		bi = dev->block_info;+		for (i = dev->internal_start_block;+		     i <= dev->internal_end_block && !selected; i++) {++			if (bi->gc_prioritise) {+				prioritised_exist = 1;+				if (bi->block_state == YAFFS_BLOCK_STATE_FULL &&+				    yaffs_block_ok_for_gc(dev, bi)) {+					selected = i;+					prioritised = 1;+				}+			}+			bi++;+		}++		/*+		 * If there is a prioritised block and none was selected then+		 * this happened because there is at least one old dirty block+		 * gumming up the works. Let's gc the oldest dirty block.+		 */++		if (prioritised_exist &&+		    !selected && dev->oldest_dirty_block > 0)+			selected = dev->oldest_dirty_block;++		if (!prioritised_exist)	/* None found, so we can clear this */+			dev->has_pending_prioritised_gc = 0;+	}++	/* If we're doing aggressive GC then we are happy to take a less-dirty+	 * block, and search harder.+	 * else (leasurely gc), then we only bother to do this if the+	 * block has only a few pages in use.+	 */++	if (!selected) {+		int pages_used;+		int n_blocks =+		    dev->internal_end_block - dev->internal_start_block + 1;+		if (aggressive) {+			threshold = dev->param.chunks_per_block;+			iterations = n_blocks;+		} else {+			int max_threshold;++			if (background)+				max_threshold = dev->param.chunks_per_block / 2;+			else+				max_threshold = dev->param.chunks_per_block / 8;++			if (max_threshold < YAFFS_GC_PASSIVE_THRESHOLD)+				max_threshold = YAFFS_GC_PASSIVE_THRESHOLD;++			threshold = background ? (dev->gc_not_done + 2) * 2 : 0;+			if (threshold < YAFFS_GC_PASSIVE_THRESHOLD)+				threshold = YAFFS_GC_PASSIVE_THRESHOLD;+			if (threshold > max_threshold)+				threshold = max_threshold;++			iterations = n_blocks / 16 + 1;+			if (iterations > 100)+				iterations = 100;+		}++		for (i = 0;+		     i < iterations &&+		     (dev->gc_dirtiest < 1 ||+		      dev->gc_pages_in_use > YAFFS_GC_GOOD_ENOUGH);+		     i++) {+			dev->gc_block_finder++;+			if (dev->gc_block_finder < dev->internal_start_block ||+			    dev->gc_block_finder > dev->internal_end_block)+				dev->gc_block_finder =+				    dev->internal_start_block;++			bi = yaffs_get_block_info(dev, dev->gc_block_finder);++			pages_used = bi->pages_in_use - bi->soft_del_pages;++			if (bi->block_state == YAFFS_BLOCK_STATE_FULL &&+			    pages_used < dev->param.chunks_per_block &&+			    (dev->gc_dirtiest < 1 ||+			     pages_used < dev->gc_pages_in_use) &&+			    yaffs_block_ok_for_gc(dev, bi)) {+				dev->gc_dirtiest = dev->gc_block_finder;+				dev->gc_pages_in_use = pages_used;+			}+		}++		if (dev->gc_dirtiest > 0 && dev->gc_pages_in_use <= threshold)+			selected = dev->gc_dirtiest;+	}++	/*+	 * If nothing has been selected for a while, try the oldest dirty+	 * because that's gumming up the works.+	 */++	if (!selected && dev->param.is_yaffs2 &&+	    dev->gc_not_done >= (background ? 10 : 20)) {+		yaffs2_find_oldest_dirty_seq(dev);+		if (dev->oldest_dirty_block > 0) {+			selected = dev->oldest_dirty_block;+			dev->gc_dirtiest = selected;+			dev->oldest_dirty_gc_count++;+			bi = yaffs_get_block_info(dev, selected);+			dev->gc_pages_in_use =+			    bi->pages_in_use - bi->soft_del_pages;+		} else {+			dev->gc_not_done = 0;+		}+	}++	if (selected) {+		yaffs_trace(YAFFS_TRACE_GC,+			"GC Selected block %d with %d free, prioritised:%d",+			selected,+			dev->param.chunks_per_block - dev->gc_pages_in_use,+			prioritised);++		dev->n_gc_blocks++;+		if (background)+			dev->bg_gcs++;++		dev->gc_dirtiest = 0;+		dev->gc_pages_in_use = 0;+		dev->gc_not_done = 0;+		if (dev->refresh_skip > 0)+			dev->refresh_skip--;+	} else {+		dev->gc_not_done++;+		yaffs_trace(YAFFS_TRACE_GC,+			"GC none: finder %d skip %d threshold %d dirtiest %d using %d oldest %d%s",+			dev->gc_block_finder, dev->gc_not_done, threshold,+			dev->gc_dirtiest, dev->gc_pages_in_use,+			dev->oldest_dirty_block, background ? " bg" : "");+	}++	return selected;+}++/* 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 only accepts 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_check_gc(struct yaffs_dev *dev, int background)+{+	int aggressive = 0;+	int gc_ok = YAFFS_OK;+	int max_tries = 0;+	int min_erased;+	int erased_chunks;+	int checkpt_block_adjust;++	if (dev->param.gc_control_fn &&+		(dev->param.gc_control_fn(dev) & 1) == 0)+		return YAFFS_OK;++	if (dev->gc_disable)+		/* Bail out so we don't get recursive gc */+		return YAFFS_OK;++	/* This loop should pass the first time.+	 * Only loops here if the collection does not increase space.+	 */++	do {+		max_tries++;++		checkpt_block_adjust = yaffs_calc_checkpt_blocks_required(dev);++		min_erased =+		    dev->param.n_reserved_blocks + checkpt_block_adjust + 1;+		erased_chunks =+		    dev->n_erased_blocks * dev->param.chunks_per_block;++		/* If we need a block soon then do aggressive gc. */+		if (dev->n_erased_blocks < min_erased)+			aggressive = 1;+		else {+			if (!background+			    && erased_chunks > (dev->n_free_chunks / 4))+				break;++			if (dev->gc_skip > 20)+				dev->gc_skip = 20;+			if (erased_chunks < dev->n_free_chunks / 2 ||+			    dev->gc_skip < 1 || background)+				aggressive = 0;+			else {+				dev->gc_skip--;+				break;+			}+		}++		dev->gc_skip = 5;++		/* If we don't already have a block being gc'd then see if we+		 * should start another */++		if (dev->gc_block < 1 && !aggressive) {+			dev->gc_block = yaffs2_find_refresh_block(dev);+			dev->gc_chunk = 0;+			dev->n_clean_ups = 0;+		}+		if (dev->gc_block < 1) {+			dev->gc_block =+			    yaffs_find_gc_block(dev, aggressive, background);+			dev->gc_chunk = 0;+			dev->n_clean_ups = 0;+		}++		if (dev->gc_block > 0) {+			dev->all_gcs++;+			if (!aggressive)+				dev->passive_gc_count++;++			yaffs_trace(YAFFS_TRACE_GC,+				"yaffs: GC n_erased_blocks %d aggressive %d",+				dev->n_erased_blocks, aggressive);++			gc_ok = yaffs_gc_block(dev, dev->gc_block, aggressive);+		}++		if (dev->n_erased_blocks < (dev->param.n_reserved_blocks) &&+		    dev->gc_block > 0) {+			yaffs_trace(YAFFS_TRACE_GC,+				"yaffs: GC !!!no reclaim!!! n_erased_blocks %d after try %d block %d",+				dev->n_erased_blocks, max_tries,+				dev->gc_block);+		}+	} while ((dev->n_erased_blocks < dev->param.n_reserved_blocks) &&+		 (dev->gc_block > 0) && (max_tries < 2));++	return aggressive ? gc_ok : YAFFS_OK;+}++/*+ * yaffs_bg_gc()+ * Garbage collects. Intended to be called from a background thread.+ * Returns non-zero if at least half the free chunks are erased.+ */+int yaffs_bg_gc(struct yaffs_dev *dev, unsigned urgency)+{+	int erased_chunks = dev->n_erased_blocks * dev->param.chunks_per_block;++	yaffs_trace(YAFFS_TRACE_BACKGROUND, "Background gc %u", urgency);++	yaffs_check_gc(dev, 1);+	return erased_chunks > dev->n_free_chunks / 2;+}++/*-------------------- Data file manipulation -----------------*/++static int yaffs_rd_data_obj(struct yaffs_obj *in, int inode_chunk, u8 * buffer)+{+	int nand_chunk = yaffs_find_chunk_in_file(in, inode_chunk, NULL);++	if (nand_chunk >= 0)+		return yaffs_rd_chunk_tags_nand(in->my_dev, nand_chunk,+						buffer, NULL);+	else {+		yaffs_trace(YAFFS_TRACE_NANDACCESS,+			"Chunk %d not found zero instead",+			nand_chunk);+		/* get sane (zero) data if you read a hole */+		memset(buffer, 0, in->my_dev->data_bytes_per_chunk);+		return 0;+	}++}++void yaffs_chunk_del(struct yaffs_dev *dev, int chunk_id, int mark_flash,+		     int lyn)+{+	int block;+	int page;+	struct yaffs_ext_tags tags;+	struct yaffs_block_info *bi;++	if (chunk_id <= 0)+		return;++	dev->n_deletions++;+	block = chunk_id / dev->param.chunks_per_block;+	page = chunk_id % dev->param.chunks_per_block;++	if (!yaffs_check_chunk_bit(dev, block, page))+		yaffs_trace(YAFFS_TRACE_VERIFY,+			"Deleting invalid chunk %d", chunk_id);++	bi = yaffs_get_block_info(dev, block);++	yaffs2_update_oldest_dirty_seq(dev, block, bi);++	yaffs_trace(YAFFS_TRACE_DELETION,+		"line %d delete of chunk %d",+		lyn, chunk_id);++	if (!dev->param.is_yaffs2 && mark_flash &&+	    bi->block_state != YAFFS_BLOCK_STATE_COLLECTING) {++		memset(&tags, 0, sizeof(tags));+		tags.is_deleted = 1;+		yaffs_wr_chunk_tags_nand(dev, chunk_id, NULL, &tags);+		yaffs_handle_chunk_update(dev, chunk_id, &tags);+	} else {+		dev->n_unmarked_deletions++;+	}++	/* Pull out of the management area.+	 * If the whole block became dirty, this will kick off an erasure.+	 */+	if (bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING ||+	    bi->block_state == YAFFS_BLOCK_STATE_FULL ||+	    bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCAN ||+	    bi->block_state == YAFFS_BLOCK_STATE_COLLECTING) {+		dev->n_free_chunks++;+		yaffs_clear_chunk_bit(dev, block, page);+		bi->pages_in_use--;++		if (bi->pages_in_use == 0 &&+		    !bi->has_shrink_hdr &&+		    bi->block_state != YAFFS_BLOCK_STATE_ALLOCATING &&+		    bi->block_state != YAFFS_BLOCK_STATE_NEEDS_SCAN) {+			yaffs_block_became_dirty(dev, block);+		}+	}+}++static int yaffs_wr_data_obj(struct yaffs_obj *in, int inode_chunk,+			     const u8 *buffer, int n_bytes, int use_reserve)+{+	/* Find old chunk Need to do this to get serial number+	 * Write new one and patch into tree.+	 * Invalidate old tags.+	 */++	int prev_chunk_id;+	struct yaffs_ext_tags prev_tags;+	int new_chunk_id;+	struct yaffs_ext_tags new_tags;+	struct yaffs_dev *dev = in->my_dev;++	yaffs_check_gc(dev, 0);++	/* Get the previous chunk at this location in the file if it exists.+	 * If it does not exist then put a zero into the tree. This creates+	 * the tnode now, rather than later when it is harder to clean up.+	 */+	prev_chunk_id = yaffs_find_chunk_in_file(in, inode_chunk, &prev_tags);+	if (prev_chunk_id < 1 &&+	    !yaffs_put_chunk_in_file(in, inode_chunk, 0, 0))+		return 0;++	/* Set up new tags */+	memset(&new_tags, 0, sizeof(new_tags));++	new_tags.chunk_id = inode_chunk;+	new_tags.obj_id = in->obj_id;+	new_tags.serial_number =+	    (prev_chunk_id > 0) ? prev_tags.serial_number + 1 : 1;+	new_tags.n_bytes = n_bytes;++	if (n_bytes < 1 || n_bytes > dev->param.total_bytes_per_chunk) {+		yaffs_trace(YAFFS_TRACE_ERROR,+		  "Writing %d bytes to chunk!!!!!!!!!",+		   n_bytes);+		BUG();+	}++	new_chunk_id =+	    yaffs_write_new_chunk(dev, buffer, &new_tags, use_reserve);++	if (new_chunk_id > 0) {+		yaffs_put_chunk_in_file(in, inode_chunk, new_chunk_id, 0);++		if (prev_chunk_id > 0)+			yaffs_chunk_del(dev, prev_chunk_id, 1, __LINE__);++		yaffs_verify_file_sane(in);+	}+	return new_chunk_id;++}++++static int yaffs_do_xattrib_mod(struct yaffs_obj *obj, int set,+				const YCHAR *name, const void *value, int size,+				int flags)+{+	struct yaffs_xattr_mod xmod;+	int result;++	xmod.set = set;+	xmod.name = name;+	xmod.data = value;+	xmod.size = size;+	xmod.flags = flags;+	xmod.result = -ENOSPC;++	result = yaffs_update_oh(obj, NULL, 0, 0, 0, &xmod);++	if (result > 0)+		return xmod.result;+	else+		return -ENOSPC;+}++static int yaffs_apply_xattrib_mod(struct yaffs_obj *obj, char *buffer,+				   struct yaffs_xattr_mod *xmod)+{+	int retval = 0;+	int x_offs = sizeof(struct yaffs_obj_hdr);+	struct yaffs_dev *dev = obj->my_dev;+	int x_size = dev->data_bytes_per_chunk - sizeof(struct yaffs_obj_hdr);+	char *x_buffer = buffer + x_offs;++	if (xmod->set)+		retval =+		    nval_set(x_buffer, x_size, xmod->name, xmod->data,+			     xmod->size, xmod->flags);+	else+		retval = nval_del(x_buffer, x_size, xmod->name);++	obj->has_xattr = nval_hasvalues(x_buffer, x_size);+	obj->xattr_known = 1;+	xmod->result = retval;++	return retval;+}++static int yaffs_do_xattrib_fetch(struct yaffs_obj *obj, const YCHAR *name,+				  void *value, int size)+{+	char *buffer = NULL;+	int result;+	struct yaffs_ext_tags tags;+	struct yaffs_dev *dev = obj->my_dev;+	int x_offs = sizeof(struct yaffs_obj_hdr);+	int x_size = dev->data_bytes_per_chunk - sizeof(struct yaffs_obj_hdr);+	char *x_buffer;+	int retval = 0;++	if (obj->hdr_chunk < 1)+		return -ENODATA;++	/* If we know that the object has no xattribs then don't do all the+	 * reading and parsing.+	 */+	if (obj->xattr_known && !obj->has_xattr) {+		if (name)+			return -ENODATA;+		else+			return 0;+	}++	buffer = (char *)yaffs_get_temp_buffer(dev);+	if (!buffer)+		return -ENOMEM;++	result =+	    yaffs_rd_chunk_tags_nand(dev, obj->hdr_chunk, (u8 *) buffer, &tags);++	if (result != YAFFS_OK)+		retval = -ENOENT;+	else {+		x_buffer = buffer + x_offs;++		if (!obj->xattr_known) {+			obj->has_xattr = nval_hasvalues(x_buffer, x_size);+			obj->xattr_known = 1;+		}++		if (name)+			retval = nval_get(x_buffer, x_size, name, value, size);+		else+			retval = nval_list(x_buffer, x_size, value, size);+	}+	yaffs_release_temp_buffer(dev, (u8 *) buffer);+	return retval;+}++int yaffs_set_xattrib(struct yaffs_obj *obj, const YCHAR * name,+		      const void *value, int size, int flags)+{+	return yaffs_do_xattrib_mod(obj, 1, name, value, size, flags);+}++int yaffs_remove_xattrib(struct yaffs_obj *obj, const YCHAR * name)+{+	return yaffs_do_xattrib_mod(obj, 0, name, NULL, 0, 0);+}++int yaffs_get_xattrib(struct yaffs_obj *obj, const YCHAR * name, void *value,+		      int size)+{+	return yaffs_do_xattrib_fetch(obj, name, value, size);+}++int yaffs_list_xattrib(struct yaffs_obj *obj, char *buffer, int size)+{+	return yaffs_do_xattrib_fetch(obj, NULL, buffer, size);+}++static void yaffs_check_obj_details_loaded(struct yaffs_obj *in)+{+	u8 *buf;+	struct yaffs_obj_hdr *oh;+	struct yaffs_dev *dev;+	struct yaffs_ext_tags tags;+	int result;+	int alloc_failed = 0;++	if (!in || !in->lazy_loaded || in->hdr_chunk < 1)+		return;++	dev = in->my_dev;+	in->lazy_loaded = 0;+	buf = yaffs_get_temp_buffer(dev);++	result = yaffs_rd_chunk_tags_nand(dev, in->hdr_chunk, buf, &tags);+	oh = (struct yaffs_obj_hdr *)buf;++	in->yst_mode = oh->yst_mode;+	yaffs_load_attribs(in, oh);+	yaffs_set_obj_name_from_oh(in, oh);++	if (in->variant_type == YAFFS_OBJECT_TYPE_SYMLINK) {+		in->variant.symlink_variant.alias =+		    yaffs_clone_str(oh->alias);+		if (!in->variant.symlink_variant.alias)+			alloc_failed = 1;	/* Not returned */+	}+	yaffs_release_temp_buffer(dev, buf);+}++static void yaffs_load_name_from_oh(struct yaffs_dev *dev, YCHAR *name,+				    const YCHAR *oh_name, int buff_size)+{+#ifdef CONFIG_YAFFS_AUTO_UNICODE+	if (dev->param.auto_unicode) {+		if (*oh_name) {+			/* It is an ASCII name, do an ASCII to+			 * unicode conversion */+			const char *ascii_oh_name = (const char *)oh_name;+			int n = buff_size - 1;+			while (n > 0 && *ascii_oh_name) {+				*name = *ascii_oh_name;+				name++;+				ascii_oh_name++;+				n--;+			}+		} else {+			strncpy(name, oh_name + 1, buff_size - 1);+		}+	} else {+#else+	(void) dev;+	{+#endif+		strncpy(name, oh_name, buff_size - 1);+	}+}++static void yaffs_load_oh_from_name(struct yaffs_dev *dev, YCHAR *oh_name,+				    const YCHAR *name)+{+#ifdef CONFIG_YAFFS_AUTO_UNICODE++	int is_ascii;+	YCHAR *w;++	if (dev->param.auto_unicode) {++		is_ascii = 1;+		w = name;++		/* Figure out if the name will fit in ascii character set */+		while (is_ascii && *w) {+			if ((*w) & 0xff00)+				is_ascii = 0;+			w++;+		}++		if (is_ascii) {+			/* It is an ASCII name, so convert unicode to ascii */+			char *ascii_oh_name = (char *)oh_name;+			int n = YAFFS_MAX_NAME_LENGTH - 1;+			while (n > 0 && *name) {+				*ascii_oh_name = *name;+				name++;+				ascii_oh_name++;+				n--;+			}+		} else {+			/* Unicode name, so save starting at the second YCHAR */+			*oh_name = 0;+			strncpy(oh_name + 1, name, YAFFS_MAX_NAME_LENGTH - 2);+		}+	} else {+#else+	dev = dev;+	{+#endif+		strncpy(oh_name, name, YAFFS_MAX_NAME_LENGTH - 1);+	}+}++/* UpdateObjectHeader updates the header on NAND for an object.+ * If name is not NULL, then that new name is used.+ */+int yaffs_update_oh(struct yaffs_obj *in, const YCHAR *name, int force,+		    int is_shrink, int shadows, struct yaffs_xattr_mod *xmod)+{++	struct yaffs_block_info *bi;+	struct yaffs_dev *dev = in->my_dev;+	int prev_chunk_id;+	int ret_val = 0;+	int result = 0;+	int new_chunk_id;+	struct yaffs_ext_tags new_tags;+	struct yaffs_ext_tags old_tags;+	const YCHAR *alias = NULL;+	u8 *buffer = NULL;+	YCHAR old_name[YAFFS_MAX_NAME_LENGTH + 1];+	struct yaffs_obj_hdr *oh = NULL;+	loff_t file_size = 0;++	strcpy(old_name, _Y("silly old name"));++	if (in->fake && in != dev->root_dir && !force && !xmod)+		return ret_val;++	yaffs_check_gc(dev, 0);+	yaffs_check_obj_details_loaded(in);++	buffer = yaffs_get_temp_buffer(in->my_dev);+	oh = (struct yaffs_obj_hdr *)buffer;++	prev_chunk_id = in->hdr_chunk;++	if (prev_chunk_id > 0) {+		result = yaffs_rd_chunk_tags_nand(dev, prev_chunk_id,+						  buffer, &old_tags);++		yaffs_verify_oh(in, oh, &old_tags, 0);+		memcpy(old_name, oh->name, sizeof(oh->name));+		memset(buffer, 0xff, sizeof(struct yaffs_obj_hdr));+	} else {+		memset(buffer, 0xff, dev->data_bytes_per_chunk);+	}++	oh->type = in->variant_type;+	oh->yst_mode = in->yst_mode;+	oh->shadows_obj = oh->inband_shadowed_obj_id = shadows;++	yaffs_load_attribs_oh(oh, in);++	if (in->parent)+		oh->parent_obj_id = in->parent->obj_id;+	else+		oh->parent_obj_id = 0;++	if (name && *name) {+		memset(oh->name, 0, sizeof(oh->name));+		yaffs_load_oh_from_name(dev, oh->name, name);+	} else if (prev_chunk_id > 0) {+		memcpy(oh->name, old_name, sizeof(oh->name));+	} else {+		memset(oh->name, 0, sizeof(oh->name));+	}++	oh->is_shrink = is_shrink;++	switch (in->variant_type) {+	case YAFFS_OBJECT_TYPE_UNKNOWN:+		/* Should not happen */+		break;+	case YAFFS_OBJECT_TYPE_FILE:+		if (oh->parent_obj_id != YAFFS_OBJECTID_DELETED &&+		    oh->parent_obj_id != YAFFS_OBJECTID_UNLINKED)+			file_size = in->variant.file_variant.file_size;+		yaffs_oh_size_load(oh, file_size);+		break;+	case YAFFS_OBJECT_TYPE_HARDLINK:+		oh->equiv_id = in->variant.hardlink_variant.equiv_id;+		break;+	case YAFFS_OBJECT_TYPE_SPECIAL:+		/* Do nothing */+		break;+	case YAFFS_OBJECT_TYPE_DIRECTORY:+		/* Do nothing */+		break;+	case YAFFS_OBJECT_TYPE_SYMLINK:+		alias = in->variant.symlink_variant.alias;+		if (!alias)+			alias = _Y("no alias");+		strncpy(oh->alias, alias, YAFFS_MAX_ALIAS_LENGTH);+		oh->alias[YAFFS_MAX_ALIAS_LENGTH] = 0;+		break;+	}++	/* process any xattrib modifications */+	if (xmod)+		yaffs_apply_xattrib_mod(in, (char *)buffer, xmod);++	/* Tags */+	memset(&new_tags, 0, sizeof(new_tags));+	in->serial++;+	new_tags.chunk_id = 0;+	new_tags.obj_id = in->obj_id;+	new_tags.serial_number = in->serial;++	/* Add extra info for file header */+	new_tags.extra_available = 1;+	new_tags.extra_parent_id = oh->parent_obj_id;+	new_tags.extra_file_size = file_size;+	new_tags.extra_is_shrink = oh->is_shrink;+	new_tags.extra_equiv_id = oh->equiv_id;+	new_tags.extra_shadows = (oh->shadows_obj > 0) ? 1 : 0;+	new_tags.extra_obj_type = in->variant_type;+	yaffs_verify_oh(in, oh, &new_tags, 1);++	/* Create new chunk in NAND */+	new_chunk_id =+	    yaffs_write_new_chunk(dev, buffer, &new_tags,+				  (prev_chunk_id > 0) ? 1 : 0);++	if (buffer)+		yaffs_release_temp_buffer(dev, buffer);++	if (new_chunk_id < 0)+		return new_chunk_id;++	in->hdr_chunk = new_chunk_id;++	if (prev_chunk_id > 0)+		yaffs_chunk_del(dev, prev_chunk_id, 1, __LINE__);++	if (!yaffs_obj_cache_dirty(in))+		in->dirty = 0;++	/* If this was a shrink, then mark the block+	 * that the chunk lives on */+	if (is_shrink) {+		bi = yaffs_get_block_info(in->my_dev,+					  new_chunk_id /+					  in->my_dev->param.chunks_per_block);+		bi->has_shrink_hdr = 1;+	}+++	return new_chunk_id;+}++/*--------------------- 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_file_rd(struct yaffs_obj *in, u8 * buffer, loff_t offset, int n_bytes)+{+	int chunk;+	u32 start;+	int n_copy;+	int n = n_bytes;+	int n_done = 0;+	struct yaffs_cache *cache;+	struct yaffs_dev *dev;++	dev = in->my_dev;++	while (n > 0) {+		yaffs_addr_to_chunk(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->data_bytes_per_chunk)+			n_copy = n;+		else+			n_copy = dev->data_bytes_per_chunk - start;++		cache = yaffs_find_chunk_cache(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 || n_copy != dev->data_bytes_per_chunk ||+		    dev->param.inband_tags) {+			if (dev->param.n_caches > 0) {++				/* If we can't find the data in the cache,+				 * then load it up. */++				if (!cache) {+					cache =+					    yaffs_grab_chunk_cache(in->my_dev);+					cache->object = in;+					cache->chunk_id = chunk;+					cache->dirty = 0;+					cache->locked = 0;+					yaffs_rd_data_obj(in, chunk,+							  cache->data);+					cache->n_bytes = 0;+				}++				yaffs_use_cache(dev, cache, 0);++				cache->locked = 1;++				memcpy(buffer, &cache->data[start], n_copy);++				cache->locked = 0;+			} else {+				/* Read into the local buffer then copy.. */++				u8 *local_buffer =+				    yaffs_get_temp_buffer(dev);+				yaffs_rd_data_obj(in, chunk, local_buffer);++				memcpy(buffer, &local_buffer[start], n_copy);++				yaffs_release_temp_buffer(dev, local_buffer);+			}+		} else {+			/* A full chunk. Read directly into the buffer. */+			yaffs_rd_data_obj(in, chunk, buffer);+		}+		n -= n_copy;+		offset += n_copy;+		buffer += n_copy;+		n_done += n_copy;+	}+	return n_done;+}++int yaffs_do_file_wr(struct yaffs_obj *in, const u8 *buffer, loff_t offset,+		     int n_bytes, int write_through)+{++	int chunk;+	u32 start;+	int n_copy;+	int n = n_bytes;+	int n_done = 0;+	int n_writeback;+	loff_t start_write = offset;+	int chunk_written = 0;+	u32 n_bytes_read;+	loff_t chunk_start;+	struct yaffs_dev *dev;++	dev = in->my_dev;++	while (n > 0 && chunk_written >= 0) {+		yaffs_addr_to_chunk(dev, offset, &chunk, &start);++		if (((loff_t)chunk) *+		    dev->data_bytes_per_chunk + start != offset ||+		    start >= dev->data_bytes_per_chunk) {+			yaffs_trace(YAFFS_TRACE_ERROR,+				"AddrToChunk of offset %lld gives chunk %d start %d",+				offset, chunk, start);+		}+		chunk++;	/* File pos to chunk in file offset */++		/* OK now check for the curveball where the start and end are in+		 * the same chunk.+		 */++		if ((start + n) < dev->data_bytes_per_chunk) {+			n_copy = n;++			/* Now 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.+			 */++			chunk_start = (((loff_t)(chunk - 1)) *+					dev->data_bytes_per_chunk);++			if (chunk_start > in->variant.file_variant.file_size)+				n_bytes_read = 0;	/* Past end of file */+			else+				n_bytes_read =+				    in->variant.file_variant.file_size -+				    chunk_start;++			if (n_bytes_read > dev->data_bytes_per_chunk)+				n_bytes_read = dev->data_bytes_per_chunk;++			n_writeback =+			    (n_bytes_read >+			     (start + n)) ? n_bytes_read : (start + n);++			if (n_writeback < 0 ||+			    n_writeback > dev->data_bytes_per_chunk)+				BUG();++		} else {+			n_copy = dev->data_bytes_per_chunk - start;+			n_writeback = dev->data_bytes_per_chunk;+		}++		if (n_copy != dev->data_bytes_per_chunk ||+		    !dev->param.cache_bypass_aligned ||+		    dev->param.inband_tags) {+			/* An incomplete start or end chunk (or maybe both+			 * start and end chunk), or we're using inband tags,+			 * or we're forcing writes through the cache,+			 * so we want to use the cache buffers.+			 */+			if (dev->param.n_caches > 0) {+				struct yaffs_cache *cache;++				/* If we can't find the data in the cache, then+				 * load the cache */+				cache = yaffs_find_chunk_cache(in, chunk);++				if (!cache &&+				    yaffs_check_alloc_available(dev, 1)) {+					cache = yaffs_grab_chunk_cache(dev);+					cache->object = in;+					cache->chunk_id = chunk;+					cache->dirty = 0;+					cache->locked = 0;+					yaffs_rd_data_obj(in, chunk,+							  cache->data);+				} else if (cache &&+					   !cache->dirty &&+					   !yaffs_check_alloc_available(dev,+									1)) {+					/* Drop the cache if it was a read cache+					 * item and no space check has been made+					 * for it.+					 */+					cache = NULL;+				}++				if (cache) {+					yaffs_use_cache(dev, cache, 1);+					cache->locked = 1;++					memcpy(&cache->data[start], buffer,+					       n_copy);++					cache->locked = 0;+					cache->n_bytes = n_writeback;++					if (write_through) {+						chunk_written =+						    yaffs_wr_data_obj+						    (cache->object,+						     cache->chunk_id,+						     cache->data,+						     cache->n_bytes, 1);+						cache->dirty = 0;+					}+				} else {+					chunk_written = -1;	/* fail write */+				}+			} else {+				/* An incomplete start or end chunk (or maybe+				 * both start and end chunk). Read into the+				 * local buffer then copy over and write back.+				 */++				u8 *local_buffer = yaffs_get_temp_buffer(dev);++				yaffs_rd_data_obj(in, chunk, local_buffer);+				memcpy(&local_buffer[start], buffer, n_copy);++				chunk_written =+				    yaffs_wr_data_obj(in, chunk,+						      local_buffer,+						      n_writeback, 0);++				yaffs_release_temp_buffer(dev, local_buffer);+			}+		} else {+			/* A full chunk. Write directly from the buffer. */++			chunk_written =+			    yaffs_wr_data_obj(in, chunk, buffer,+					      dev->data_bytes_per_chunk, 0);++			/* Since we've overwritten the cached data,+			 * we better invalidate it. */+			yaffs_invalidate_chunk_cache(in, chunk);+		}++		if (chunk_written >= 0) {+			n -= n_copy;+			offset += n_copy;+			buffer += n_copy;+			n_done += n_copy;+		}+	}++	/* Update file object */++	if ((start_write + n_done) > in->variant.file_variant.file_size)+		in->variant.file_variant.file_size = (start_write + n_done);++	in->dirty = 1;+	return n_done;+}++int yaffs_wr_file(struct yaffs_obj *in, const u8 *buffer, loff_t offset,+		  int n_bytes, int write_through)+{+	yaffs2_handle_hole(in, offset);+	return yaffs_do_file_wr(in, buffer, offset, n_bytes, write_through);+}++/* ---------------------- File resizing stuff ------------------ */++static void yaffs_prune_chunks(struct yaffs_obj *in, loff_t new_size)+{++	struct yaffs_dev *dev = in->my_dev;+	loff_t old_size = in->variant.file_variant.file_size;+	int i;+	int chunk_id;+	u32 dummy;+	int last_del;+	int start_del;++	if (old_size > 0)+		yaffs_addr_to_chunk(dev, old_size - 1, &last_del, &dummy);+	else+		last_del = 0;++	yaffs_addr_to_chunk(dev, new_size + dev->data_bytes_per_chunk - 1,+				&start_del, &dummy);+	last_del++;+	start_del++;++	/* Delete backwards so that we don't end up with holes if+	 * power is lost part-way through the operation.+	 */+	for (i = last_del; i >= start_del; i--) {+		/* NB this could be optimised somewhat,+		 * eg. could retrieve the tags and write them without+		 * using yaffs_chunk_del+		 */++		chunk_id = yaffs_find_del_file_chunk(in, i, NULL);++		if (chunk_id < 1)+			continue;++		if (chunk_id <+		    (dev->internal_start_block * dev->param.chunks_per_block) ||+		    chunk_id >=+		    ((dev->internal_end_block + 1) *+		      dev->param.chunks_per_block)) {+			yaffs_trace(YAFFS_TRACE_ALWAYS,+				"Found daft chunk_id %d for %d",+				chunk_id, i);+		} else {+			in->n_data_chunks--;+			yaffs_chunk_del(dev, chunk_id, 1, __LINE__);+		}+	}+}++void yaffs_resize_file_down(struct yaffs_obj *obj, loff_t new_size)+{+	int new_full;+	u32 new_partial;+	struct yaffs_dev *dev = obj->my_dev;++	yaffs_addr_to_chunk(dev, new_size, &new_full, &new_partial);++	yaffs_prune_chunks(obj, new_size);++	if (new_partial != 0) {+		int last_chunk = 1 + new_full;+		u8 *local_buffer = yaffs_get_temp_buffer(dev);++		/* Rewrite the last chunk with its new size and zero pad */+		yaffs_rd_data_obj(obj, last_chunk, local_buffer);+		memset(local_buffer + new_partial, 0,+		       dev->data_bytes_per_chunk - new_partial);++		yaffs_wr_data_obj(obj, last_chunk, local_buffer,+				  new_partial, 1);++		yaffs_release_temp_buffer(dev, local_buffer);+	}++	obj->variant.file_variant.file_size = new_size;++	yaffs_prune_tree(dev, &obj->variant.file_variant);+}++int yaffs_resize_file(struct yaffs_obj *in, loff_t new_size)+{+	struct yaffs_dev *dev = in->my_dev;+	loff_t old_size = in->variant.file_variant.file_size;++	yaffs_flush_file_cache(in);+	yaffs_invalidate_whole_cache(in);++	yaffs_check_gc(dev, 0);++	if (in->variant_type != YAFFS_OBJECT_TYPE_FILE)+		return YAFFS_FAIL;++	if (new_size == old_size)+		return YAFFS_OK;++	if (new_size > old_size) {+		yaffs2_handle_hole(in, new_size);+		in->variant.file_variant.file_size = new_size;+	} else {+		/* new_size < old_size */+		yaffs_resize_file_down(in, new_size);+	}++	/* Write a new object header to reflect the resize.+	 * show we've shrunk the file, if need be+	 * Do this only if the file is not in the deleted directories+	 * and is not shadowed.+	 */+	if (in->parent &&+	    !in->is_shadowed &&+	    in->parent->obj_id != YAFFS_OBJECTID_UNLINKED &&+	    in->parent->obj_id != YAFFS_OBJECTID_DELETED)+		yaffs_update_oh(in, NULL, 0, 0, 0, NULL);++	return YAFFS_OK;+}++int yaffs_flush_file(struct yaffs_obj *in, int update_time, int data_sync)+{+	if (!in->dirty)+		return YAFFS_OK;++	yaffs_flush_file_cache(in);++	if (data_sync)+		return YAFFS_OK;++	if (update_time)+		yaffs_load_current_time(in, 0, 0);++	return (yaffs_update_oh(in, NULL, 0, 0, 0, NULL) >= 0) ?+				YAFFS_OK : YAFFS_FAIL;+}+++/* yaffs_del_file 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_unlink_file_if_needed(struct yaffs_obj *in)+{+	int ret_val;+	int del_now = 0;+	struct yaffs_dev *dev = in->my_dev;++	if (!in->my_inode)+		del_now = 1;++	if (del_now) {+		ret_val =+		    yaffs_change_obj_name(in, in->my_dev->del_dir,+					  _Y("deleted"), 0, 0);+		yaffs_trace(YAFFS_TRACE_TRACING,+			"yaffs: immediate deletion of file %d",+			in->obj_id);+		in->deleted = 1;+		in->my_dev->n_deleted_files++;+		if (dev->param.disable_soft_del || dev->param.is_yaffs2)+			yaffs_resize_file(in, 0);+		yaffs_soft_del_file(in);+	} else {+		ret_val =+		    yaffs_change_obj_name(in, in->my_dev->unlinked_dir,+					  _Y("unlinked"), 0, 0);+	}+	return ret_val;+}++static int yaffs_del_file(struct yaffs_obj *in)+{+	int ret_val = YAFFS_OK;+	int deleted;	/* Need to cache value on stack if in is freed */+	struct yaffs_dev *dev = in->my_dev;++	if (dev->param.disable_soft_del || dev->param.is_yaffs2)+		yaffs_resize_file(in, 0);++	if (in->n_data_chunks > 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)+			ret_val = yaffs_unlink_file_if_needed(in);++		deleted = in->deleted;++		if (ret_val == YAFFS_OK && in->unlinked && !in->deleted) {+			in->deleted = 1;+			deleted = 1;+			in->my_dev->n_deleted_files++;+			yaffs_soft_del_file(in);+		}+		return deleted ? YAFFS_OK : YAFFS_FAIL;+	} else {+		/* The file has no data chunks so we toss it immediately */+		yaffs_free_tnode(in->my_dev, in->variant.file_variant.top);+		in->variant.file_variant.top = NULL;+		yaffs_generic_obj_del(in);++		return YAFFS_OK;+	}+}++int yaffs_is_non_empty_dir(struct yaffs_obj *obj)+{+	return (obj &&+		obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) &&+		!(list_empty(&obj->variant.dir_variant.children));+}++static int yaffs_del_dir(struct yaffs_obj *obj)+{+	/* First check that the directory is empty. */+	if (yaffs_is_non_empty_dir(obj))+		return YAFFS_FAIL;++	return yaffs_generic_obj_del(obj);+}++static int yaffs_del_symlink(struct yaffs_obj *in)+{+	kfree(in->variant.symlink_variant.alias);+	in->variant.symlink_variant.alias = NULL;++	return yaffs_generic_obj_del(in);+}++static int yaffs_del_link(struct yaffs_obj *in)+{+	/* remove this hardlink from the list associated with the equivalent+	 * object+	 */+	list_del_init(&in->hard_links);+	return yaffs_generic_obj_del(in);+}++int yaffs_del_obj(struct yaffs_obj *obj)+{+	int ret_val = -1;++	switch (obj->variant_type) {+	case YAFFS_OBJECT_TYPE_FILE:+		ret_val = yaffs_del_file(obj);+		break;+	case YAFFS_OBJECT_TYPE_DIRECTORY:+		if (!list_empty(&obj->variant.dir_variant.dirty)) {+			yaffs_trace(YAFFS_TRACE_BACKGROUND,+				"Remove object %d from dirty directories",+				obj->obj_id);+			list_del_init(&obj->variant.dir_variant.dirty);+		}+		return yaffs_del_dir(obj);+		break;+	case YAFFS_OBJECT_TYPE_SYMLINK:+		ret_val = yaffs_del_symlink(obj);+		break;+	case YAFFS_OBJECT_TYPE_HARDLINK:+		ret_val = yaffs_del_link(obj);+		break;+	case YAFFS_OBJECT_TYPE_SPECIAL:+		ret_val = yaffs_generic_obj_del(obj);+		break;+	case YAFFS_OBJECT_TYPE_UNKNOWN:+		ret_val = 0;+		break;		/* should not happen. */+	}+	return ret_val;+}+++static void yaffs_empty_dir_to_dir(struct yaffs_obj *from_dir,+				   struct yaffs_obj *to_dir)+{+	struct yaffs_obj *obj;+	struct list_head *lh;+	struct list_head *n;++	list_for_each_safe(lh, n, &from_dir->variant.dir_variant.children) {+		obj = list_entry(lh, struct yaffs_obj, siblings);+		yaffs_add_obj_to_dir(to_dir, obj);+	}+}++struct yaffs_obj *yaffs_retype_obj(struct yaffs_obj *obj,+				   enum yaffs_obj_type type)+{+	/* Tear down the old variant */+	switch (obj->variant_type) {+	case YAFFS_OBJECT_TYPE_FILE:+		/* Nuke file data */+		yaffs_resize_file(obj, 0);+		yaffs_free_tnode(obj->my_dev, obj->variant.file_variant.top);+		obj->variant.file_variant.top = NULL;+		break;+	case YAFFS_OBJECT_TYPE_DIRECTORY:+		/* Put the children in lost and found. */+		yaffs_empty_dir_to_dir(obj, obj->my_dev->lost_n_found);+		if (!list_empty(&obj->variant.dir_variant.dirty))+			list_del_init(&obj->variant.dir_variant.dirty);+		break;+	case YAFFS_OBJECT_TYPE_SYMLINK:+		/* Nuke symplink data */+		kfree(obj->variant.symlink_variant.alias);+		obj->variant.symlink_variant.alias = NULL;+		break;+	case YAFFS_OBJECT_TYPE_HARDLINK:+		list_del_init(&obj->hard_links);+		break;+	default:+		break;+	}++	memset(&obj->variant, 0, sizeof(obj->variant));++	/*Set up new variant if the memset is not enough. */+	switch (type) {+	case YAFFS_OBJECT_TYPE_DIRECTORY:+		INIT_LIST_HEAD(&obj->variant.dir_variant.children);+		INIT_LIST_HEAD(&obj->variant.dir_variant.dirty);+		break;+	case YAFFS_OBJECT_TYPE_FILE:+	case YAFFS_OBJECT_TYPE_SYMLINK:+	case YAFFS_OBJECT_TYPE_HARDLINK:+	default:+		break;+	}++	obj->variant_type = type;++	return obj;++}++static int yaffs_unlink_worker(struct yaffs_obj *obj)+{+	int del_now = 0;++	if (!obj)+		return YAFFS_FAIL;++	if (!obj->my_inode)+		del_now = 1;++	yaffs_update_parent(obj->parent);++	if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK) {+		return yaffs_del_link(obj);+	} else if (!list_empty(&obj->hard_links)) {+		/* 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+		 * - Move it from its parent directory so that the rename works.+		 * - Rename the object to the hardlink's name.+		 * - Delete the hardlink+		 */++		struct yaffs_obj *hl;+		struct yaffs_obj *parent;+		int ret_val;+		YCHAR name[YAFFS_MAX_NAME_LENGTH + 1];++		hl = list_entry(obj->hard_links.next, struct yaffs_obj,+				hard_links);++		yaffs_get_obj_name(hl, name, YAFFS_MAX_NAME_LENGTH + 1);+		parent = hl->parent;++		list_del_init(&hl->hard_links);++		yaffs_add_obj_to_dir(obj->my_dev->unlinked_dir, hl);++		ret_val = yaffs_change_obj_name(obj, parent, name, 0, 0);++		if (ret_val == YAFFS_OK)+			ret_val = yaffs_generic_obj_del(hl);++		return ret_val;++	} else if (del_now) {+		switch (obj->variant_type) {+		case YAFFS_OBJECT_TYPE_FILE:+			return yaffs_del_file(obj);+			break;+		case YAFFS_OBJECT_TYPE_DIRECTORY:+			list_del_init(&obj->variant.dir_variant.dirty);+			return yaffs_del_dir(obj);+			break;+		case YAFFS_OBJECT_TYPE_SYMLINK:+			return yaffs_del_symlink(obj);+			break;+		case YAFFS_OBJECT_TYPE_SPECIAL:+			return yaffs_generic_obj_del(obj);+			break;+		case YAFFS_OBJECT_TYPE_HARDLINK:+		case YAFFS_OBJECT_TYPE_UNKNOWN:+		default:+			return YAFFS_FAIL;+		}+	} else if (yaffs_is_non_empty_dir(obj)) {+		return YAFFS_FAIL;+	} else {+		return yaffs_change_obj_name(obj, obj->my_dev->unlinked_dir,+						_Y("unlinked"), 0, 0);+	}+}++static int yaffs_unlink_obj(struct yaffs_obj *obj)+{+	if (obj && obj->unlink_allowed)+		return yaffs_unlink_worker(obj);++	return YAFFS_FAIL;+}++int yaffs_unlinker(struct yaffs_obj *dir, const YCHAR *name)+{+	struct yaffs_obj *obj;++	obj = yaffs_find_by_name(dir, name);+	return yaffs_unlink_obj(obj);+}++/* Note:+ * If old_name is NULL then we take old_dir as the object to be renamed.+ */+int yaffs_rename_obj(struct yaffs_obj *old_dir, const YCHAR *old_name,+		     struct yaffs_obj *new_dir, const YCHAR *new_name)+{+	struct yaffs_obj *obj = NULL;+	struct yaffs_obj *existing_target = NULL;+	int force = 0;+	int result;+	struct yaffs_dev *dev;++	if (!old_dir || old_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {+		BUG();+		return YAFFS_FAIL;+	}+	if (!new_dir || new_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {+		BUG();+		return YAFFS_FAIL;+	}++	dev = old_dir->my_dev;++#ifdef CONFIG_YAFFS_CASE_INSENSITIVE+	/* Special case for case insemsitive systems.+	 * While look-up is case insensitive, the name isn't.+	 * Therefore we might want to change x.txt to X.txt+	 */+	if (old_dir == new_dir &&+		old_name && new_name &&+		strcmp(old_name, new_name) == 0)+		force = 1;+#endif++	if (strnlen(new_name, YAFFS_MAX_NAME_LENGTH + 1) >+	    YAFFS_MAX_NAME_LENGTH)+		/* ENAMETOOLONG */+		return YAFFS_FAIL;++	if (old_name)+		obj = yaffs_find_by_name(old_dir, old_name);+	else{+		obj = old_dir;+		old_dir = obj->parent;+	}++	if (obj && obj->rename_allowed) {+		/* Now handle an existing target, if there is one */+		existing_target = yaffs_find_by_name(new_dir, new_name);+		if (yaffs_is_non_empty_dir(existing_target)) {+			return YAFFS_FAIL;	/* ENOTEMPTY */+		} else if (existing_target && existing_target != obj) {+			/* Nuke the target first, using shadowing,+			 * but only if it isn't the same object.+			 *+			 * Note we must disable gc here otherwise it can mess+			 * up the shadowing.+			 *+			 */+			dev->gc_disable = 1;+			yaffs_change_obj_name(obj, new_dir, new_name, force,+					      existing_target->obj_id);+			existing_target->is_shadowed = 1;+			yaffs_unlink_obj(existing_target);+			dev->gc_disable = 0;+		}++		result = yaffs_change_obj_name(obj, new_dir, new_name, 1, 0);++		yaffs_update_parent(old_dir);+		if (new_dir != old_dir)+			yaffs_update_parent(new_dir);++		return result;+	}+	return YAFFS_FAIL;+}++/*----------------------- Initialisation Scanning ---------------------- */++void yaffs_handle_shadowed_obj(struct yaffs_dev *dev, int obj_id,+			       int backward_scanning)+{+	struct yaffs_obj *obj;++	if (backward_scanning) {+		/* Handle YAFFS2 case (backward scanning)+		 * If the shadowed object exists then ignore.+		 */+		obj = yaffs_find_by_number(dev, obj_id);+		if (obj)+			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_find_or_create_by_number(dev, obj_id, YAFFS_OBJECT_TYPE_FILE);+	if (!obj)+		return;+	obj->is_shadowed = 1;+	yaffs_add_obj_to_dir(dev->unlinked_dir, obj);+	obj->variant.file_variant.shrink_size = 0;+	obj->valid = 1;		/* So that we don't read any other info. */+}++void yaffs_link_fixup(struct yaffs_dev *dev, struct list_head *hard_list)+{+	struct list_head *lh;+	struct list_head *save;+	struct yaffs_obj *hl;+	struct yaffs_obj *in;++	list_for_each_safe(lh, save, hard_list) {+		hl = list_entry(lh, struct yaffs_obj, hard_links);+		in = yaffs_find_by_number(dev,+					hl->variant.hardlink_variant.equiv_id);++		if (in) {+			/* Add the hardlink pointers */+			hl->variant.hardlink_variant.equiv_obj = in;+			list_add(&hl->hard_links, &in->hard_links);+		} else {+			/* Todo Need to report/handle this better.+			 * Got a problem... hardlink to a non-existant object+			 */+			hl->variant.hardlink_variant.equiv_obj = NULL;+			INIT_LIST_HEAD(&hl->hard_links);+		}+	}+}++static void yaffs_strip_deleted_objs(struct yaffs_dev *dev)+{+	/*+	 *  Sort out state of unlinked and deleted objects after scanning.+	 */+	struct list_head *i;+	struct list_head *n;+	struct yaffs_obj *l;++	if (dev->read_only)+		return;++	/* Soft delete all the unlinked files */+	list_for_each_safe(i, n,+			   &dev->unlinked_dir->variant.dir_variant.children) {+		l = list_entry(i, struct yaffs_obj, siblings);+		yaffs_del_obj(l);+	}++	list_for_each_safe(i, n, &dev->del_dir->variant.dir_variant.children) {+		l = list_entry(i, struct yaffs_obj, siblings);+		yaffs_del_obj(l);+	}+}++/*+ * This code iterates through all the objects making sure that they are rooted.+ * Any unrooted objects are re-rooted in lost+found.+ * An object needs to be in one of:+ * - Directly under deleted, unlinked+ * - Directly or indirectly under root.+ *+ * Note:+ *  This code assumes that we don't ever change the current relationships+ *  between directories:+ *   root_dir->parent == unlinked_dir->parent == del_dir->parent == NULL+ *   lost-n-found->parent == root_dir+ *+ * This fixes the problem where directories might have inadvertently been+ * deleted leaving the object "hanging" without being rooted in the+ * directory tree.+ */++static int yaffs_has_null_parent(struct yaffs_dev *dev, struct yaffs_obj *obj)+{+	return (obj == dev->del_dir ||+		obj == dev->unlinked_dir || obj == dev->root_dir);+}++static void yaffs_fix_hanging_objs(struct yaffs_dev *dev)+{+	struct yaffs_obj *obj;+	struct yaffs_obj *parent;+	int i;+	struct list_head *lh;+	struct list_head *n;+	int depth_limit;+	int hanging;++	if (dev->read_only)+		return;++	/* Iterate through the objects in each hash entry,+	 * looking at each object.+	 * Make sure it is rooted.+	 */++	for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {+		list_for_each_safe(lh, n, &dev->obj_bucket[i].list) {+			obj = list_entry(lh, struct yaffs_obj, hash_link);+			parent = obj->parent;++			if (yaffs_has_null_parent(dev, obj)) {+				/* These directories are not hanging */+				hanging = 0;+			} else if (!parent ||+				   parent->variant_type !=+				   YAFFS_OBJECT_TYPE_DIRECTORY) {+				hanging = 1;+			} else if (yaffs_has_null_parent(dev, parent)) {+				hanging = 0;+			} else {+				/*+				 * Need to follow the parent chain to+				 * see if it is hanging.+				 */+				hanging = 0;+				depth_limit = 100;++				while (parent != dev->root_dir &&+				       parent->parent &&+				       parent->parent->variant_type ==+				       YAFFS_OBJECT_TYPE_DIRECTORY &&+				       depth_limit > 0) {+					parent = parent->parent;+					depth_limit--;+				}+				if (parent != dev->root_dir)+					hanging = 1;+			}+			if (hanging) {+				yaffs_trace(YAFFS_TRACE_SCAN,+					"Hanging object %d moved to lost and found",+					obj->obj_id);+				yaffs_add_obj_to_dir(dev->lost_n_found, obj);+			}+		}+	}+}++/*+ * Delete directory contents for cleaning up lost and found.+ */+static void yaffs_del_dir_contents(struct yaffs_obj *dir)+{+	struct yaffs_obj *obj;+	struct list_head *lh;+	struct list_head *n;++	if (dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)+		BUG();++	list_for_each_safe(lh, n, &dir->variant.dir_variant.children) {+		obj = list_entry(lh, struct yaffs_obj, siblings);+		if (obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY)+			yaffs_del_dir_contents(obj);+		yaffs_trace(YAFFS_TRACE_SCAN,+			"Deleting lost_found object %d",+			obj->obj_id);+		yaffs_unlink_obj(obj);+	}+}++static void yaffs_empty_l_n_f(struct yaffs_dev *dev)+{+	yaffs_del_dir_contents(dev->lost_n_found);+}+++struct yaffs_obj *yaffs_find_by_name(struct yaffs_obj *directory,+				     const YCHAR *name)+{+	int sum;+	struct list_head *i;+	YCHAR buffer[YAFFS_MAX_NAME_LENGTH + 1];+	struct yaffs_obj *l;++	if (!name)+		return NULL;++	if (!directory) {+		yaffs_trace(YAFFS_TRACE_ALWAYS,+			"tragedy: yaffs_find_by_name: null pointer directory"+			);+		BUG();+		return NULL;+	}+	if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {+		yaffs_trace(YAFFS_TRACE_ALWAYS,+			"tragedy: yaffs_find_by_name: non-directory"+			);+		BUG();+	}++	sum = yaffs_calc_name_sum(name);++	list_for_each(i, &directory->variant.dir_variant.children) {+		l = list_entry(i, struct yaffs_obj, siblings);++		if (l->parent != directory)+			BUG();++		yaffs_check_obj_details_loaded(l);++		/* Special case for lost-n-found */+		if (l->obj_id == YAFFS_OBJECTID_LOSTNFOUND) {+			if (!strcmp(name, YAFFS_LOSTNFOUND_NAME))+				return l;+		} else if (l->sum == sum || l->hdr_chunk <= 0) {+			/* LostnFound chunk called Objxxx+			 * Do a real check+			 */+			yaffs_get_obj_name(l, buffer,+				YAFFS_MAX_NAME_LENGTH + 1);+			if (!strncmp(name, buffer, YAFFS_MAX_NAME_LENGTH))+				return l;+		}+	}+	return NULL;+}++/* GetEquivalentObject dereferences any hard links to get to the+ * actual object.+ */++struct yaffs_obj *yaffs_get_equivalent_obj(struct yaffs_obj *obj)+{+	if (obj && obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK) {+		obj = obj->variant.hardlink_variant.equiv_obj;+		yaffs_check_obj_details_loaded(obj);+	}+	return obj;+}++/*+ *  A note or two on object names.+ *  * If the object name is missing, we then make one up in the form objnnn+ *+ *  * ASCII names are stored in the object header's name field from byte zero+ *  * Unicode names are historically stored starting from byte zero.+ *+ * Then there are automatic Unicode names...+ * The purpose of these is to save names in a way that can be read as+ * ASCII or Unicode names as appropriate, thus allowing a Unicode and ASCII+ * system to share files.+ *+ * These automatic unicode are stored slightly differently...+ *  - If the name can fit in the ASCII character space then they are saved as+ *    ascii names as per above.+ *  - If the name needs Unicode then the name is saved in Unicode+ *    starting at oh->name[1].++ */+static void yaffs_fix_null_name(struct yaffs_obj *obj, YCHAR *name,+				int buffer_size)+{+	/* Create an object name if we could not find one. */+	if (strnlen(name, YAFFS_MAX_NAME_LENGTH) == 0) {+		YCHAR local_name[20];+		YCHAR num_string[20];+		YCHAR *x = &num_string[19];+		unsigned v = obj->obj_id;+		num_string[19] = 0;+		while (v > 0) {+			x--;+			*x = '0' + (v % 10);+			v /= 10;+		}+		/* make up a name */+		strcpy(local_name, YAFFS_LOSTNFOUND_PREFIX);+		strcat(local_name, x);+		strncpy(name, local_name, buffer_size - 1);+	}+}++int yaffs_get_obj_name(struct yaffs_obj *obj, YCHAR *name, int buffer_size)+{+	memset(name, 0, buffer_size * sizeof(YCHAR));+	yaffs_check_obj_details_loaded(obj);+	if (obj->obj_id == YAFFS_OBJECTID_LOSTNFOUND) {+		strncpy(name, YAFFS_LOSTNFOUND_NAME, buffer_size - 1);+	} else if (obj->short_name[0]) {+		strcpy(name, obj->short_name);+	} else if (obj->hdr_chunk > 0) {+		int result;+		u8 *buffer = yaffs_get_temp_buffer(obj->my_dev);++		struct yaffs_obj_hdr *oh = (struct yaffs_obj_hdr *)buffer;++		memset(buffer, 0, obj->my_dev->data_bytes_per_chunk);++		if (obj->hdr_chunk > 0) {+			result = yaffs_rd_chunk_tags_nand(obj->my_dev,+							  obj->hdr_chunk,+							  buffer, NULL);+		}+		yaffs_load_name_from_oh(obj->my_dev, name, oh->name,+					buffer_size);++		yaffs_release_temp_buffer(obj->my_dev, buffer);+	}++	yaffs_fix_null_name(obj, name, buffer_size);++	return strnlen(name, YAFFS_MAX_NAME_LENGTH);+}++loff_t yaffs_get_obj_length(struct yaffs_obj *obj)+{+	/* Dereference any hard linking */+	obj = yaffs_get_equivalent_obj(obj);++	if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE)+		return obj->variant.file_variant.file_size;+	if (obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK) {+		if (!obj->variant.symlink_variant.alias)+			return 0;+		return strnlen(obj->variant.symlink_variant.alias,+				     YAFFS_MAX_ALIAS_LENGTH);+	} else {+		/* Only a directory should drop through to here */+		return obj->my_dev->data_bytes_per_chunk;+	}+}++int yaffs_get_obj_link_count(struct yaffs_obj *obj)+{+	int count = 0;+	struct list_head *i;++	if (!obj->unlinked)+		count++;	/* the object itself */++	list_for_each(i, &obj->hard_links)+	    count++;		/* add the hard links; */++	return count;+}++int yaffs_get_obj_inode(struct yaffs_obj *obj)+{+	obj = yaffs_get_equivalent_obj(obj);++	return obj->obj_id;+}++unsigned yaffs_get_obj_type(struct yaffs_obj *obj)+{+	obj = yaffs_get_equivalent_obj(obj);++	switch (obj->variant_type) {+	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;+		return DT_REG;+		break;+	default:+		return DT_REG;+		break;+	}+}++YCHAR *yaffs_get_symlink_alias(struct yaffs_obj *obj)+{+	obj = yaffs_get_equivalent_obj(obj);+	if (obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK)+		return yaffs_clone_str(obj->variant.symlink_variant.alias);+	else+		return yaffs_clone_str(_Y(""));+}++/*--------------------------- Initialisation code -------------------------- */++static int yaffs_check_dev_fns(struct yaffs_dev *dev)+{+	struct yaffs_driver *drv = &dev->drv;+	struct yaffs_tags_handler *tagger = &dev->tagger;++	/* Common functions, gotta have */+	if (!drv->drv_read_chunk_fn ||+	    !drv->drv_write_chunk_fn ||+	    !drv->drv_erase_fn)+		return 0;++	if (dev->param.is_yaffs2 &&+	     (!drv->drv_mark_bad_fn  || !drv->drv_check_bad_fn))+		return 0;++	/* Install the default tags marshalling functions if needed. */+	yaffs_tags_compat_install(dev);+	yaffs_tags_marshall_install(dev);++	/* Check we now have the marshalling functions required. */+	if (!tagger->write_chunk_tags_fn ||+	    !tagger->read_chunk_tags_fn ||+	    !tagger->query_block_fn ||+	    !tagger->mark_bad_fn)+		return 0;++	return 1;+}++static int yaffs_create_initial_dir(struct yaffs_dev *dev)+{+	/* Initialise the unlinked, deleted, root and lost+found directories */+	dev->lost_n_found = dev->root_dir = NULL;+	dev->unlinked_dir = dev->del_dir = NULL;+	dev->unlinked_dir =+	    yaffs_create_fake_dir(dev, YAFFS_OBJECTID_UNLINKED, S_IFDIR);+	dev->del_dir =+	    yaffs_create_fake_dir(dev, YAFFS_OBJECTID_DELETED, S_IFDIR);+	dev->root_dir =+	    yaffs_create_fake_dir(dev, YAFFS_OBJECTID_ROOT,+				  YAFFS_ROOT_MODE | S_IFDIR);+	dev->lost_n_found =+	    yaffs_create_fake_dir(dev, YAFFS_OBJECTID_LOSTNFOUND,+				  YAFFS_LOSTNFOUND_MODE | S_IFDIR);++	if (dev->lost_n_found && dev->root_dir && dev->unlinked_dir+	    && dev->del_dir) {+		yaffs_add_obj_to_dir(dev->root_dir, dev->lost_n_found);+		return YAFFS_OK;+	}+	return YAFFS_FAIL;+}++/* Low level init.+ * Typically only used by yaffs_guts_initialise, but also used by the+ * Low level yaffs driver tests.+ */++int yaffs_guts_ll_init(struct yaffs_dev *dev)+{+++	yaffs_trace(YAFFS_TRACE_TRACING, "yaffs: yaffs_ll_init()");++	if (!dev) {+		yaffs_trace(YAFFS_TRACE_ALWAYS,+			"yaffs: Need a device"+			);+		return YAFFS_FAIL;+	}++	if (dev->ll_init)+		return YAFFS_OK;++	dev->internal_start_block = dev->param.start_block;+	dev->internal_end_block = dev->param.end_block;+	dev->block_offset = 0;+	dev->chunk_offset = 0;+	dev->n_free_chunks = 0;++	dev->gc_block = 0;++	if (dev->param.start_block == 0) {+		dev->internal_start_block = dev->param.start_block + 1;+		dev->internal_end_block = dev->param.end_block + 1;+		dev->block_offset = 1;+		dev->chunk_offset = dev->param.chunks_per_block;+	}++	/* Check geometry parameters. */++	if ((!dev->param.inband_tags && dev->param.is_yaffs2 &&+		dev->param.total_bytes_per_chunk < 1024) ||+		(!dev->param.is_yaffs2 &&+			dev->param.total_bytes_per_chunk < 512) ||+		(dev->param.inband_tags && !dev->param.is_yaffs2) ||+		 dev->param.chunks_per_block < 2 ||+		 dev->param.n_reserved_blocks < 2 ||+		dev->internal_start_block <= 0 ||+		dev->internal_end_block <= 0 ||+		dev->internal_end_block <=+		(dev->internal_start_block + dev->param.n_reserved_blocks + 2)+		) {+		/* otherwise it is too small */+		yaffs_trace(YAFFS_TRACE_ALWAYS,+			"NAND geometry problems: chunk size %d, type is yaffs%s, inband_tags %d ",+			dev->param.total_bytes_per_chunk,+			dev->param.is_yaffs2 ? "2" : "",+			dev->param.inband_tags);+		return YAFFS_FAIL;+	}++	/* Sort out space for inband tags, if required */+	if (dev->param.inband_tags)+		dev->data_bytes_per_chunk =+		    dev->param.total_bytes_per_chunk -+		    sizeof(struct yaffs_packed_tags2_tags_only);+	else+		dev->data_bytes_per_chunk = dev->param.total_bytes_per_chunk;++	/* Got the right mix of functions? */+	if (!yaffs_check_dev_fns(dev)) {+		/* Function missing */+		yaffs_trace(YAFFS_TRACE_ALWAYS,+			"device function(s) missing or wrong");++		return YAFFS_FAIL;+	}++	if (yaffs_init_nand(dev) != YAFFS_OK) {+		yaffs_trace(YAFFS_TRACE_ALWAYS, "InitialiseNAND failed");+		return YAFFS_FAIL;+	}++	return YAFFS_OK;+}+++int yaffs_guts_format_dev(struct yaffs_dev *dev)+{+	int i;+	enum yaffs_block_state state;+	u32 dummy;++	if(yaffs_guts_ll_init(dev) != YAFFS_OK)+		return YAFFS_FAIL;++	if(dev->is_mounted)+		return YAFFS_FAIL;++	for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {+		yaffs_query_init_block_state(dev, i, &state, &dummy);+		if (state != YAFFS_BLOCK_STATE_DEAD)+			yaffs_erase_block(dev, i);+	}++	return YAFFS_OK;+}+++int yaffs_guts_initialise(struct yaffs_dev *dev)+{+	int init_failed = 0;+	unsigned x;+	int bits;++	if(yaffs_guts_ll_init(dev) != YAFFS_OK)+		return YAFFS_FAIL;++	if (dev->is_mounted) {+		yaffs_trace(YAFFS_TRACE_ALWAYS, "device already mounted");+		return YAFFS_FAIL;+	}++	dev->is_mounted = 1;++	/* OK now calculate a few things for the device */++	/*+	 *  Calculate all the chunk size manipulation numbers:+	 */+	x = dev->data_bytes_per_chunk;+	/* We always use dev->chunk_shift and dev->chunk_div */+	dev->chunk_shift = calc_shifts(x);+	x >>= dev->chunk_shift;+	dev->chunk_div = x;+	/* We only use chunk mask if chunk_div is 1 */+	dev->chunk_mask = (1 << dev->chunk_shift) - 1;++	/*+	 * Calculate chunk_grp_bits.+	 * We need to find the next power of 2 > than internal_end_block+	 */++	x = dev->param.chunks_per_block * (dev->internal_end_block + 1);++	bits = calc_shifts_ceiling(x);++	/* Set up tnode width if wide tnodes are enabled. */+	if (!dev->param.wide_tnodes_disabled) {+		/* bits must be even so that we end up with 32-bit words */+		if (bits & 1)+			bits++;+		if (bits < 16)+			dev->tnode_width = 16;+		else+			dev->tnode_width = bits;+	} else {+		dev->tnode_width = 16;+	}++	dev->tnode_mask = (1 << dev->tnode_width) - 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 chunk_grp_size+	 */++	if (bits <= dev->tnode_width)+		dev->chunk_grp_bits = 0;+	else+		dev->chunk_grp_bits = bits - dev->tnode_width;++	dev->tnode_size = (dev->tnode_width * YAFFS_NTNODES_LEVEL0) / 8;+	if (dev->tnode_size < sizeof(struct yaffs_tnode))+		dev->tnode_size = sizeof(struct yaffs_tnode);++	dev->chunk_grp_size = 1 << dev->chunk_grp_bits;++	if (dev->param.chunks_per_block < dev->chunk_grp_size) {+		/* 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".+		 */+		yaffs_trace(YAFFS_TRACE_ALWAYS, "chunk group too large");++		return YAFFS_FAIL;+	}++	/* Finished verifying the device, continue with initialisation */++	/* More device initialisation */+	dev->all_gcs = 0;+	dev->passive_gc_count = 0;+	dev->oldest_dirty_gc_count = 0;+	dev->bg_gcs = 0;+	dev->gc_block_finder = 0;+	dev->buffered_block = -1;+	dev->doing_buffered_block_rewrite = 0;+	dev->n_deleted_files = 0;+	dev->n_bg_deletions = 0;+	dev->n_unlinked_files = 0;+	dev->n_ecc_fixed = 0;+	dev->n_ecc_unfixed = 0;+	dev->n_tags_ecc_fixed = 0;+	dev->n_tags_ecc_unfixed = 0;+	dev->n_erase_failures = 0;+	dev->n_erased_blocks = 0;+	dev->gc_disable = 0;+	dev->has_pending_prioritised_gc = 1;+		/* Assume the worst for now, will get fixed on first GC */+	INIT_LIST_HEAD(&dev->dirty_dirs);+	dev->oldest_dirty_seq = 0;+	dev->oldest_dirty_block = 0;++	/* Initialise temporary buffers and caches. */+	if (!yaffs_init_tmp_buffers(dev))+		init_failed = 1;++	dev->cache = NULL;+	dev->gc_cleanup_list = NULL;++	if (!init_failed && dev->param.n_caches > 0) {+		int i;+		void *buf;+		int cache_bytes =+		    dev->param.n_caches * sizeof(struct yaffs_cache);++		if (dev->param.n_caches > YAFFS_MAX_SHORT_OP_CACHES)+			dev->param.n_caches = YAFFS_MAX_SHORT_OP_CACHES;++		dev->cache = kmalloc(cache_bytes, GFP_NOFS);++		buf = (u8 *) dev->cache;++		if (dev->cache)+			memset(dev->cache, 0, cache_bytes);++		for (i = 0; i < dev->param.n_caches && buf; i++) {+			dev->cache[i].object = NULL;+			dev->cache[i].last_use = 0;+			dev->cache[i].dirty = 0;+			dev->cache[i].data = buf =+			    kmalloc(dev->param.total_bytes_per_chunk, GFP_NOFS);+		}+		if (!buf)+			init_failed = 1;++		dev->cache_last_use = 0;+	}++	dev->cache_hits = 0;++	if (!init_failed) {+		dev->gc_cleanup_list =+		    kmalloc(dev->param.chunks_per_block * sizeof(u32),+					GFP_NOFS);+		if (!dev->gc_cleanup_list)+			init_failed = 1;+	}++	if (dev->param.is_yaffs2)+		dev->param.use_header_file_size = 1;++	if (!init_failed && !yaffs_init_blocks(dev))+		init_failed = 1;++	yaffs_init_tnodes_and_objs(dev);++	if (!init_failed && !yaffs_create_initial_dir(dev))+		init_failed = 1;++	if (!init_failed && dev->param.is_yaffs2 &&+		!dev->param.disable_summary &&+		!yaffs_summary_init(dev))+		init_failed = 1;++	if (!init_failed) {+		/* Now scan the flash. */+		if (dev->param.is_yaffs2) {+			if (yaffs2_checkpt_restore(dev)) {+				yaffs_check_obj_details_loaded(dev->root_dir);+				yaffs_trace(YAFFS_TRACE_CHECKPOINT |+					YAFFS_TRACE_MOUNT,+					"yaffs: restored from checkpoint"+					);+			} else {++				/* Clean up the mess caused by an aborted+				 * checkpoint load then scan backwards.+				 */+				yaffs_deinit_blocks(dev);++				yaffs_deinit_tnodes_and_objs(dev);++				dev->n_erased_blocks = 0;+				dev->n_free_chunks = 0;+				dev->alloc_block = -1;+				dev->alloc_page = -1;+				dev->n_deleted_files = 0;+				dev->n_unlinked_files = 0;+				dev->n_bg_deletions = 0;++				if (!init_failed && !yaffs_init_blocks(dev))+					init_failed = 1;++				yaffs_init_tnodes_and_objs(dev);++				if (!init_failed+				    && !yaffs_create_initial_dir(dev))+					init_failed = 1;++				if (!init_failed && !yaffs2_scan_backwards(dev))+					init_failed = 1;+			}+		} else if (!yaffs1_scan(dev)) {+			init_failed = 1;+		}++		yaffs_strip_deleted_objs(dev);+		yaffs_fix_hanging_objs(dev);+		if (dev->param.empty_lost_n_found)+			yaffs_empty_l_n_f(dev);+	}++	if (init_failed) {+		/* Clean up the mess */+		yaffs_trace(YAFFS_TRACE_TRACING,+		  "yaffs: yaffs_guts_initialise() aborted.");++		yaffs_deinitialise(dev);+		return YAFFS_FAIL;+	}++	/* Zero out stats */+	dev->n_page_reads = 0;+	dev->n_page_writes = 0;+	dev->n_erasures = 0;+	dev->n_gc_copies = 0;+	dev->n_retried_writes = 0;++	dev->n_retired_blocks = 0;++	yaffs_verify_free_chunks(dev);+	yaffs_verify_blocks(dev);++	/* Clean up any aborted checkpoint data */+	if (!dev->is_checkpointed && dev->blocks_in_checkpt > 0)+		yaffs2_checkpt_invalidate(dev);++	yaffs_trace(YAFFS_TRACE_TRACING,+	  "yaffs: yaffs_guts_initialise() done.");+	return YAFFS_OK;+}++void yaffs_deinitialise(struct yaffs_dev *dev)+{+	if (dev->is_mounted) {+		int i;++		yaffs_deinit_blocks(dev);+		yaffs_deinit_tnodes_and_objs(dev);+		yaffs_summary_deinit(dev);++		if (dev->param.n_caches > 0 && dev->cache) {++			for (i = 0; i < dev->param.n_caches; i++) {+				kfree(dev->cache[i].data);+				dev->cache[i].data = NULL;+			}++			kfree(dev->cache);+			dev->cache = NULL;+		}++		kfree(dev->gc_cleanup_list);++		for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++)+			kfree(dev->temp_buffer[i].buffer);++		dev->is_mounted = 0;++		yaffs_deinit_nand(dev);+	}+}++int yaffs_count_free_chunks(struct yaffs_dev *dev)+{+	int n_free = 0;+	int b;+	struct yaffs_block_info *blk;++	blk = dev->block_info;+	for (b = dev->internal_start_block; b <= dev->internal_end_block; b++) {+		switch (blk->block_state) {+		case YAFFS_BLOCK_STATE_EMPTY:+		case YAFFS_BLOCK_STATE_ALLOCATING:+		case YAFFS_BLOCK_STATE_COLLECTING:+		case YAFFS_BLOCK_STATE_FULL:+			n_free +=+			    (dev->param.chunks_per_block - blk->pages_in_use ++			     blk->soft_del_pages);+			break;+		default:+			break;+		}+		blk++;+	}+	return n_free;+}++int yaffs_get_n_free_chunks(struct yaffs_dev *dev)+{+	/* This is what we report to the outside world */+	int n_free;+	int n_dirty_caches;+	int blocks_for_checkpt;+	int i;++	n_free = dev->n_free_chunks;+	n_free += dev->n_deleted_files;++	/* Now count and subtract the number of dirty chunks in the cache. */++	for (n_dirty_caches = 0, i = 0; i < dev->param.n_caches; i++) {+		if (dev->cache[i].dirty)+			n_dirty_caches++;+	}++	n_free -= n_dirty_caches;++	n_free -=+	    ((dev->param.n_reserved_blocks + 1) * dev->param.chunks_per_block);++	/* Now figure checkpoint space and report that... */+	blocks_for_checkpt = yaffs_calc_checkpt_blocks_required(dev);++	n_free -= (blocks_for_checkpt * dev->param.chunks_per_block);++	if (n_free < 0)+		n_free = 0;++	return n_free;+}++++/*+ * Marshalling functions to get loff_t file sizes into and out of+ * object headers.+ */+void yaffs_oh_size_load(struct yaffs_obj_hdr *oh, loff_t fsize)+{+	oh->file_size_low = (fsize & 0xFFFFFFFF);+	oh->file_size_high = ((fsize >> 32) & 0xFFFFFFFF);+}++loff_t yaffs_oh_to_size(struct yaffs_obj_hdr *oh)+{+	loff_t retval;++	if (sizeof(loff_t) >= 8 && ~(oh->file_size_high))+		retval = (((loff_t) oh->file_size_high) << 32) |+			(((loff_t) oh->file_size_low) & 0xFFFFFFFF);+	else+		retval = (loff_t) oh->file_size_low;++	return retval;+}+++void yaffs_count_blocks_by_state(struct yaffs_dev *dev, int bs[10])+{+	int i;+	struct yaffs_block_info *bi;+	int s;++	for(i = 0; i < 10; i++)+		bs[i] = 0;++	for(i = dev->internal_start_block; i <= dev->internal_end_block; i++) {+		bi = yaffs_get_block_info(dev, i);+		s = bi->block_state;+		if(s > YAFFS_BLOCK_STATE_DEAD || s < YAFFS_BLOCK_STATE_UNKNOWN)+			bs[0]++;+		else+			bs[s]++;+	}+}diff -Nur linux-3.15-rc5.orig/fs/yaffs2/yaffs_guts.h linux-3.15-rc5/fs/yaffs2/yaffs_guts.h--- linux-3.15-rc5.orig/fs/yaffs2/yaffs_guts.h	1970-01-01 01:00:00.000000000 +0100+++ linux-3.15-rc5/fs/yaffs2/yaffs_guts.h	2014-05-17 01:53:27.000000000 +0200@@ -0,0 +1,1007 @@+/*+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.+ *+ * Copyright (C) 2002-2011 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 "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++/*+ * Tnodes form a tree with the tnodes in "levels"+ * Levels greater than 0 hold 8 slots which point to other tnodes.+ * Those at level 0 hold 16 slots which point to chunks in NAND.+ *+ * A maximum level of 8 thust supports files of size up to:+ *+ * 2^(3*MAX_LEVEL+4)+ *+ * Thus a max level of 8 supports files with up to 2^^28 chunks which gives+ * a maximum file size of around 512Gbytees with 2k chunks.+ */+#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		8+#define YAFFS_TNODES_MAX_BITS		(YAFFS_TNODES_LEVEL0_BITS + \+					YAFFS_TNODES_INTERNAL_BITS * \+					YAFFS_TNODES_MAX_LEVEL)+#define YAFFS_MAX_CHUNK_ID		((1 << YAFFS_TNODES_MAX_BITS) - 1)++#define YAFFS_MAX_FILE_SIZE_32		0x7fffffff++/* Constants for YAFFS1 mode */+#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)++#define YAFFS_MIN_YAFFS2_CHUNK_SIZE	1024+#define YAFFS_MIN_YAFFS2_SPARE_SIZE	32++++#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_MAX_OBJECT_ID		(YAFFS_OBJECT_SPACE - 1)++/* Binary data version stamps */+#define YAFFS_SUMMARY_VERSION		1+#define YAFFS_CHECKPOINT_VERSION	7++#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++/* Fake object Id for summary data */+#define YAFFS_OBJECTID_SUMMARY		0x10++/* Pseudo object ids for checkpointing */+#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/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.*/+struct yaffs_cache {+	struct yaffs_obj *object;+	int chunk_id;+	int last_use;+	int dirty;+	int n_bytes;		/* Only valid if the cache is dirty */+	int locked;		/* Can't push out or flush while locked. */+	u8 *data;+};++/* yaffs1 tags structures in RAM+ * NB This uses bitfield. Bitfields should not straddle a u32 boundary+ * otherwise the structure size will get blown out.+ */++struct yaffs_tags {+	u32 chunk_id:20;+	u32 serial_number:2;+	u32 n_bytes_lsb:10;+	u32 obj_id:18;+	u32 ecc:12;+	u32 n_bytes_msb:2;+};++union yaffs_tags_union {+	struct yaffs_tags as_tags;+	u8 as_bytes[8];+};+++/* Stuff used for extended tags in YAFFS2 */++enum yaffs_ecc_result {+	YAFFS_ECC_RESULT_UNKNOWN,+	YAFFS_ECC_RESULT_NO_ERROR,+	YAFFS_ECC_RESULT_FIXED,+	YAFFS_ECC_RESULT_UNFIXED+};++enum yaffs_obj_type {+	YAFFS_OBJECT_TYPE_UNKNOWN,+	YAFFS_OBJECT_TYPE_FILE,+	YAFFS_OBJECT_TYPE_SYMLINK,+	YAFFS_OBJECT_TYPE_DIRECTORY,+	YAFFS_OBJECT_TYPE_HARDLINK,+	YAFFS_OBJECT_TYPE_SPECIAL+};++#define YAFFS_OBJECT_TYPE_MAX YAFFS_OBJECT_TYPE_SPECIAL++struct yaffs_ext_tags {+	unsigned chunk_used;	/*  Status of the chunk: used or unused */+	unsigned obj_id;	/* If 0 this is not used */+	unsigned chunk_id;	/* If 0 this is a header, else a data chunk */+	unsigned n_bytes;	/* Only valid for data chunks */++	/* The following stuff only has meaning when we read */+	enum yaffs_ecc_result ecc_result;+	unsigned block_bad;++	/* YAFFS 1 stuff */+	unsigned is_deleted;	/* The chunk is marked deleted */+	unsigned serial_number;	/* Yaffs1 2-bit serial number */++	/* YAFFS2 stuff */+	unsigned seq_number;	/* The sequence number of this block */++	/* Extra info if this is an object header (YAFFS2 only) */++	unsigned extra_available;	/* Extra info available if not zero */+	unsigned extra_parent_id;	/* The parent object */+	unsigned extra_is_shrink;	/* Is it a shrink header? */+	unsigned extra_shadows;	/* Does this shadow another object? */++	enum yaffs_obj_type extra_obj_type;	/* What object type? */++	loff_t extra_file_size;		/* Length if it is a file */+	unsigned extra_equiv_id;	/* Equivalent object for a hard link */+};++/* Spare structure for YAFFS1 */+struct yaffs_spare {+	u8 tb0;+	u8 tb1;+	u8 tb2;+	u8 tb3;+	u8 page_status;		/* set to 0 to delete the chunk */+	u8 block_status;+	u8 tb4;+	u8 tb5;+	u8 ecc1[3];+	u8 tb6;+	u8 tb7;+	u8 ecc2[3];+};++/*Special structure for passing through to mtd */+struct yaffs_nand_spare {+	struct yaffs_spare spare;+	int eccres1;+	int eccres2;+};++/* Block data in RAM */++enum yaffs_block_state {+	YAFFS_BLOCK_STATE_UNKNOWN = 0,++	YAFFS_BLOCK_STATE_SCANNING,+	/* Being scanned */++	YAFFS_BLOCK_STATE_NEEDS_SCAN,+	/* 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 scanning.+	 * 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.+	 * If a block is only partially allocated at mount it is treated as+	 * full.+	 */++	YAFFS_BLOCK_STATE_FULL,+	/* All the pages in this block have been allocated.+	 * If a block was only partially allocated when mounted we treat+	 * it as fully allocated.+	 */++	YAFFS_BLOCK_STATE_DIRTY,+	/* The block was full and now all chunks have been 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 */+};++#define	YAFFS_NUMBER_OF_BLOCK_STATES (YAFFS_BLOCK_STATE_DEAD + 1)++struct yaffs_block_info {++	s32 soft_del_pages:10;	/* number of soft deleted pages */+	s32 pages_in_use:10;	/* number of pages in use */+	u32 block_state:4;	/* One of the above block states. */+				/* NB use unsigned because enum is sometimes+				 * an int */+	u32 needs_retiring:1;	/* Data has failed on this block, */+				/*need to get valid data off and retire*/+	u32 skip_erased_check:1;/* Skip the erased check on this block */+	u32 gc_prioritise:1;	/* An ECC check or blank check has failed.+				   Block should be prioritised for GC */+	u32 chunk_error_strikes:3;	/* How many times we've had ecc etc+				failures on this block and tried to reuse it */+	u32 has_summary:1;	/* The block has a summary */++	u32 has_shrink_hdr:1;	/* This block has at least one shrink header */+	u32 seq_number;		/* block sequence number for yaffs2 */++};++/* -------------------------- Object structure -------------------------------*/+/* This is the object structure as stored on NAND */++struct yaffs_obj_hdr {+	enum yaffs_obj_type type;++	/* Apply to everything  */+	int parent_obj_id;+	u16 sum_no_longer_used;	/* checksum of name. No longer used */+	YCHAR name[YAFFS_MAX_NAME_LENGTH + 1];++	/* The following apply to all object types except for hard links */+	u32 yst_mode;		/* protection */++	u32 yst_uid;+	u32 yst_gid;+	u32 yst_atime;+	u32 yst_mtime;+	u32 yst_ctime;++	/* File size  applies to files only */+	u32 file_size_low;++	/* Equivalent object id applies to hard links only. */+	int equiv_id;++	/* Alias is for symlinks only. */+	YCHAR alias[YAFFS_MAX_ALIAS_LENGTH + 1];++	u32 yst_rdev;	/* stuff for block and char devices (major/min) */++	u32 win_ctime[2];+	u32 win_atime[2];+	u32 win_mtime[2];++	u32 inband_shadowed_obj_id;+	u32 inband_is_shrink;++	u32 file_size_high;+	u32 reserved[1];+	int shadows_obj;	/* This object header shadows the+				specified object if > 0 */++	/* is_shrink applies to object headers written when wemake a hole. */+	u32 is_shrink;++};++/*--------------------------- Tnode -------------------------- */++struct yaffs_tnode {+	struct yaffs_tnode *internal[YAFFS_NTNODES_INTERNAL];+};++/*------------------------  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+ */++struct yaffs_file_var {+	loff_t file_size;+	loff_t scanned_size;+	loff_t shrink_size;+	int top_level;+	struct yaffs_tnode *top;+};++struct yaffs_dir_var {+	struct list_head children;	/* list of child links */+	struct list_head dirty;	/* Entry for list of dirty directories */+};++struct yaffs_symlink_var {+	YCHAR *alias;+};++struct yaffs_hardlink_var {+	struct yaffs_obj *equiv_obj;+	u32 equiv_id;+};++union yaffs_obj_var {+	struct yaffs_file_var file_variant;+	struct yaffs_dir_var dir_variant;+	struct yaffs_symlink_var symlink_variant;+	struct yaffs_hardlink_var hardlink_variant;+};++struct yaffs_obj {+	u8 deleted:1;		/* This should only apply to unlinked files. */+	u8 soft_del:1;		/* it has also been soft deleted */+	u8 unlinked:1;		/* An unlinked file.*/+	u8 fake:1;		/* A fake object has no presence on NAND. */+	u8 rename_allowed:1;	/* Some objects cannot be renamed. */+	u8 unlink_allowed: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 chunks encountered before+				* the header.+				 */+	u8 lazy_loaded:1;	/* This object has been lazy loaded and+				 * is missing some detail */++	u8 defered_free:1;	/* Object is removed from NAND, but is+				 * still in the inode cache.+				 * Free of object is defered.+				 * until the inode is released.+				 */+	u8 being_created:1;	/* This object is still being created+				 * so skip some verification checks. */+	u8 is_shadowed:1;	/* This object is shadowed on the way+				 * to being renamed. */++	u8 xattr_known:1;	/* We know if this has object has xattribs+				 * or not. */+	u8 has_xattr:1;		/* This object has xattribs.+				 * Only valid if xattr_known. */++	u8 serial;		/* serial number of chunk in NAND.*/+	u16 sum;		/* sum of the name to speed searching */++	struct yaffs_dev *my_dev;	/* The device I'm on */++	struct list_head hash_link;	/* list of objects in hash bucket */++	struct list_head hard_links;	/* hard linked object chain*/++	/* directory structure stuff */+	/* also used for linking up the free list */+	struct yaffs_obj *parent;+	struct list_head siblings;++	/* Where's my object header in NAND? */+	int hdr_chunk;++	int n_data_chunks;	/* Number of data chunks for this file. */++	u32 obj_id;		/* the object id value */++	u32 yst_mode;++	YCHAR short_name[YAFFS_SHORT_NAME_LENGTH + 1];++#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;++	void *my_inode;++	enum yaffs_obj_type variant_type;++	union yaffs_obj_var variant;++};++struct yaffs_obj_bucket {+	struct list_head list;+	int count;+};++/* yaffs_checkpt_obj holds the definition of an object as dumped+ * by checkpointing.+ */++struct yaffs_checkpt_obj {+	int struct_type;+	u32 obj_id;+	u32 parent_id;+	int hdr_chunk;+	enum yaffs_obj_type variant_type:3;+	u8 deleted:1;+	u8 soft_del:1;+	u8 unlinked:1;+	u8 fake:1;+	u8 rename_allowed:1;+	u8 unlink_allowed:1;+	u8 serial;+	int n_data_chunks;+	loff_t size_or_equiv_obj;+};++/*--------------------- Temporary buffers ----------------+ *+ * These are chunk-sized working buffers. Each device has a few.+ */++struct yaffs_buffer {+	u8 *buffer;+	int in_use;+};++/*----------------- Device ---------------------------------*/++struct yaffs_param {+	const YCHAR *name;++	/*+	 * Entry parameters set up way early. Yaffs sets up the rest.+	 * The structure should be zeroed out before use so that unused+	 * and default values are zero.+	 */++	int inband_tags;	/* Use unband tags */+	u32 total_bytes_per_chunk;	/* Should be >= 512, does not need to+					 be a power of 2 */+	int chunks_per_block;	/* does not need to be a power of 2 */+	int spare_bytes_per_chunk;	/* spare area size */+	int start_block;	/* Start block we're allowed to use */+	int end_block;		/* End block we're allowed to use */+	int n_reserved_blocks;	/* Tuneable so that we can reduce+				 * reserved blocks on NOR and RAM. */++	int n_caches;		/* If <= 0, then short op caching is disabled,+				 * else the number of short op caches.+				 */+	int cache_bypass_aligned; /* If non-zero then bypass the cache for+				   * aligned writes.+				   */++	int use_nand_ecc;	/* Flag to decide whether or not to use+				 * NAND driver ECC on data (yaffs1) */+	int tags_9bytes;	/* Use 9 byte tags */+	int no_tags_ecc;	/* Flag to decide whether or not to do ECC+				 * on packed tags (yaffs2) */++	int is_yaffs2;		/* Use yaffs2 mode on this device */++	int empty_lost_n_found;	/* Auto-empty lost+found directory on mount */++	int refresh_period;	/* How often to check for a block refresh */++	/* Checkpoint control. Can be set before or after initialisation */+	u8 skip_checkpt_rd;+	u8 skip_checkpt_wr;++	int enable_xattr;	/* Enable xattribs */++	int max_objects;	/*+				 * Set to limit the number of objects created.+				 * 0 = no limit.+				*/++	/* The remove_obj_fn function must be supplied by OS flavours that+	 * need it.+	 * yaffs direct uses it to implement the faster readdir.+	 * Linux uses it to protect the directory during unlocking.+	 */+	void (*remove_obj_fn) (struct yaffs_obj *obj);++	/* Callback to mark the superblock dirty */+	void (*sb_dirty_fn) (struct yaffs_dev *dev);++	/*  Callback to control garbage collection. */+	unsigned (*gc_control_fn) (struct yaffs_dev *dev);++	/* Debug control flags. Don't use unless you know what you're doing */+	int use_header_file_size;	/* Flag to determine if we should use+					 * file sizes from the header */+	int disable_lazy_load;	/* Disable lazy loading on this device */+	int wide_tnodes_disabled;	/* Set to disable wide tnodes */+	int disable_soft_del;	/* yaffs 1 only: Set to disable the use of+				 * softdeletion. */++	int defered_dir_update;	/* Set to defer directory updates */++#ifdef CONFIG_YAFFS_AUTO_UNICODE+	int auto_unicode;+#endif+	int always_check_erased;	/* Force chunk erased check always on */++	int disable_summary;+	int disable_bad_block_marking;++};++struct yaffs_driver {+	int (*drv_write_chunk_fn) (struct yaffs_dev *dev, int nand_chunk,+				   const u8 *data, int data_len,+				   const u8 *oob, int oob_len);+	int (*drv_read_chunk_fn) (struct yaffs_dev *dev, int nand_chunk,+				   u8 *data, int data_len,+				   u8 *oob, int oob_len,+				   enum yaffs_ecc_result *ecc_result);+	int (*drv_erase_fn) (struct yaffs_dev *dev, int block_no);+	int (*drv_mark_bad_fn) (struct yaffs_dev *dev, int block_no);+	int (*drv_check_bad_fn) (struct yaffs_dev *dev, int block_no);+	int (*drv_initialise_fn) (struct yaffs_dev *dev);+	int (*drv_deinitialise_fn) (struct yaffs_dev *dev);+};++struct yaffs_tags_handler {+	int (*write_chunk_tags_fn) (struct yaffs_dev *dev,+				    int nand_chunk, const u8 *data,+				    const struct yaffs_ext_tags *tags);+	int (*read_chunk_tags_fn) (struct yaffs_dev *dev,+				   int nand_chunk, u8 *data,+				   struct yaffs_ext_tags *tags);++	int (*query_block_fn) (struct yaffs_dev *dev, int block_no,+			       enum yaffs_block_state *state,+			       u32 *seq_number);+	int (*mark_bad_fn) (struct yaffs_dev *dev, int block_no);+};++struct yaffs_dev {+	struct yaffs_param param;+	struct yaffs_driver drv;+	struct yaffs_tags_handler tagger;++	/* Context storage. Holds extra OS specific data for this device */++	void *os_context;+	void *driver_context;++	struct list_head dev_list;++	int ll_init;+	/* Runtime parameters. Set up by YAFFS. */+	int data_bytes_per_chunk;++	/* Non-wide tnode stuff */+	u16 chunk_grp_bits;	/* Number of bits that need to be resolved if+				 * the tnodes are not wide enough.+				 */+	u16 chunk_grp_size;	/* == 2^^chunk_grp_bits */++	/* Stuff to support wide tnodes */+	u32 tnode_width;+	u32 tnode_mask;+	u32 tnode_size;++	/* Stuff for figuring out file offset to chunk conversions */+	u32 chunk_shift;	/* Shift value */+	u32 chunk_div;		/* Divisor after shifting: 1 for 2^n sizes */+	u32 chunk_mask;		/* Mask to use for power-of-2 case */++	int is_mounted;+	int read_only;+	int is_checkpointed;++	/* Stuff to support block offsetting to support start block zero */+	int internal_start_block;+	int internal_end_block;+	int block_offset;+	int chunk_offset;++	/* Runtime checkpointing stuff */+	int checkpt_page_seq;	/* running sequence number of checkpt pages */+	int checkpt_byte_count;+	int checkpt_byte_offs;+	u8 *checkpt_buffer;+	int checkpt_open_write;+	int blocks_in_checkpt;+	int checkpt_cur_chunk;+	int checkpt_cur_block;+	int checkpt_next_block;+	int *checkpt_block_list;+	int checkpt_max_blocks;+	u32 checkpt_sum;+	u32 checkpt_xor;++	int checkpoint_blocks_required;	/* Number of blocks needed to store+					 * current checkpoint set */++	/* Block Info */+	struct yaffs_block_info *block_info;+	u8 *chunk_bits;		/* bitmap of chunks in use */+	u8 block_info_alt:1;	/* allocated using alternative alloc */+	u8 chunk_bits_alt:1;	/* allocated using alternative alloc */+	int chunk_bit_stride;	/* Number of bytes of chunk_bits per block.+				 * Must be consistent with chunks_per_block.+				 */++	int n_erased_blocks;+	int alloc_block;	/* Current block being allocated off */+	u32 alloc_page;+	int alloc_block_finder;	/* Used to search for next allocation block */++	/* Object and Tnode memory management */+	void *allocator;+	int n_obj;+	int n_tnodes;++	int n_hardlinks;++	struct yaffs_obj_bucket obj_bucket[YAFFS_NOBJECT_BUCKETS];+	u32 bucket_finder;++	int n_free_chunks;++	/* Garbage collection control */+	u32 *gc_cleanup_list;	/* objects to delete at the end of a GC. */+	u32 n_clean_ups;++	unsigned has_pending_prioritised_gc;	/* We think this device might+						have pending prioritised gcs */+	unsigned gc_disable;+	unsigned gc_block_finder;+	unsigned gc_dirtiest;+	unsigned gc_pages_in_use;+	unsigned gc_not_done;+	unsigned gc_block;+	unsigned gc_chunk;+	unsigned gc_skip;+	struct yaffs_summary_tags *gc_sum_tags;++	/* Special directories */+	struct yaffs_obj *root_dir;+	struct yaffs_obj *lost_n_found;++	int buffered_block;	/* Which block is buffered here? */+	int doing_buffered_block_rewrite;++	struct yaffs_cache *cache;+	int cache_last_use;++	/* Stuff for background deletion and unlinked files. */+	struct yaffs_obj *unlinked_dir;	/* Directory where unlinked and deleted+					 files live. */+	struct yaffs_obj *del_dir;	/* Directory where deleted objects are+					sent to disappear. */+	struct yaffs_obj *unlinked_deletion;	/* Current file being+							background deleted. */+	int n_deleted_files;	/* Count of files awaiting deletion; */+	int n_unlinked_files;	/* Count of unlinked files. */+	int n_bg_deletions;	/* Count of background deletions. */++	/* Temporary buffer management */+	struct yaffs_buffer temp_buffer[YAFFS_N_TEMP_BUFFERS];+	int max_temp;+	int temp_in_use;+	int unmanaged_buffer_allocs;+	int unmanaged_buffer_deallocs;++	/* yaffs2 runtime stuff */+	unsigned seq_number;	/* Sequence number of currently+					allocating block */+	unsigned oldest_dirty_seq;+	unsigned oldest_dirty_block;++	/* Block refreshing */+	int refresh_skip;	/* A skip down counter.+				 * Refresh happens when this gets to zero. */++	/* Dirty directory handling */+	struct list_head dirty_dirs;	/* List of dirty directories */++	/* Summary */+	int chunks_per_summary;+	struct yaffs_summary_tags *sum_tags;++	/* Statistics */+	u32 n_page_writes;+	u32 n_page_reads;+	u32 n_erasures;+	u32 n_bad_queries;+	u32 n_bad_markings;+	u32 n_erase_failures;+	u32 n_gc_copies;+	u32 all_gcs;+	u32 passive_gc_count;+	u32 oldest_dirty_gc_count;+	u32 n_gc_blocks;+	u32 bg_gcs;+	u32 n_retried_writes;+	u32 n_retired_blocks;+	u32 n_ecc_fixed;+	u32 n_ecc_unfixed;+	u32 n_tags_ecc_fixed;+	u32 n_tags_ecc_unfixed;+	u32 n_deletions;+	u32 n_unmarked_deletions;+	u32 refresh_count;+	u32 cache_hits;+	u32 tags_used;+	u32 summary_used;++};++/* The CheckpointDevice structure holds the device information that changes+ *at runtime and must be preserved over unmount/mount cycles.+ */+struct yaffs_checkpt_dev {+	int struct_type;+	int n_erased_blocks;+	int alloc_block;	/* Current block being allocated off */+	u32 alloc_page;+	int n_free_chunks;++	int n_deleted_files;	/* Count of files awaiting deletion; */+	int n_unlinked_files;	/* Count of unlinked files. */+	int n_bg_deletions;	/* Count of background deletions. */++	/* yaffs2 runtime stuff */+	unsigned seq_number;	/* Sequence number of currently+				 * allocating block */++};++struct yaffs_checkpt_validity {+	int struct_type;+	u32 magic;+	u32 version;+	u32 head;+};++struct yaffs_shadow_fixer {+	int obj_id;+	int shadowed_id;+	struct yaffs_shadow_fixer *next;+};++/* Structure for doing xattr modifications */+struct yaffs_xattr_mod {+	int set;		/* If 0 then this is a deletion */+	const YCHAR *name;+	const void *data;+	int size;+	int flags;+	int result;+};++/*----------------------- YAFFS Functions -----------------------*/++int yaffs_guts_initialise(struct yaffs_dev *dev);+void yaffs_deinitialise(struct yaffs_dev *dev);++int yaffs_get_n_free_chunks(struct yaffs_dev *dev);++int yaffs_rename_obj(struct yaffs_obj *old_dir, const YCHAR * old_name,+		     struct yaffs_obj *new_dir, const YCHAR * new_name);++int yaffs_unlinker(struct yaffs_obj *dir, const YCHAR * name);+int yaffs_del_obj(struct yaffs_obj *obj);+struct yaffs_obj *yaffs_retype_obj(struct yaffs_obj *obj,+				   enum yaffs_obj_type type);+++int yaffs_get_obj_name(struct yaffs_obj *obj, YCHAR * name, int buffer_size);+loff_t yaffs_get_obj_length(struct yaffs_obj *obj);+int yaffs_get_obj_inode(struct yaffs_obj *obj);+unsigned yaffs_get_obj_type(struct yaffs_obj *obj);+int yaffs_get_obj_link_count(struct yaffs_obj *obj);++/* File operations */+int yaffs_file_rd(struct yaffs_obj *obj, u8 * buffer, loff_t offset,+		  int n_bytes);+int yaffs_wr_file(struct yaffs_obj *obj, const u8 * buffer, loff_t offset,+		  int n_bytes, int write_trhrough);+int yaffs_resize_file(struct yaffs_obj *obj, loff_t new_size);++struct yaffs_obj *yaffs_create_file(struct yaffs_obj *parent,+				    const YCHAR *name, u32 mode, u32 uid,+				    u32 gid);++int yaffs_flush_file(struct yaffs_obj *obj, int update_time, int data_sync);++/* Flushing and checkpointing */+void yaffs_flush_whole_cache(struct yaffs_dev *dev);++int yaffs_checkpoint_save(struct yaffs_dev *dev);+int yaffs_checkpoint_restore(struct yaffs_dev *dev);++/* Directory operations */+struct yaffs_obj *yaffs_create_dir(struct yaffs_obj *parent, const YCHAR *name,+				   u32 mode, u32 uid, u32 gid);+struct yaffs_obj *yaffs_find_by_name(struct yaffs_obj *the_dir,+				     const YCHAR *name);+struct yaffs_obj *yaffs_find_by_number(struct yaffs_dev *dev, u32 number);++/* Link operations */+struct yaffs_obj *yaffs_link_obj(struct yaffs_obj *parent, const YCHAR *name,+				 struct yaffs_obj *equiv_obj);++struct yaffs_obj *yaffs_get_equivalent_obj(struct yaffs_obj *obj);++/* Symlink operations */+struct yaffs_obj *yaffs_create_symlink(struct yaffs_obj *parent,+				       const YCHAR *name, u32 mode, u32 uid,+				       u32 gid, const YCHAR *alias);+YCHAR *yaffs_get_symlink_alias(struct yaffs_obj *obj);++/* Special inodes (fifos, sockets and devices) */+struct yaffs_obj *yaffs_create_special(struct yaffs_obj *parent,+				       const YCHAR *name, u32 mode, u32 uid,+				       u32 gid, u32 rdev);++int yaffs_set_xattrib(struct yaffs_obj *obj, const YCHAR *name,+		      const void *value, int size, int flags);+int yaffs_get_xattrib(struct yaffs_obj *obj, const YCHAR *name, void *value,+		      int size);+int yaffs_list_xattrib(struct yaffs_obj *obj, char *buffer, int size);+int yaffs_remove_xattrib(struct yaffs_obj *obj, const YCHAR *name);++/* Special directories */+struct yaffs_obj *yaffs_root(struct yaffs_dev *dev);+struct yaffs_obj *yaffs_lost_n_found(struct yaffs_dev *dev);++void yaffs_handle_defered_free(struct yaffs_obj *obj);++void yaffs_update_dirty_dirs(struct yaffs_dev *dev);++int yaffs_bg_gc(struct yaffs_dev *dev, unsigned urgency);++/* Debug dump  */+int yaffs_dump_obj(struct yaffs_obj *obj);++void yaffs_guts_test(struct yaffs_dev *dev);+int yaffs_guts_ll_init(struct yaffs_dev *dev);+++/* A few useful functions to be used within the core files*/+void yaffs_chunk_del(struct yaffs_dev *dev, int chunk_id, int mark_flash,+		     int lyn);+int yaffs_check_ff(u8 *buffer, int n_bytes);+void yaffs_handle_chunk_error(struct yaffs_dev *dev,+			      struct yaffs_block_info *bi);++u8 *yaffs_get_temp_buffer(struct yaffs_dev *dev);+void yaffs_release_temp_buffer(struct yaffs_dev *dev, u8 *buffer);++struct yaffs_obj *yaffs_find_or_create_by_number(struct yaffs_dev *dev,+						 int number,+						 enum yaffs_obj_type type);+int yaffs_put_chunk_in_file(struct yaffs_obj *in, int inode_chunk,+			    int nand_chunk, int in_scan);+void yaffs_set_obj_name(struct yaffs_obj *obj, const YCHAR *name);+void yaffs_set_obj_name_from_oh(struct yaffs_obj *obj,+				const struct yaffs_obj_hdr *oh);+void yaffs_add_obj_to_dir(struct yaffs_obj *directory, struct yaffs_obj *obj);+YCHAR *yaffs_clone_str(const YCHAR *str);+void yaffs_link_fixup(struct yaffs_dev *dev, struct list_head *hard_list);+void yaffs_block_became_dirty(struct yaffs_dev *dev, int block_no);+int yaffs_update_oh(struct yaffs_obj *in, const YCHAR *name,+		    int force, int is_shrink, int shadows,+		    struct yaffs_xattr_mod *xop);+void yaffs_handle_shadowed_obj(struct yaffs_dev *dev, int obj_id,+			       int backward_scanning);+int yaffs_check_alloc_available(struct yaffs_dev *dev, int n_chunks);+struct yaffs_tnode *yaffs_get_tnode(struct yaffs_dev *dev);+struct yaffs_tnode *yaffs_add_find_tnode_0(struct yaffs_dev *dev,+					   struct yaffs_file_var *file_struct,+					   u32 chunk_id,+					   struct yaffs_tnode *passed_tn);++int yaffs_do_file_wr(struct yaffs_obj *in, const u8 *buffer, loff_t offset,+		     int n_bytes, int write_trhrough);+void yaffs_resize_file_down(struct yaffs_obj *obj, loff_t new_size);+void yaffs_skip_rest_of_block(struct yaffs_dev *dev);++int yaffs_count_free_chunks(struct yaffs_dev *dev);++struct yaffs_tnode *yaffs_find_tnode_0(struct yaffs_dev *dev,+				       struct yaffs_file_var *file_struct,+				       u32 chunk_id);++u32 yaffs_get_group_base(struct yaffs_dev *dev, struct yaffs_tnode *tn,+			 unsigned pos);++int yaffs_is_non_empty_dir(struct yaffs_obj *obj);++int yaffs_guts_format_dev(struct yaffs_dev *dev);++void yaffs_addr_to_chunk(struct yaffs_dev *dev, loff_t addr,+				int *chunk_out, u32 *offset_out);+/*+ * Marshalling functions to get loff_t file sizes into aand out of+ * object headers.+ */+void yaffs_oh_size_load(struct yaffs_obj_hdr *oh, loff_t fsize);+loff_t yaffs_oh_to_size(struct yaffs_obj_hdr *oh);+loff_t yaffs_max_file_size(struct yaffs_dev *dev);++/*+ * Debug function to count number of blocks in each state+ * NB Needs to be called with correct number of integers+ */++void yaffs_count_blocks_by_state(struct yaffs_dev *dev, int bs[10]);++int yaffs_find_chunk_in_file(struct yaffs_obj *in, int inode_chunk,+				    struct yaffs_ext_tags *tags);++#endifdiff -Nur linux-3.15-rc5.orig/fs/yaffs2/yaffs_linux.h linux-3.15-rc5/fs/yaffs2/yaffs_linux.h--- linux-3.15-rc5.orig/fs/yaffs2/yaffs_linux.h	1970-01-01 01:00:00.000000000 +0100+++ linux-3.15-rc5/fs/yaffs2/yaffs_linux.h	2014-05-17 01:53:27.000000000 +0200@@ -0,0 +1,48 @@+/*+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.+ *+ * Copyright (C) 2002-2011 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_LINUX_H__+#define __YAFFS_LINUX_H__++#include "yportenv.h"++struct yaffs_linux_context {+	struct list_head context_list;	/* List of these we have mounted */+	struct yaffs_dev *dev;+	struct super_block *super;+	struct task_struct *bg_thread;	/* Background thread for this device */+	int bg_running;+	struct mutex gross_lock;	/* Gross locking mutex*/+	u8 *spare_buffer;	/* For mtdif2 use. Don't know the buffer size+				 * at compile time so we have to allocate it.+				 */+	struct list_head search_contexts;+	struct task_struct *readdir_process;+	unsigned mount_id;+	int dirty;+};++#define yaffs_dev_to_lc(dev) ((struct yaffs_linux_context *)((dev)->os_context))+#define yaffs_dev_to_mtd(dev) ((struct mtd_info *)((dev)->driver_context))++#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++#endifdiff -Nur linux-3.15-rc5.orig/fs/yaffs2/yaffs_mtdif.c linux-3.15-rc5/fs/yaffs2/yaffs_mtdif.c--- linux-3.15-rc5.orig/fs/yaffs2/yaffs_mtdif.c	1970-01-01 01:00:00.000000000 +0100+++ linux-3.15-rc5/fs/yaffs2/yaffs_mtdif.c	2014-05-17 01:53:27.000000000 +0200@@ -0,0 +1,309 @@+/*+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.+ *+ * Copyright (C) 2002-2011 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 "yportenv.h"++#include "yaffs_mtdif.h"++#include "linux/mtd/mtd.h"+#include "linux/types.h"+#include "linux/time.h"+#include "linux/major.h"+#include "linux/mtd/nand.h"+#include "linux/kernel.h"+#include "linux/version.h"+#include "linux/types.h"++#include "yaffs_trace.h"+#include "yaffs_guts.h"+#include "yaffs_linux.h"+++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0))+#define MTD_OPS_AUTO_OOB MTD_OOB_AUTO+#endif+++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0))+#define mtd_erase(m, ei) (m)->erase(m, ei)+#define mtd_write_oob(m, addr, pops) (m)->write_oob(m, addr, pops)+#define mtd_read_oob(m, addr, pops) (m)->read_oob(m, addr, pops)+#define mtd_block_isbad(m, offs) (m)->block_isbad(m, offs)+#define mtd_block_markbad(m, offs) (m)->block_markbad(m, offs)+#endif++++int nandmtd_erase_block(struct yaffs_dev *dev, int block_no)+{+	struct mtd_info *mtd = yaffs_dev_to_mtd(dev);+	u32 addr =+	    ((loff_t) block_no) * dev->param.total_bytes_per_chunk *+	    dev->param.chunks_per_block;+	struct erase_info ei;+	int retval = 0;++	ei.mtd = mtd;+	ei.addr = addr;+	ei.len = dev->param.total_bytes_per_chunk * dev->param.chunks_per_block;+	ei.time = 1000;+	ei.retries = 2;+	ei.callback = NULL;+	ei.priv = (u_long) dev;++	retval = mtd_erase(mtd, &ei);++	if (retval == 0)+		return YAFFS_OK;++	return YAFFS_FAIL;+}+++static 	int yaffs_mtd_write(struct yaffs_dev *dev, int nand_chunk,+				   const u8 *data, int data_len,+				   const u8 *oob, int oob_len)+{+	struct mtd_info *mtd = yaffs_dev_to_mtd(dev);+	loff_t addr;+	struct mtd_oob_ops ops;+	int retval;++	yaffs_trace(YAFFS_TRACE_MTD,+			"yaffs_mtd_write(%p, %d, %p, %d, %p, %d)\n",+			dev, nand_chunk, data, data_len, oob, oob_len);++	if (!data || !data_len) {+		data = NULL;+		data_len = 0;+	}++	if (!oob || !oob_len) {+		oob = NULL;+		oob_len = 0;+	}++	addr = ((loff_t) nand_chunk) * dev->param.total_bytes_per_chunk;+	memset(&ops, 0, sizeof(ops));+	ops.mode = MTD_OPS_AUTO_OOB;+	ops.len = (data) ? data_len : 0;+	ops.ooblen = oob_len;+	ops.datbuf = (u8 *)data;+	ops.oobbuf = (u8 *)oob;++	retval = mtd_write_oob(mtd, addr, &ops);+	if (retval) {+		yaffs_trace(YAFFS_TRACE_MTD,+			"write_oob failed, chunk %d, mtd error %d",+			nand_chunk, retval);+	}+	return retval ? YAFFS_FAIL : YAFFS_OK;+}++static int yaffs_mtd_read(struct yaffs_dev *dev, int nand_chunk,+				   u8 *data, int data_len,+				   u8 *oob, int oob_len,+				   enum yaffs_ecc_result *ecc_result)+{+	struct mtd_info *mtd = yaffs_dev_to_mtd(dev);+	loff_t addr;+	struct mtd_oob_ops ops;+	int retval;++	addr = ((loff_t) nand_chunk) * dev->param.total_bytes_per_chunk;+	memset(&ops, 0, sizeof(ops));+	ops.mode = MTD_OPS_AUTO_OOB;+	ops.len = (data) ? data_len : 0;+	ops.ooblen = oob_len;+	ops.datbuf = data;+	ops.oobbuf = oob;++#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",+			nand_chunk, retval);++	switch (retval) {+	case 0:+		/* no error */+		if(ecc_result)+			*ecc_result = YAFFS_ECC_RESULT_NO_ERROR;+		break;++	case -EUCLEAN:+		/* MTD's ECC fixed the data */+		if(ecc_result)+			*ecc_result = YAFFS_ECC_RESULT_FIXED;+		dev->n_ecc_fixed++;+		break;++	case -EBADMSG:+	default:+		/* MTD's ECC could not fix the data */+		dev->n_ecc_unfixed++;+		if(ecc_result)+			*ecc_result = YAFFS_ECC_RESULT_UNFIXED;+		return YAFFS_FAIL;+	}++	return YAFFS_OK;+}++static 	int yaffs_mtd_erase(struct yaffs_dev *dev, int block_no)+{+	struct mtd_info *mtd = yaffs_dev_to_mtd(dev);++	loff_t addr;+	struct erase_info ei;+	int retval = 0;+	u32 block_size;++	block_size = dev->param.total_bytes_per_chunk *+		     dev->param.chunks_per_block;+	addr = ((loff_t) block_no) * block_size;++	ei.mtd = mtd;+	ei.addr = addr;+	ei.len = block_size;+	ei.time = 1000;+	ei.retries = 2;+	ei.callback = NULL;+	ei.priv = (u_long) dev;++	retval = mtd_erase(mtd, &ei);++	if (retval == 0)+		return YAFFS_OK;++	return YAFFS_FAIL;+}++static int yaffs_mtd_mark_bad(struct yaffs_dev *dev, int block_no)+{+	struct mtd_info *mtd = yaffs_dev_to_mtd(dev);+	int blocksize = dev->param.chunks_per_block * dev->param.total_bytes_per_chunk;+	int retval;++	yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, "marking block %d bad", block_no);++	retval = mtd_block_markbad(mtd, (loff_t) blocksize * block_no);+	return (retval) ? YAFFS_FAIL : YAFFS_OK;+}++static int yaffs_mtd_check_bad(struct yaffs_dev *dev, int block_no)+{+	struct mtd_info *mtd = yaffs_dev_to_mtd(dev);+	int blocksize = dev->param.chunks_per_block * dev->param.total_bytes_per_chunk;+	int retval;++	yaffs_trace(YAFFS_TRACE_MTD, "checking block %d bad", block_no);++	retval = mtd_block_isbad(mtd, (loff_t) blocksize * block_no);+	return (retval) ? YAFFS_FAIL : YAFFS_OK;+}++static int yaffs_mtd_initialise(struct yaffs_dev *dev)+{+	return YAFFS_OK;+}++static int yaffs_mtd_deinitialise(struct yaffs_dev *dev)+{+	return YAFFS_OK;+}+++void yaffs_mtd_drv_install(struct yaffs_dev *dev)+{+	struct yaffs_driver *drv = &dev->drv;++	drv->drv_write_chunk_fn = yaffs_mtd_write;+	drv->drv_read_chunk_fn = yaffs_mtd_read;+	drv->drv_erase_fn = yaffs_mtd_erase;+	drv->drv_mark_bad_fn = yaffs_mtd_mark_bad;+	drv->drv_check_bad_fn = yaffs_mtd_check_bad;+	drv->drv_initialise_fn = yaffs_mtd_initialise;+	drv->drv_deinitialise_fn = yaffs_mtd_deinitialise;+}+++struct mtd_info * yaffs_get_mtd_device(dev_t sdev)+{+	struct mtd_info *mtd;++	mtd = yaffs_get_mtd_device(sdev);++	/* Check it's an mtd device..... */+	if (MAJOR(sdev) != MTD_BLOCK_MAJOR)+		return NULL;	/* This isn't an mtd device */++	/* Check it's NAND */+	if (mtd->type != MTD_NANDFLASH) {+		yaffs_trace(YAFFS_TRACE_ALWAYS,+			"yaffs: MTD device is not NAND it's type %d",+			mtd->type);+		return NULL;+	}++	yaffs_trace(YAFFS_TRACE_OS, " %s %d", WRITE_SIZE_STR, WRITE_SIZE(mtd));+	yaffs_trace(YAFFS_TRACE_OS, " oobsize %d", mtd->oobsize);+	yaffs_trace(YAFFS_TRACE_OS, " erasesize %d", mtd->erasesize);+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)+	yaffs_trace(YAFFS_TRACE_OS, " size %u", mtd->size);+#else+	yaffs_trace(YAFFS_TRACE_OS, " size %lld", mtd->size);+#endif++	return mtd;+}++int yaffs_verify_mtd(struct mtd_info *mtd, int yaffs_version, int inband_tags)+{+	if (yaffs_version == 2) {+		if ((WRITE_SIZE(mtd) < YAFFS_MIN_YAFFS2_CHUNK_SIZE ||+		     mtd->oobsize < YAFFS_MIN_YAFFS2_SPARE_SIZE) &&+		    !inband_tags) {+			yaffs_trace(YAFFS_TRACE_ALWAYS,+				"MTD device does not have the right page sizes"+			);+			return -1;+		}+	} else {+		if (WRITE_SIZE(mtd) < YAFFS_BYTES_PER_CHUNK ||+		    mtd->oobsize != YAFFS_BYTES_PER_SPARE) {+			yaffs_trace(YAFFS_TRACE_ALWAYS,+				"MTD device does not support have the right page sizes"+			);+			return -1;+		}+	}++	return 0;+}+++void yaffs_put_mtd_device(struct mtd_info *mtd)+{+	if(mtd)+		put_mtd_device(mtd);+}diff -Nur linux-3.15-rc5.orig/fs/yaffs2/yaffs_mtdif.h linux-3.15-rc5/fs/yaffs2/yaffs_mtdif.h--- linux-3.15-rc5.orig/fs/yaffs2/yaffs_mtdif.h	1970-01-01 01:00:00.000000000 +0100+++ linux-3.15-rc5/fs/yaffs2/yaffs_mtdif.h	2014-05-17 01:53:27.000000000 +0200@@ -0,0 +1,25 @@+/*+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.+ *+ * Copyright (C) 2002-2011 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"++void yaffs_mtd_drv_install(struct yaffs_dev *dev);+struct mtd_info * yaffs_get_mtd_device(dev_t sdev);+void yaffs_put_mtd_device(struct mtd_info *mtd);+int yaffs_verify_mtd(struct mtd_info *mtd, int yaffs_version, int inband_tags);+#endifdiff -Nur linux-3.15-rc5.orig/fs/yaffs2/yaffs_nameval.c linux-3.15-rc5/fs/yaffs2/yaffs_nameval.c--- linux-3.15-rc5.orig/fs/yaffs2/yaffs_nameval.c	1970-01-01 01:00:00.000000000 +0100+++ linux-3.15-rc5/fs/yaffs2/yaffs_nameval.c	2014-05-17 01:53:27.000000000 +0200@@ -0,0 +1,208 @@+/*+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.+ *+ * Copyright (C) 2002-2011 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 simple implementation of a name-value store assumes a small number of+* values and fits into a small finite buffer.+ *+ * Each attribute is stored as a record:+ *  sizeof(int) bytes   record size.+ *  strnlen+1 bytes name null terminated.+ *  nbytes    value.+ *  ----------+ *  total size  stored in record size+ *+ * This code has not been tested with unicode yet.+ */++#include "yaffs_nameval.h"++#include "yportenv.h"++static int nval_find(const char *xb, int xb_size, const YCHAR *name,+		     int *exist_size)+{+	int pos = 0;+	int size;++	memcpy(&size, xb, sizeof(int));+	while (size > 0 && (size < xb_size) && (pos + size < xb_size)) {+		if (!strncmp((YCHAR *) (xb + pos + sizeof(int)),+				name, size)) {+			if (exist_size)+				*exist_size = size;+			return pos;+		}+		pos += size;+		if (pos < xb_size - sizeof(int))+			memcpy(&size, xb + pos, sizeof(int));+		else+			size = 0;+	}+	if (exist_size)+		*exist_size = 0;+	return -ENODATA;+}++static int nval_used(const char *xb, int xb_size)+{+	int pos = 0;+	int size;++	memcpy(&size, xb + pos, sizeof(int));+	while (size > 0 && (size < xb_size) && (pos + size < xb_size)) {+		pos += size;+		if (pos < xb_size - sizeof(int))+			memcpy(&size, xb + pos, sizeof(int));+		else+			size = 0;+	}+	return pos;+}++int nval_del(char *xb, int xb_size, const YCHAR *name)+{+	int pos = nval_find(xb, xb_size, name, NULL);+	int size;++	if (pos < 0 || pos >= xb_size)+		return -ENODATA;++	/* Find size, shift rest over this record,+	 * then zero out the rest of buffer */+	memcpy(&size, xb + pos, sizeof(int));+	memcpy(xb + pos, xb + pos + size, xb_size - (pos + size));+	memset(xb + (xb_size - size), 0, size);+	return 0;+}++int nval_set(char *xb, int xb_size, const YCHAR *name, const char *buf,+		int bsize, int flags)+{+	int pos;+	int namelen = strnlen(name, xb_size);+	int reclen;+	int size_exist = 0;+	int space;+	int start;++	pos = nval_find(xb, xb_size, name, &size_exist);++	if (flags & XATTR_CREATE && pos >= 0)+		return -EEXIST;+	if (flags & XATTR_REPLACE && pos < 0)+		return -ENODATA;++	start = nval_used(xb, xb_size);+	space = xb_size - start + size_exist;++	reclen = (sizeof(int) + namelen + 1 + bsize);++	if (reclen > space)+		return -ENOSPC;++	if (pos >= 0) {+		nval_del(xb, xb_size, name);+		start = nval_used(xb, xb_size);+	}++	pos = start;++	memcpy(xb + pos, &reclen, sizeof(int));+	pos += sizeof(int);+	strncpy((YCHAR *) (xb + pos), name, reclen);+	pos += (namelen + 1);+	memcpy(xb + pos, buf, bsize);+	return 0;+}++int nval_get(const char *xb, int xb_size, const YCHAR * name, char *buf,+	     int bsize)+{+	int pos = nval_find(xb, xb_size, name, NULL);+	int size;++	if (pos >= 0 && pos < xb_size) {++		memcpy(&size, xb + pos, sizeof(int));+		pos += sizeof(int);	/* advance past record length */+		size -= sizeof(int);++		/* Advance over name string */+		while (xb[pos] && size > 0 && pos < xb_size) {+			pos++;+			size--;+		}+		/*Advance over NUL */+		pos++;+		size--;++		/* If bsize is zero then this is a size query.+		 * Return the size, but don't copy.+		 */+		if (!bsize)+			return size;++		if (size <= bsize) {+			memcpy(buf, xb + pos, size);+			return size;+		}+	}+	if (pos >= 0)+		return -ERANGE;++	return -ENODATA;+}++int nval_list(const char *xb, int xb_size, char *buf, int bsize)+{+	int pos = 0;+	int size;+	int name_len;+	int ncopied = 0;+	int filled = 0;++	memcpy(&size, xb + pos, sizeof(int));+	while (size > sizeof(int) &&+		size <= xb_size &&+		(pos + size) < xb_size &&+		!filled) {+		pos += sizeof(int);+		size -= sizeof(int);+		name_len = strnlen((YCHAR *) (xb + pos), size);+		if (ncopied + name_len + 1 < bsize) {+			memcpy(buf, xb + pos, name_len * sizeof(YCHAR));+			buf += name_len;+			*buf = '\0';+			buf++;+			if (sizeof(YCHAR) > 1) {+				*buf = '\0';+				buf++;+			}+			ncopied += (name_len + 1);+		} else {+			filled = 1;+		}+		pos += size;+		if (pos < xb_size - sizeof(int))+			memcpy(&size, xb + pos, sizeof(int));+		else+			size = 0;+	}+	return ncopied;+}++int nval_hasvalues(const char *xb, int xb_size)+{+	return nval_used(xb, xb_size) > 0;+}diff -Nur linux-3.15-rc5.orig/fs/yaffs2/yaffs_nameval.h linux-3.15-rc5/fs/yaffs2/yaffs_nameval.h--- linux-3.15-rc5.orig/fs/yaffs2/yaffs_nameval.h	1970-01-01 01:00:00.000000000 +0100+++ linux-3.15-rc5/fs/yaffs2/yaffs_nameval.h	2014-05-17 01:53:27.000000000 +0200@@ -0,0 +1,28 @@+/*+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.+ *+ * Copyright (C) 2002-2011 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 __NAMEVAL_H__+#define __NAMEVAL_H__++#include "yportenv.h"++int nval_del(char *xb, int xb_size, const YCHAR * name);+int nval_set(char *xb, int xb_size, const YCHAR * name, const char *buf,+	     int bsize, int flags);+int nval_get(const char *xb, int xb_size, const YCHAR * name, char *buf,+	     int bsize);+int nval_list(const char *xb, int xb_size, char *buf, int bsize);+int nval_hasvalues(const char *xb, int xb_size);+#endifdiff -Nur linux-3.15-rc5.orig/fs/yaffs2/yaffs_nand.c linux-3.15-rc5/fs/yaffs2/yaffs_nand.c--- linux-3.15-rc5.orig/fs/yaffs2/yaffs_nand.c	1970-01-01 01:00:00.000000000 +0100+++ linux-3.15-rc5/fs/yaffs2/yaffs_nand.c	2014-05-17 01:53:27.000000000 +0200@@ -0,0 +1,122 @@+/*+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.+ *+ * Copyright (C) 2002-2011 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_nand.h"+#include "yaffs_tagscompat.h"++#include "yaffs_getblockinfo.h"+#include "yaffs_summary.h"++static int apply_chunk_offset(struct yaffs_dev *dev, int chunk)+{+	return chunk - dev->chunk_offset;+}++int yaffs_rd_chunk_tags_nand(struct yaffs_dev *dev, int nand_chunk,+			     u8 *buffer, struct yaffs_ext_tags *tags)+{+	int result;+	struct yaffs_ext_tags local_tags;+	int flash_chunk = apply_chunk_offset(dev, nand_chunk);++	dev->n_page_reads++;++	/* If there are no tags provided use local tags. */+	if (!tags)+		tags = &local_tags;++	result = dev->tagger.read_chunk_tags_fn(dev, flash_chunk, buffer, tags);+	if (tags && tags->ecc_result > YAFFS_ECC_RESULT_NO_ERROR) {++		struct yaffs_block_info *bi;+		bi = yaffs_get_block_info(dev,+					  nand_chunk /+					  dev->param.chunks_per_block);+		yaffs_handle_chunk_error(dev, bi);+	}+	return result;+}++int yaffs_wr_chunk_tags_nand(struct yaffs_dev *dev,+				int nand_chunk,+				const u8 *buffer, struct yaffs_ext_tags *tags)+{+	int result;+	int flash_chunk = apply_chunk_offset(dev, nand_chunk);++	dev->n_page_writes++;++	if (!tags) {+		yaffs_trace(YAFFS_TRACE_ERROR, "Writing with no tags");+		BUG();+		return YAFFS_FAIL;+	}++	tags->seq_number = dev->seq_number;+	tags->chunk_used = 1;+	yaffs_trace(YAFFS_TRACE_WRITE,+		"Writing chunk %d tags %d %d",+		nand_chunk, tags->obj_id, tags->chunk_id);++	result = dev->tagger.write_chunk_tags_fn(dev, flash_chunk,+							buffer, tags);++	yaffs_summary_add(dev, tags, nand_chunk);++	return result;+}++int yaffs_mark_bad(struct yaffs_dev *dev, int block_no)+{+	block_no -= dev->block_offset;+	dev->n_bad_markings++;++	if (dev->param.disable_bad_block_marking)+		return YAFFS_OK;++	return dev->tagger.mark_bad_fn(dev, block_no);+}+++int yaffs_query_init_block_state(struct yaffs_dev *dev,+				 int block_no,+				 enum yaffs_block_state *state,+				 u32 *seq_number)+{+	block_no -= dev->block_offset;+	return dev->tagger.query_block_fn(dev, block_no, state, seq_number);+}++int yaffs_erase_block(struct yaffs_dev *dev, int block_no)+{+	int result;++	block_no -= dev->block_offset;+	dev->n_erasures++;+	result = dev->drv.drv_erase_fn(dev, block_no);+	return result;+}++int yaffs_init_nand(struct yaffs_dev *dev)+{+	if (dev->drv.drv_initialise_fn)+		return dev->drv.drv_initialise_fn(dev);+	return YAFFS_OK;+}++int yaffs_deinit_nand(struct yaffs_dev *dev)+{+	if (dev->drv.drv_deinitialise_fn)+		return dev->drv.drv_deinitialise_fn(dev);+	return YAFFS_OK;+}diff -Nur linux-3.15-rc5.orig/fs/yaffs2/yaffs_nand.h linux-3.15-rc5/fs/yaffs2/yaffs_nand.h--- linux-3.15-rc5.orig/fs/yaffs2/yaffs_nand.h	1970-01-01 01:00:00.000000000 +0100+++ linux-3.15-rc5/fs/yaffs2/yaffs_nand.h	2014-05-17 01:53:27.000000000 +0200@@ -0,0 +1,39 @@+/*+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.+ *+ * Copyright (C) 2002-2011 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_rd_chunk_tags_nand(struct yaffs_dev *dev, int nand_chunk,+			     u8 *buffer, struct yaffs_ext_tags *tags);++int yaffs_wr_chunk_tags_nand(struct yaffs_dev *dev,+			     int nand_chunk,+			     const u8 *buffer, struct yaffs_ext_tags *tags);++int yaffs_mark_bad(struct yaffs_dev *dev, int block_no);++int yaffs_query_init_block_state(struct yaffs_dev *dev,+				 int block_no,+				 enum yaffs_block_state *state,+				 unsigned *seq_number);++int yaffs_erase_block(struct yaffs_dev *dev, int flash_block);++int yaffs_init_nand(struct yaffs_dev *dev);+int yaffs_deinit_nand(struct yaffs_dev *dev);++#endifdiff -Nur linux-3.15-rc5.orig/fs/yaffs2/yaffs_packedtags1.c linux-3.15-rc5/fs/yaffs2/yaffs_packedtags1.c--- linux-3.15-rc5.orig/fs/yaffs2/yaffs_packedtags1.c	1970-01-01 01:00:00.000000000 +0100+++ linux-3.15-rc5/fs/yaffs2/yaffs_packedtags1.c	2014-05-17 01:53:27.000000000 +0200@@ -0,0 +1,56 @@+/*+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.+ *+ * Copyright (C) 2002-2011 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"++static const u8 all_ff[20] = {+	0xff, 0xff, 0xff, 0xff,+	0xff, 0xff, 0xff, 0xff,+	0xff, 0xff, 0xff, 0xff,+	0xff, 0xff, 0xff, 0xff,+	0xff, 0xff, 0xff, 0xff+};++void yaffs_pack_tags1(struct yaffs_packed_tags1 *pt,+		      const struct yaffs_ext_tags *t)+{+	pt->chunk_id = t->chunk_id;+	pt->serial_number = t->serial_number;+	pt->n_bytes = t->n_bytes;+	pt->obj_id = t->obj_id;+	pt->ecc = 0;+	pt->deleted = (t->is_deleted) ? 0 : 1;+	pt->unused_stuff = 0;+	pt->should_be_ff = 0xffffffff;+}++void yaffs_unpack_tags1(struct yaffs_ext_tags *t,+			const struct yaffs_packed_tags1 *pt)+{++	if (memcmp(all_ff, pt, sizeof(struct yaffs_packed_tags1))) {+		t->block_bad = 0;+		if (pt->should_be_ff != 0xffffffff)+			t->block_bad = 1;+		t->chunk_used = 1;+		t->obj_id = pt->obj_id;+		t->chunk_id = pt->chunk_id;+		t->n_bytes = pt->n_bytes;+		t->ecc_result = YAFFS_ECC_RESULT_NO_ERROR;+		t->is_deleted = (pt->deleted) ? 0 : 1;+		t->serial_number = pt->serial_number;+	} else {+		memset(t, 0, sizeof(struct yaffs_ext_tags));+	}+}diff -Nur linux-3.15-rc5.orig/fs/yaffs2/yaffs_packedtags1.h linux-3.15-rc5/fs/yaffs2/yaffs_packedtags1.h--- linux-3.15-rc5.orig/fs/yaffs2/yaffs_packedtags1.h	1970-01-01 01:00:00.000000000 +0100+++ linux-3.15-rc5/fs/yaffs2/yaffs_packedtags1.h	2014-05-17 01:53:27.000000000 +0200@@ -0,0 +1,39 @@+/*+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.+ *+ * Copyright (C) 2002-2011 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"++struct yaffs_packed_tags1 {+	u32 chunk_id:20;+	u32 serial_number:2;+	u32 n_bytes:10;+	u32 obj_id:18;+	u32 ecc:12;+	u32 deleted:1;+	u32 unused_stuff:1;+	unsigned should_be_ff;++};++void yaffs_pack_tags1(struct yaffs_packed_tags1 *pt,+		      const struct yaffs_ext_tags *t);+void yaffs_unpack_tags1(struct yaffs_ext_tags *t,+			const struct yaffs_packed_tags1 *pt);+#endifdiff -Nur linux-3.15-rc5.orig/fs/yaffs2/yaffs_packedtags2.c linux-3.15-rc5/fs/yaffs2/yaffs_packedtags2.c--- linux-3.15-rc5.orig/fs/yaffs2/yaffs_packedtags2.c	1970-01-01 01:00:00.000000000 +0100+++ linux-3.15-rc5/fs/yaffs2/yaffs_packedtags2.c	2014-05-17 01:53:27.000000000 +0200@@ -0,0 +1,197 @@+/*+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.+ *+ * Copyright (C) 2002-2011 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_trace.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 chunk_id */++#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_dump_packed_tags2_tags_only(+				const struct yaffs_packed_tags2_tags_only *ptt)+{+	yaffs_trace(YAFFS_TRACE_MTD,+		"packed tags obj %d chunk %d byte %d seq %d",+		ptt->obj_id, ptt->chunk_id, ptt->n_bytes, ptt->seq_number);+}++static void yaffs_dump_packed_tags2(const struct yaffs_packed_tags2 *pt)+{+	yaffs_dump_packed_tags2_tags_only(&pt->t);+}++static void yaffs_dump_tags2(const struct yaffs_ext_tags *t)+{+	yaffs_trace(YAFFS_TRACE_MTD,+		"ext.tags eccres %d blkbad %d chused %d obj %d chunk%d byte %d del %d ser %d seq %d",+		t->ecc_result, t->block_bad, t->chunk_used, t->obj_id,+		t->chunk_id, t->n_bytes, t->is_deleted, t->serial_number,+		t->seq_number);++}++static int yaffs_check_tags_extra_packable(const struct yaffs_ext_tags *t)+{+	if (t->chunk_id != 0 || !t->extra_available)+		return 0;++	/* Check if the file size is too long to store */+	if (t->extra_obj_type == YAFFS_OBJECT_TYPE_FILE &&+	    (t->extra_file_size >> 31) != 0)+		return 0;+	return 1;+}++void yaffs_pack_tags2_tags_only(struct yaffs_packed_tags2_tags_only *ptt,+				const struct yaffs_ext_tags *t)+{+	ptt->chunk_id = t->chunk_id;+	ptt->seq_number = t->seq_number;+	ptt->n_bytes = t->n_bytes;+	ptt->obj_id = t->obj_id;++	/* Only store extra tags for object headers.+	 * If it is a file then only store  if the file size is short\+	 * enough to fit.+	 */+	if (yaffs_check_tags_extra_packable(t)) {+		/* Store the extra header info instead */+		/* We save the parent object in the chunk_id */+		ptt->chunk_id = EXTRA_HEADER_INFO_FLAG | t->extra_parent_id;+		if (t->extra_is_shrink)+			ptt->chunk_id |= EXTRA_SHRINK_FLAG;+		if (t->extra_shadows)+			ptt->chunk_id |= EXTRA_SHADOWS_FLAG;++		ptt->obj_id &= ~EXTRA_OBJECT_TYPE_MASK;+		ptt->obj_id |= (t->extra_obj_type << EXTRA_OBJECT_TYPE_SHIFT);++		if (t->extra_obj_type == YAFFS_OBJECT_TYPE_HARDLINK)+			ptt->n_bytes = t->extra_equiv_id;+		else if (t->extra_obj_type == YAFFS_OBJECT_TYPE_FILE)+			ptt->n_bytes = (unsigned) t->extra_file_size;+		else+			ptt->n_bytes = 0;+	}++	yaffs_dump_packed_tags2_tags_only(ptt);+	yaffs_dump_tags2(t);+}++void yaffs_pack_tags2(struct yaffs_packed_tags2 *pt,+		      const struct yaffs_ext_tags *t, int tags_ecc)+{+	yaffs_pack_tags2_tags_only(&pt->t, t);++	if (tags_ecc)+		yaffs_ecc_calc_other((unsigned char *)&pt->t,+				    sizeof(struct yaffs_packed_tags2_tags_only),+				    &pt->ecc);+}++void yaffs_unpack_tags2_tags_only(struct yaffs_ext_tags *t,+				  struct yaffs_packed_tags2_tags_only *ptt)+{+	memset(t, 0, sizeof(struct yaffs_ext_tags));++	if (ptt->seq_number == 0xffffffff)+		return;++	t->block_bad = 0;+	t->chunk_used = 1;+	t->obj_id = ptt->obj_id;+	t->chunk_id = ptt->chunk_id;+	t->n_bytes = ptt->n_bytes;+	t->is_deleted = 0;+	t->serial_number = 0;+	t->seq_number = ptt->seq_number;++	/* Do extra header info stuff */+	if (ptt->chunk_id & EXTRA_HEADER_INFO_FLAG) {+		t->chunk_id = 0;+		t->n_bytes = 0;++		t->extra_available = 1;+		t->extra_parent_id = ptt->chunk_id & (~(ALL_EXTRA_FLAGS));+		t->extra_is_shrink = ptt->chunk_id & EXTRA_SHRINK_FLAG ? 1 : 0;+		t->extra_shadows = ptt->chunk_id & EXTRA_SHADOWS_FLAG ? 1 : 0;+		t->extra_obj_type = ptt->obj_id >> EXTRA_OBJECT_TYPE_SHIFT;+		t->obj_id &= ~EXTRA_OBJECT_TYPE_MASK;++		if (t->extra_obj_type == YAFFS_OBJECT_TYPE_HARDLINK)+			t->extra_equiv_id = ptt->n_bytes;+		else+			t->extra_file_size = ptt->n_bytes;+	}+	yaffs_dump_packed_tags2_tags_only(ptt);+	yaffs_dump_tags2(t);+}++void yaffs_unpack_tags2(struct yaffs_ext_tags *t, struct yaffs_packed_tags2 *pt,+			int tags_ecc)+{+	enum yaffs_ecc_result ecc_result = YAFFS_ECC_RESULT_NO_ERROR;++	if (pt->t.seq_number != 0xffffffff && tags_ecc) {+		/* Chunk is in use and we need to do ECC */++		struct yaffs_ecc_other ecc;+		int result;+		yaffs_ecc_calc_other((unsigned char *)&pt->t,+				sizeof(struct yaffs_packed_tags2_tags_only),+				&ecc);+		result =+		    yaffs_ecc_correct_other((unsigned char *)&pt->t,+				sizeof(struct yaffs_packed_tags2_tags_only),+				&pt->ecc, &ecc);+		switch (result) {+		case 0:+			ecc_result = YAFFS_ECC_RESULT_NO_ERROR;+			break;+		case 1:+			ecc_result = YAFFS_ECC_RESULT_FIXED;+			break;+		case -1:+			ecc_result = YAFFS_ECC_RESULT_UNFIXED;+			break;+		default:+			ecc_result = YAFFS_ECC_RESULT_UNKNOWN;+		}+	}+	yaffs_unpack_tags2_tags_only(t, &pt->t);++	t->ecc_result = ecc_result;++	yaffs_dump_packed_tags2(pt);+	yaffs_dump_tags2(t);+}diff -Nur linux-3.15-rc5.orig/fs/yaffs2/yaffs_packedtags2.h linux-3.15-rc5/fs/yaffs2/yaffs_packedtags2.h--- linux-3.15-rc5.orig/fs/yaffs2/yaffs_packedtags2.h	1970-01-01 01:00:00.000000000 +0100+++ linux-3.15-rc5/fs/yaffs2/yaffs_packedtags2.h	2014-05-17 01:53:27.000000000 +0200@@ -0,0 +1,47 @@+/*+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.+ *+ * Copyright (C) 2002-2011 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"++struct yaffs_packed_tags2_tags_only {+	unsigned seq_number;+	unsigned obj_id;+	unsigned chunk_id;+	unsigned n_bytes;+};++struct yaffs_packed_tags2 {+	struct yaffs_packed_tags2_tags_only t;+	struct yaffs_ecc_other ecc;+};++/* Full packed tags with ECC, used for oob tags */+void yaffs_pack_tags2(struct yaffs_packed_tags2 *pt,+		      const struct yaffs_ext_tags *t, int tags_ecc);+void yaffs_unpack_tags2(struct yaffs_ext_tags *t, struct yaffs_packed_tags2 *pt,+			int tags_ecc);++/* Only the tags part (no ECC for use with inband tags */+void yaffs_pack_tags2_tags_only(struct yaffs_packed_tags2_tags_only *pt,+				const struct yaffs_ext_tags *t);+void yaffs_unpack_tags2_tags_only(struct yaffs_ext_tags *t,+				  struct yaffs_packed_tags2_tags_only *pt);+#endifdiff -Nur linux-3.15-rc5.orig/fs/yaffs2/yaffs_summary.c linux-3.15-rc5/fs/yaffs2/yaffs_summary.c--- linux-3.15-rc5.orig/fs/yaffs2/yaffs_summary.c	1970-01-01 01:00:00.000000000 +0100+++ linux-3.15-rc5/fs/yaffs2/yaffs_summary.c	2014-05-17 01:53:27.000000000 +0200@@ -0,0 +1,312 @@+/*+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.+ *+ * Copyright (C) 2002-2011 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.+ */++/* Summaries write the useful part of the tags for the chunks in a block into an+ * an array which is written to the last n chunks of the block.+ * Reading the summaries gives all the tags for the block in one read. Much+ * faster.+ *+ * Chunks holding summaries are marked with tags making it look like+ * they are part of a fake file.+ *+ * The summary could also be used during gc.+ *+ */++#include "yaffs_summary.h"+#include "yaffs_packedtags2.h"+#include "yaffs_nand.h"+#include "yaffs_getblockinfo.h"+#include "yaffs_bitmap.h"++/*+ * The summary is built up in an array of summary tags.+ * This gets written to the last one or two (maybe more) chunks in a block.+ * A summary header is written as the first part of each chunk of summary data.+ * The summary header must match or the summary is rejected.+ */++/* Summary tags don't need the sequence number because that is redundant. */+struct yaffs_summary_tags {+	unsigned obj_id;+	unsigned chunk_id;+	unsigned n_bytes;+};++/* Summary header */+struct yaffs_summary_header {+	unsigned version;	/* Must match current version */+	unsigned block;		/* Must be this block */+	unsigned seq;		/* Must be this sequence number */+	unsigned sum;		/* Just add up all the bytes in the tags */+};+++static void yaffs_summary_clear(struct yaffs_dev *dev)+{+	if (!dev->sum_tags)+		return;+	memset(dev->sum_tags, 0, dev->chunks_per_summary *+		sizeof(struct yaffs_summary_tags));+}+++void yaffs_summary_deinit(struct yaffs_dev *dev)+{+	kfree(dev->sum_tags);+	dev->sum_tags = NULL;+	kfree(dev->gc_sum_tags);+	dev->gc_sum_tags = NULL;+	dev->chunks_per_summary = 0;+}++int yaffs_summary_init(struct yaffs_dev *dev)+{+	int sum_bytes;+	int chunks_used; /* Number of chunks used by summary */+	int sum_tags_bytes;++	sum_bytes = dev->param.chunks_per_block *+			sizeof(struct yaffs_summary_tags);++	chunks_used = (sum_bytes + dev->data_bytes_per_chunk - 1)/+			(dev->data_bytes_per_chunk -+				sizeof(struct yaffs_summary_header));++	dev->chunks_per_summary = dev->param.chunks_per_block - chunks_used;+	sum_tags_bytes = sizeof(struct yaffs_summary_tags) *+				dev->chunks_per_summary;+	dev->sum_tags = kmalloc(sum_tags_bytes, GFP_NOFS);+	dev->gc_sum_tags = kmalloc(sum_tags_bytes, GFP_NOFS);+	if (!dev->sum_tags || !dev->gc_sum_tags) {+		yaffs_summary_deinit(dev);+		return YAFFS_FAIL;+	}++	yaffs_summary_clear(dev);++	return YAFFS_OK;+}++static unsigned yaffs_summary_sum(struct yaffs_dev *dev)+{+	u8 *sum_buffer = (u8 *)dev->sum_tags;+	int i;+	unsigned sum = 0;++	i = sizeof(struct yaffs_summary_tags) *+				dev->chunks_per_summary;+	while (i > 0) {+		sum += *sum_buffer;+		sum_buffer++;+		i--;+	}++	return sum;+}++static int yaffs_summary_write(struct yaffs_dev *dev, int blk)+{+	struct yaffs_ext_tags tags;+	u8 *buffer;+	u8 *sum_buffer = (u8 *)dev->sum_tags;+	int n_bytes;+	int chunk_in_nand;+	int chunk_in_block;+	int result;+	int this_tx;+	struct yaffs_summary_header hdr;+	int sum_bytes_per_chunk = dev->data_bytes_per_chunk - sizeof(hdr);+	struct yaffs_block_info *bi = yaffs_get_block_info(dev, blk);++	buffer = yaffs_get_temp_buffer(dev);+	n_bytes = sizeof(struct yaffs_summary_tags) *+				dev->chunks_per_summary;+	memset(&tags, 0, sizeof(struct yaffs_ext_tags));+	tags.obj_id = YAFFS_OBJECTID_SUMMARY;+	tags.chunk_id = 1;+	chunk_in_block = dev->chunks_per_summary;+	chunk_in_nand = dev->alloc_block * dev->param.chunks_per_block ++						dev->chunks_per_summary;+	hdr.version = YAFFS_SUMMARY_VERSION;+	hdr.block = blk;+	hdr.seq = bi->seq_number;+	hdr.sum = yaffs_summary_sum(dev);++	do {+		this_tx = n_bytes;+		if (this_tx > sum_bytes_per_chunk)+			this_tx = sum_bytes_per_chunk;+		memcpy(buffer, &hdr, sizeof(hdr));+		memcpy(buffer + sizeof(hdr), sum_buffer, this_tx);+		tags.n_bytes = this_tx + sizeof(hdr);+		result = yaffs_wr_chunk_tags_nand(dev, chunk_in_nand,+						buffer, &tags);++		if (result != YAFFS_OK)+			break;+		yaffs_set_chunk_bit(dev, blk, chunk_in_block);+		bi->pages_in_use++;+		dev->n_free_chunks--;++		n_bytes -= this_tx;+		sum_buffer += this_tx;+		chunk_in_nand++;+		chunk_in_block++;+		tags.chunk_id++;+	} while (result == YAFFS_OK && n_bytes > 0);+	yaffs_release_temp_buffer(dev, buffer);+++	if (result == YAFFS_OK)+		bi->has_summary = 1;+++	return result;+}++int yaffs_summary_read(struct yaffs_dev *dev,+			struct yaffs_summary_tags *st,+			int blk)+{+	struct yaffs_ext_tags tags;+	u8 *buffer;+	u8 *sum_buffer = (u8 *)st;+	int n_bytes;+	int chunk_id;+	int chunk_in_nand;+	int chunk_in_block;+	int result;+	int this_tx;+	struct yaffs_summary_header hdr;+	struct yaffs_block_info *bi = yaffs_get_block_info(dev, blk);+	int sum_bytes_per_chunk = dev->data_bytes_per_chunk - sizeof(hdr);+	int sum_tags_bytes;++	sum_tags_bytes = sizeof(struct yaffs_summary_tags) *+				dev->chunks_per_summary;+	buffer = yaffs_get_temp_buffer(dev);+	n_bytes = sizeof(struct yaffs_summary_tags) * dev->chunks_per_summary;+	chunk_in_block = dev->chunks_per_summary;+	chunk_in_nand = blk * dev->param.chunks_per_block ++							dev->chunks_per_summary;+	chunk_id = 1;+	do {+		this_tx = n_bytes;+		if (this_tx > sum_bytes_per_chunk)+			this_tx = sum_bytes_per_chunk;+		result = yaffs_rd_chunk_tags_nand(dev, chunk_in_nand,+						buffer, &tags);++		if (tags.chunk_id != chunk_id ||+			tags.obj_id != YAFFS_OBJECTID_SUMMARY ||+			tags.chunk_used == 0 ||+			tags.ecc_result > YAFFS_ECC_RESULT_FIXED ||+			tags.n_bytes != (this_tx + sizeof(hdr)))+				result = YAFFS_FAIL;+		if (result != YAFFS_OK)+			break;++		if (st == dev->sum_tags) {+			/* If we're scanning then update the block info */+			yaffs_set_chunk_bit(dev, blk, chunk_in_block);+			bi->pages_in_use++;+		}+		memcpy(&hdr, buffer, sizeof(hdr));+		memcpy(sum_buffer, buffer + sizeof(hdr), this_tx);+		n_bytes -= this_tx;+		sum_buffer += this_tx;+		chunk_in_nand++;+		chunk_in_block++;+		chunk_id++;+	} while (result == YAFFS_OK && n_bytes > 0);+	yaffs_release_temp_buffer(dev, buffer);++	if (result == YAFFS_OK) {+		/* Verify header */+		if (hdr.version != YAFFS_SUMMARY_VERSION ||+		    hdr.seq != bi->seq_number ||+		    hdr.sum != yaffs_summary_sum(dev))+			result = YAFFS_FAIL;+	}++	if (st == dev->sum_tags && result == YAFFS_OK)+		bi->has_summary = 1;++	return result;+}++int yaffs_summary_add(struct yaffs_dev *dev,+			struct yaffs_ext_tags *tags,+			int chunk_in_nand)+{+	struct yaffs_packed_tags2_tags_only tags_only;+	struct yaffs_summary_tags *sum_tags;+	int block_in_nand = chunk_in_nand / dev->param.chunks_per_block;+	int chunk_in_block = chunk_in_nand % dev->param.chunks_per_block;++	if (!dev->sum_tags)+		return YAFFS_OK;++	if (chunk_in_block >= 0 && chunk_in_block < dev->chunks_per_summary) {+		yaffs_pack_tags2_tags_only(&tags_only, tags);+		sum_tags = &dev->sum_tags[chunk_in_block];+		sum_tags->chunk_id = tags_only.chunk_id;+		sum_tags->n_bytes = tags_only.n_bytes;+		sum_tags->obj_id = tags_only.obj_id;++		if (chunk_in_block == dev->chunks_per_summary - 1) {+			/* Time to write out the summary */+			yaffs_summary_write(dev, block_in_nand);+			yaffs_summary_clear(dev);+			yaffs_skip_rest_of_block(dev);+		}+	}+	return YAFFS_OK;+}++int yaffs_summary_fetch(struct yaffs_dev *dev,+			struct yaffs_ext_tags *tags,+			int chunk_in_block)+{+	struct yaffs_packed_tags2_tags_only tags_only;+	struct yaffs_summary_tags *sum_tags;+	if (chunk_in_block >= 0 && chunk_in_block < dev->chunks_per_summary) {+		sum_tags = &dev->sum_tags[chunk_in_block];+		tags_only.chunk_id = sum_tags->chunk_id;+		tags_only.n_bytes = sum_tags->n_bytes;+		tags_only.obj_id = sum_tags->obj_id;+		yaffs_unpack_tags2_tags_only(tags, &tags_only);+		return YAFFS_OK;+	}+	return YAFFS_FAIL;+}++void yaffs_summary_gc(struct yaffs_dev *dev, int blk)+{+	struct yaffs_block_info *bi = yaffs_get_block_info(dev, blk);+	int i;++	if (!bi->has_summary)+		return;++	for (i = dev->chunks_per_summary;+	     i < dev->param.chunks_per_block;+	     i++) {+		if (yaffs_check_chunk_bit(dev, blk, i)) {+			yaffs_clear_chunk_bit(dev, blk, i);+			bi->pages_in_use--;+			dev->n_free_chunks++;+		}+	}+}diff -Nur linux-3.15-rc5.orig/fs/yaffs2/yaffs_summary.h linux-3.15-rc5/fs/yaffs2/yaffs_summary.h--- linux-3.15-rc5.orig/fs/yaffs2/yaffs_summary.h	1970-01-01 01:00:00.000000000 +0100+++ linux-3.15-rc5/fs/yaffs2/yaffs_summary.h	2014-05-17 01:53:27.000000000 +0200@@ -0,0 +1,37 @@+/*+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.+ *+ * Copyright (C) 2002-2011 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_SUMMARY_H__+#define __YAFFS_SUMMARY_H__++#include "yaffs_packedtags2.h"+++int yaffs_summary_init(struct yaffs_dev *dev);+void yaffs_summary_deinit(struct yaffs_dev *dev);++int yaffs_summary_add(struct yaffs_dev *dev,+			struct yaffs_ext_tags *tags,+			int chunk_in_block);+int yaffs_summary_fetch(struct yaffs_dev *dev,+			struct yaffs_ext_tags *tags,+			int chunk_in_block);+int yaffs_summary_read(struct yaffs_dev *dev,+			struct yaffs_summary_tags *st,+			int blk);+void yaffs_summary_gc(struct yaffs_dev *dev, int blk);+++#endifdiff -Nur linux-3.15-rc5.orig/fs/yaffs2/yaffs_tagscompat.c linux-3.15-rc5/fs/yaffs2/yaffs_tagscompat.c--- linux-3.15-rc5.orig/fs/yaffs2/yaffs_tagscompat.c	1970-01-01 01:00:00.000000000 +0100+++ linux-3.15-rc5/fs/yaffs2/yaffs_tagscompat.c	2014-05-17 01:53:27.000000000 +0200@@ -0,0 +1,381 @@+/*+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.+ *+ * Copyright (C) 2002-2011 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"+#include "yaffs_trace.h"++static void yaffs_handle_rd_data_error(struct yaffs_dev *dev, int nand_chunk);+++/********** Tags ECC calculations  *********/+++void yaffs_calc_tags_ecc(struct yaffs_tags *tags)+{+	/* Calculate an ecc */+	unsigned char *b = ((union yaffs_tags_union *)tags)->as_bytes;+	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_check_tags_ecc(struct yaffs_tags *tags)+{+	unsigned ecc = tags->ecc;++	yaffs_calc_tags_ecc(tags);++	ecc ^= tags->ecc;++	if (ecc && ecc <= 64) {+		/* TODO: Handle the failure better. Retire? */+		unsigned char *b = ((union yaffs_tags_union *)tags)->as_bytes;++		ecc--;++		b[ecc / 8] ^= (1 << (ecc & 7));++		/* Now recvalc the ecc */+		yaffs_calc_tags_ecc(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_load_tags_to_spare(struct yaffs_spare *spare_ptr,+				     struct yaffs_tags *tags_ptr)+{+	union yaffs_tags_union *tu = (union yaffs_tags_union *)tags_ptr;++	yaffs_calc_tags_ecc(tags_ptr);++	spare_ptr->tb0 = tu->as_bytes[0];+	spare_ptr->tb1 = tu->as_bytes[1];+	spare_ptr->tb2 = tu->as_bytes[2];+	spare_ptr->tb3 = tu->as_bytes[3];+	spare_ptr->tb4 = tu->as_bytes[4];+	spare_ptr->tb5 = tu->as_bytes[5];+	spare_ptr->tb6 = tu->as_bytes[6];+	spare_ptr->tb7 = tu->as_bytes[7];+}++static void yaffs_get_tags_from_spare(struct yaffs_dev *dev,+				      struct yaffs_spare *spare_ptr,+				      struct yaffs_tags *tags_ptr)+{+	union yaffs_tags_union *tu = (union yaffs_tags_union *)tags_ptr;+	int result;++	tu->as_bytes[0] = spare_ptr->tb0;+	tu->as_bytes[1] = spare_ptr->tb1;+	tu->as_bytes[2] = spare_ptr->tb2;+	tu->as_bytes[3] = spare_ptr->tb3;+	tu->as_bytes[4] = spare_ptr->tb4;+	tu->as_bytes[5] = spare_ptr->tb5;+	tu->as_bytes[6] = spare_ptr->tb6;+	tu->as_bytes[7] = spare_ptr->tb7;++	result = yaffs_check_tags_ecc(tags_ptr);+	if (result > 0)+		dev->n_tags_ecc_fixed++;+	else if (result < 0)+		dev->n_tags_ecc_unfixed++;+}++static void yaffs_spare_init(struct yaffs_spare *spare)+{+	memset(spare, 0xff, sizeof(struct yaffs_spare));+}++static int yaffs_wr_nand(struct yaffs_dev *dev,+			 int nand_chunk, const u8 *data,+			 struct yaffs_spare *spare)+{+	int data_size = dev->data_bytes_per_chunk;++	return dev->drv.drv_write_chunk_fn(dev, nand_chunk,+				data, data_size,+				(u8 *) spare, sizeof(*spare));+}++static int yaffs_rd_chunk_nand(struct yaffs_dev *dev,+			       int nand_chunk,+			       u8 *data,+			       struct yaffs_spare *spare,+			       enum yaffs_ecc_result *ecc_result,+			       int correct_errors)+{+	int ret_val;+	struct yaffs_spare local_spare;+	int data_size;+	int spare_size;+	int ecc_result1, ecc_result2;+	u8 calc_ecc[3];++	if (!spare) {+		/* If we don't have a real spare, then we use a local one. */+		/* Need this for the calculation of the ecc */+		spare = &local_spare;+	}+	data_size = dev->data_bytes_per_chunk;+	spare_size = sizeof(struct yaffs_spare);++	if (dev->param.use_nand_ecc)+		return dev->drv.drv_read_chunk_fn(dev, nand_chunk,+						data, data_size,+						(u8 *) spare, spare_size,+						ecc_result);+++	/* Handle the ECC at this level. */++	ret_val = dev->drv.drv_read_chunk_fn(dev, nand_chunk,+						 data, data_size,+						 (u8 *)spare, spare_size,+						NULL);+	if (!data || !correct_errors)+		return ret_val;++	/* Do ECC correction if needed. */+	yaffs_ecc_calc(data, calc_ecc);+	ecc_result1 = yaffs_ecc_correct(data, spare->ecc1, calc_ecc);+	yaffs_ecc_calc(&data[256], calc_ecc);+	ecc_result2 = yaffs_ecc_correct(&data[256], spare->ecc2, calc_ecc);++	if (ecc_result1 > 0) {+		yaffs_trace(YAFFS_TRACE_ERROR,+			"**>>yaffs ecc error fix performed on chunk %d:0",+			nand_chunk);+		dev->n_ecc_fixed++;+	} else if (ecc_result1 < 0) {+		yaffs_trace(YAFFS_TRACE_ERROR,+			"**>>yaffs ecc error unfixed on chunk %d:0",+			nand_chunk);+		dev->n_ecc_unfixed++;+	}++	if (ecc_result2 > 0) {+		yaffs_trace(YAFFS_TRACE_ERROR,+			"**>>yaffs ecc error fix performed on chunk %d:1",+			nand_chunk);+		dev->n_ecc_fixed++;+	} else if (ecc_result2 < 0) {+		yaffs_trace(YAFFS_TRACE_ERROR,+			"**>>yaffs ecc error unfixed on chunk %d:1",+			nand_chunk);+		dev->n_ecc_unfixed++;+	}++	if (ecc_result1 || ecc_result2) {+		/* We had a data problem on this page */+		yaffs_handle_rd_data_error(dev, nand_chunk);+	}++	if (ecc_result1 < 0 || ecc_result2 < 0)+		*ecc_result = YAFFS_ECC_RESULT_UNFIXED;+	else if (ecc_result1 > 0 || ecc_result2 > 0)+		*ecc_result = YAFFS_ECC_RESULT_FIXED;+	else+		*ecc_result = YAFFS_ECC_RESULT_NO_ERROR;++	return ret_val;+}++/*+ * Functions for robustisizing+ */++static void yaffs_handle_rd_data_error(struct yaffs_dev *dev, int nand_chunk)+{+	int flash_block = nand_chunk / dev->param.chunks_per_block;++	/* Mark the block for retirement */+	yaffs_get_block_info(dev, flash_block + dev->block_offset)->+		needs_retiring = 1;+	yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,+		"**>>Block %d marked for retirement",+		flash_block);++	/* TODO:+	 * Just do a garbage collection on the affected block+	 * then retire the block+	 * NB recursion+	 */+}++static int yaffs_tags_compat_wr(struct yaffs_dev *dev,+			 int nand_chunk,+			 const u8 *data, const struct yaffs_ext_tags *ext_tags)+{+	struct yaffs_spare spare;+	struct yaffs_tags tags;++	yaffs_spare_init(&spare);++	if (ext_tags->is_deleted)+		spare.page_status = 0;+	else {+		tags.obj_id = ext_tags->obj_id;+		tags.chunk_id = ext_tags->chunk_id;++		tags.n_bytes_lsb = ext_tags->n_bytes & (1024 - 1);++		if (dev->data_bytes_per_chunk >= 1024)+			tags.n_bytes_msb = (ext_tags->n_bytes >> 10) & 3;+		else+			tags.n_bytes_msb = 3;++		tags.serial_number = ext_tags->serial_number;++		if (!dev->param.use_nand_ecc && data) {+			yaffs_ecc_calc(data, spare.ecc1);+			yaffs_ecc_calc(&data[256], spare.ecc2);+		}++		yaffs_load_tags_to_spare(&spare, &tags);+	}+	return yaffs_wr_nand(dev, nand_chunk, data, &spare);+}++static int yaffs_tags_compat_rd(struct yaffs_dev *dev,+			 int nand_chunk,+			 u8 *data, struct yaffs_ext_tags *ext_tags)+{+	struct yaffs_spare spare;+	struct yaffs_tags tags;+	enum yaffs_ecc_result ecc_result = YAFFS_ECC_RESULT_UNKNOWN;+	static struct yaffs_spare spare_ff;+	static int init;+	int deleted;++	if (!init) {+		memset(&spare_ff, 0xff, sizeof(spare_ff));+		init = 1;+	}++	if (!yaffs_rd_chunk_nand(dev, nand_chunk,+					data, &spare, &ecc_result, 1))+		return YAFFS_FAIL;++	/* ext_tags may be NULL */+	if (!ext_tags)+		return YAFFS_OK;++	deleted = (hweight8(spare.page_status) < 7) ? 1 : 0;++	ext_tags->is_deleted = deleted;+	ext_tags->ecc_result = ecc_result;+	ext_tags->block_bad = 0;	/* We're reading it */+	/* therefore it is not a bad block */+	ext_tags->chunk_used =+		memcmp(&spare_ff, &spare, sizeof(spare_ff)) ? 1 : 0;++	if (ext_tags->chunk_used) {+		yaffs_get_tags_from_spare(dev, &spare, &tags);+		ext_tags->obj_id = tags.obj_id;+		ext_tags->chunk_id = tags.chunk_id;+		ext_tags->n_bytes = tags.n_bytes_lsb;++		if (dev->data_bytes_per_chunk >= 1024)+			ext_tags->n_bytes |=+				(((unsigned)tags.n_bytes_msb) << 10);++		ext_tags->serial_number = tags.serial_number;+	}++	return YAFFS_OK;+}++static int yaffs_tags_compat_mark_bad(struct yaffs_dev *dev, int flash_block)+{+	struct yaffs_spare spare;++	memset(&spare, 0xff, sizeof(struct yaffs_spare));++	spare.block_status = 'Y';++	yaffs_wr_nand(dev, flash_block * dev->param.chunks_per_block, NULL,+		      &spare);+	yaffs_wr_nand(dev, flash_block * dev->param.chunks_per_block + 1,+		      NULL, &spare);++	return YAFFS_OK;+}++static int yaffs_tags_compat_query_block(struct yaffs_dev *dev,+				  int block_no,+				  enum yaffs_block_state *state,+				  u32 *seq_number)+{+	struct yaffs_spare spare0, spare1;+	static struct yaffs_spare spare_ff;+	static int init;+	enum yaffs_ecc_result dummy;++	if (!init) {+		memset(&spare_ff, 0xff, sizeof(spare_ff));+		init = 1;+	}++	*seq_number = 0;++	/* Look for bad block markers in the first two chunks */+	yaffs_rd_chunk_nand(dev, block_no * dev->param.chunks_per_block,+			    NULL, &spare0, &dummy, 0);+	yaffs_rd_chunk_nand(dev, block_no * dev->param.chunks_per_block + 1,+			    NULL, &spare1, &dummy, 0);++	if (hweight8(spare0.block_status & spare1.block_status) < 7)+		*state = YAFFS_BLOCK_STATE_DEAD;+	else if (memcmp(&spare_ff, &spare0, sizeof(spare_ff)) == 0)+		*state = YAFFS_BLOCK_STATE_EMPTY;+	else+		*state = YAFFS_BLOCK_STATE_NEEDS_SCAN;++	return YAFFS_OK;+}++void yaffs_tags_compat_install(struct yaffs_dev *dev)+{+	if(dev->param.is_yaffs2)+		return;+	if(!dev->tagger.write_chunk_tags_fn)+		dev->tagger.write_chunk_tags_fn = yaffs_tags_compat_wr;+	if(!dev->tagger.read_chunk_tags_fn)+		dev->tagger.read_chunk_tags_fn = yaffs_tags_compat_rd;+	if(!dev->tagger.query_block_fn)+		dev->tagger.query_block_fn = yaffs_tags_compat_query_block;+	if(!dev->tagger.mark_bad_fn)+		dev->tagger.mark_bad_fn = yaffs_tags_compat_mark_bad;+}diff -Nur linux-3.15-rc5.orig/fs/yaffs2/yaffs_tagscompat.h linux-3.15-rc5/fs/yaffs2/yaffs_tagscompat.h--- linux-3.15-rc5.orig/fs/yaffs2/yaffs_tagscompat.h	1970-01-01 01:00:00.000000000 +0100+++ linux-3.15-rc5/fs/yaffs2/yaffs_tagscompat.h	2014-05-17 01:53:27.000000000 +0200@@ -0,0 +1,44 @@+/*+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.+ *+ * Copyright (C) 2002-2011 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"++#if 0+++int yaffs_tags_compat_wr(struct yaffs_dev *dev,+			 int nand_chunk,+			 const u8 *data, const struct yaffs_ext_tags *tags);+int yaffs_tags_compat_rd(struct yaffs_dev *dev,+			 int nand_chunk,+			 u8 *data, struct yaffs_ext_tags *tags);+int yaffs_tags_compat_mark_bad(struct yaffs_dev *dev, int block_no);+int yaffs_tags_compat_query_block(struct yaffs_dev *dev,+				  int block_no,+				  enum yaffs_block_state *state,+				  u32 *seq_number);++#endif+++void yaffs_tags_compat_install(struct yaffs_dev *dev);+void yaffs_calc_tags_ecc(struct yaffs_tags *tags);+int yaffs_check_tags_ecc(struct yaffs_tags *tags);++#endifdiff -Nur linux-3.15-rc5.orig/fs/yaffs2/yaffs_tagsmarshall.c linux-3.15-rc5/fs/yaffs2/yaffs_tagsmarshall.c--- linux-3.15-rc5.orig/fs/yaffs2/yaffs_tagsmarshall.c	1970-01-01 01:00:00.000000000 +0100+++ linux-3.15-rc5/fs/yaffs2/yaffs_tagsmarshall.c	2014-05-17 01:53:27.000000000 +0200@@ -0,0 +1,199 @@+/*+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.+ *+ * Copyright (C) 2002-2011 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_trace.h"+#include "yaffs_packedtags2.h"++static int yaffs_tags_marshall_write(struct yaffs_dev *dev,+				    int nand_chunk, const u8 *data,+				    const struct yaffs_ext_tags *tags)+{+	struct yaffs_packed_tags2 pt;+	int retval;++	int packed_tags_size =+	    dev->param.no_tags_ecc ? sizeof(pt.t) : sizeof(pt);+	void *packed_tags_ptr =+	    dev->param.no_tags_ecc ? (void *)&pt.t : (void *)&pt;++	yaffs_trace(YAFFS_TRACE_MTD,+		"yaffs_tags_marshall_write chunk %d data %p tags %p",+		nand_chunk, data, tags);++	/* 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->param.inband_tags) {+		struct yaffs_packed_tags2_tags_only *pt2tp;+		pt2tp =+		    (struct yaffs_packed_tags2_tags_only *)(data ++							dev->+							data_bytes_per_chunk);+		yaffs_pack_tags2_tags_only(pt2tp, tags);+	} else {+		yaffs_pack_tags2(&pt, tags, !dev->param.no_tags_ecc);+	}++	retval = dev->drv.drv_write_chunk_fn(dev, nand_chunk,+			data, dev->param.total_bytes_per_chunk,+			(dev->param.inband_tags) ? NULL : packed_tags_ptr,+			(dev->param.inband_tags) ? 0 : packed_tags_size);++	return retval;+}++static int yaffs_tags_marshall_read(struct yaffs_dev *dev,+				   int nand_chunk, u8 *data,+				   struct yaffs_ext_tags *tags)+{+	int retval = 0;+	int local_data = 0;+	u8 spare_buffer[100];+	enum yaffs_ecc_result ecc_result;++	struct yaffs_packed_tags2 pt;++	int packed_tags_size =+	    dev->param.no_tags_ecc ? sizeof(pt.t) : sizeof(pt);+	void *packed_tags_ptr =+	    dev->param.no_tags_ecc ? (void *)&pt.t : (void *)&pt;++	yaffs_trace(YAFFS_TRACE_MTD,+		"yaffs_tags_marshall_read chunk %d data %p tags %p",+		nand_chunk, data, tags);++	if (dev->param.inband_tags) {+		if (!data) {+			local_data = 1;+			data = yaffs_get_temp_buffer(dev);+		}+	}++	if (dev->param.inband_tags || (data && !tags))+		retval = dev->drv.drv_read_chunk_fn(dev, nand_chunk,+					data, dev->param.total_bytes_per_chunk,+					NULL, 0,+					&ecc_result);+	else if (tags)+		retval = dev->drv.drv_read_chunk_fn(dev, nand_chunk,+					data, dev->param.total_bytes_per_chunk,+					spare_buffer, packed_tags_size,+					&ecc_result);+	else+		BUG();+++	if (dev->param.inband_tags) {+		if (tags) {+			struct yaffs_packed_tags2_tags_only *pt2tp;+			pt2tp =+				(struct yaffs_packed_tags2_tags_only *)+				&data[dev->data_bytes_per_chunk];+			yaffs_unpack_tags2_tags_only(tags, pt2tp);+		}+	} else if (tags) {+		memcpy(packed_tags_ptr, spare_buffer, packed_tags_size);+		yaffs_unpack_tags2(tags, &pt, !dev->param.no_tags_ecc);+	}++	if (local_data)+		yaffs_release_temp_buffer(dev, data);++	if (tags && ecc_result == YAFFS_ECC_RESULT_UNFIXED) {+		tags->ecc_result = YAFFS_ECC_RESULT_UNFIXED;+		dev->n_ecc_unfixed++;+	}++	if (tags && ecc_result == -YAFFS_ECC_RESULT_FIXED) {+		if (tags->ecc_result <= YAFFS_ECC_RESULT_NO_ERROR)+			tags->ecc_result = YAFFS_ECC_RESULT_FIXED;+		dev->n_ecc_fixed++;+	}++	if (ecc_result < YAFFS_ECC_RESULT_UNFIXED)+		return YAFFS_OK;+	else+		return YAFFS_FAIL;+}++static int yaffs_tags_marshall_query_block(struct yaffs_dev *dev, int block_no,+			       enum yaffs_block_state *state,+			       u32 *seq_number)+{+	int retval;++	yaffs_trace(YAFFS_TRACE_MTD, "yaffs_tags_marshall_query_block %d",+			block_no);++	retval = dev->drv.drv_check_bad_fn(dev, block_no);++	if (retval== YAFFS_FAIL) {+		yaffs_trace(YAFFS_TRACE_MTD, "block is bad");++		*state = YAFFS_BLOCK_STATE_DEAD;+		*seq_number = 0;+	} else {+		struct yaffs_ext_tags t;++		yaffs_tags_marshall_read(dev,+				    block_no * dev->param.chunks_per_block,+				    NULL, &t);++		if (t.chunk_used) {+			*seq_number = t.seq_number;+			*state = YAFFS_BLOCK_STATE_NEEDS_SCAN;+		} else {+			*seq_number = 0;+			*state = YAFFS_BLOCK_STATE_EMPTY;+		}+	}++	yaffs_trace(YAFFS_TRACE_MTD,+		"block query returns  seq %d state %d",+		*seq_number, *state);++	if (retval == 0)+		return YAFFS_OK;+	else+		return YAFFS_FAIL;+}++static int yaffs_tags_marshall_mark_bad(struct yaffs_dev *dev, int block_no)+{+	return dev->drv.drv_mark_bad_fn(dev, block_no);++}+++void yaffs_tags_marshall_install(struct yaffs_dev *dev)+{+	if (!dev->param.is_yaffs2)+		return;++	if (!dev->tagger.write_chunk_tags_fn)+		dev->tagger.write_chunk_tags_fn = yaffs_tags_marshall_write;++	if (!dev->tagger.read_chunk_tags_fn)+		dev->tagger.read_chunk_tags_fn = yaffs_tags_marshall_read;++	if (!dev->tagger.query_block_fn)+		dev->tagger.query_block_fn = yaffs_tags_marshall_query_block;++	if (!dev->tagger.mark_bad_fn)+		dev->tagger.mark_bad_fn = yaffs_tags_marshall_mark_bad;++}diff -Nur linux-3.15-rc5.orig/fs/yaffs2/yaffs_tagsmarshall.h linux-3.15-rc5/fs/yaffs2/yaffs_tagsmarshall.h--- linux-3.15-rc5.orig/fs/yaffs2/yaffs_tagsmarshall.h	1970-01-01 01:00:00.000000000 +0100+++ linux-3.15-rc5/fs/yaffs2/yaffs_tagsmarshall.h	2014-05-17 01:53:27.000000000 +0200@@ -0,0 +1,22 @@+/*+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.+ *+ * Copyright (C) 2002-2011 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_TAGSMARSHALL_H__+#define __YAFFS_TAGSMARSHALL_H__++#include "yaffs_guts.h"+void yaffs_tags_marshall_install(struct yaffs_dev *dev);++#endifdiff -Nur linux-3.15-rc5.orig/fs/yaffs2/yaffs_trace.h linux-3.15-rc5/fs/yaffs2/yaffs_trace.h--- linux-3.15-rc5.orig/fs/yaffs2/yaffs_trace.h	1970-01-01 01:00:00.000000000 +0100+++ linux-3.15-rc5/fs/yaffs2/yaffs_trace.h	2014-05-17 01:53:27.000000000 +0200@@ -0,0 +1,57 @@+/*+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.+ *+ * Copyright (C) 2002-2011 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 __YTRACE_H__+#define __YTRACE_H__++extern unsigned int yaffs_trace_mask;+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_SYNC		0x00100000+#define YAFFS_TRACE_BACKGROUND		0x00200000+#define YAFFS_TRACE_LOCK		0x00400000+#define YAFFS_TRACE_MOUNT		0x00800000++#define YAFFS_TRACE_ERROR		0x40000000+#define YAFFS_TRACE_BUG			0x80000000+#define YAFFS_TRACE_ALWAYS		0xf0000000++#endifdiff -Nur linux-3.15-rc5.orig/fs/yaffs2/yaffs_verify.c linux-3.15-rc5/fs/yaffs2/yaffs_verify.c--- linux-3.15-rc5.orig/fs/yaffs2/yaffs_verify.c	1970-01-01 01:00:00.000000000 +0100+++ linux-3.15-rc5/fs/yaffs2/yaffs_verify.c	2014-05-17 01:53:27.000000000 +0200@@ -0,0 +1,529 @@+/*+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.+ *+ * Copyright (C) 2002-2011 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_verify.h"+#include "yaffs_trace.h"+#include "yaffs_bitmap.h"+#include "yaffs_getblockinfo.h"+#include "yaffs_nand.h"++int yaffs_skip_verification(struct yaffs_dev *dev)+{+	(void) dev;+	return !(yaffs_trace_mask &+		 (YAFFS_TRACE_VERIFY | YAFFS_TRACE_VERIFY_FULL));+}++static int yaffs_skip_full_verification(struct yaffs_dev *dev)+{+	(void) dev;+	return !(yaffs_trace_mask & (YAFFS_TRACE_VERIFY_FULL));+}++static int yaffs_skip_nand_verification(struct yaffs_dev *dev)+{+	(void) dev;+	return !(yaffs_trace_mask & (YAFFS_TRACE_VERIFY_NAND));+}++static const char * const block_state_name[] = {+	"Unknown",+	"Needs scan",+	"Scanning",+	"Empty",+	"Allocating",+	"Full",+	"Dirty",+	"Checkpoint",+	"Collecting",+	"Dead"+};++void yaffs_verify_blk(struct yaffs_dev *dev, struct yaffs_block_info *bi, int n)+{+	int actually_used;+	int in_use;++	if (yaffs_skip_verification(dev))+		return;++	/* Report illegal runtime states */+	if (bi->block_state >= YAFFS_NUMBER_OF_BLOCK_STATES)+		yaffs_trace(YAFFS_TRACE_VERIFY,+			"Block %d has undefined state %d",+			n, bi->block_state);++	switch (bi->block_state) {+	case YAFFS_BLOCK_STATE_UNKNOWN:+	case YAFFS_BLOCK_STATE_SCANNING:+	case YAFFS_BLOCK_STATE_NEEDS_SCAN:+		yaffs_trace(YAFFS_TRACE_VERIFY,+			"Block %d has bad run-state %s",+			n, block_state_name[bi->block_state]);+	}++	/* Check pages in use and soft deletions are legal */++	actually_used = bi->pages_in_use - bi->soft_del_pages;++	if (bi->pages_in_use < 0 ||+	    bi->pages_in_use > dev->param.chunks_per_block ||+	    bi->soft_del_pages < 0 ||+	    bi->soft_del_pages > dev->param.chunks_per_block ||+	    actually_used < 0 || actually_used > dev->param.chunks_per_block)+		yaffs_trace(YAFFS_TRACE_VERIFY,+			"Block %d has illegal values pages_in_used %d soft_del_pages %d",+			n, bi->pages_in_use, bi->soft_del_pages);++	/* Check chunk bitmap legal */+	in_use = yaffs_count_chunk_bits(dev, n);+	if (in_use != bi->pages_in_use)+		yaffs_trace(YAFFS_TRACE_VERIFY,+			"Block %d has inconsistent values pages_in_use %d counted chunk bits %d",+			n, bi->pages_in_use, in_use);+}++void yaffs_verify_collected_blk(struct yaffs_dev *dev,+				struct yaffs_block_info *bi, int n)+{+	yaffs_verify_blk(dev, bi, n);++	/* After collection the block should be in the erased state */++	if (bi->block_state != YAFFS_BLOCK_STATE_COLLECTING &&+	    bi->block_state != YAFFS_BLOCK_STATE_EMPTY) {+		yaffs_trace(YAFFS_TRACE_ERROR,+			"Block %d is in state %d after gc, should be erased",+			n, bi->block_state);+	}+}++void yaffs_verify_blocks(struct yaffs_dev *dev)+{+	int i;+	int state_count[YAFFS_NUMBER_OF_BLOCK_STATES];+	int illegal_states = 0;++	if (yaffs_skip_verification(dev))+		return;++	memset(state_count, 0, sizeof(state_count));++	for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {+		struct yaffs_block_info *bi = yaffs_get_block_info(dev, i);+		yaffs_verify_blk(dev, bi, i);++		if (bi->block_state < YAFFS_NUMBER_OF_BLOCK_STATES)+			state_count[bi->block_state]++;+		else+			illegal_states++;+	}++	yaffs_trace(YAFFS_TRACE_VERIFY,	"Block summary");++	yaffs_trace(YAFFS_TRACE_VERIFY,+		"%d blocks have illegal states",+		illegal_states);+	if (state_count[YAFFS_BLOCK_STATE_ALLOCATING] > 1)+		yaffs_trace(YAFFS_TRACE_VERIFY,+			"Too many allocating blocks");++	for (i = 0; i < YAFFS_NUMBER_OF_BLOCK_STATES; i++)+		yaffs_trace(YAFFS_TRACE_VERIFY,+			"%s %d blocks",+			block_state_name[i], state_count[i]);++	if (dev->blocks_in_checkpt != state_count[YAFFS_BLOCK_STATE_CHECKPOINT])+		yaffs_trace(YAFFS_TRACE_VERIFY,+			"Checkpoint block count wrong dev %d count %d",+			dev->blocks_in_checkpt,+			state_count[YAFFS_BLOCK_STATE_CHECKPOINT]);++	if (dev->n_erased_blocks != state_count[YAFFS_BLOCK_STATE_EMPTY])+		yaffs_trace(YAFFS_TRACE_VERIFY,+			"Erased block count wrong dev %d count %d",+			dev->n_erased_blocks,+			state_count[YAFFS_BLOCK_STATE_EMPTY]);++	if (state_count[YAFFS_BLOCK_STATE_COLLECTING] > 1)+		yaffs_trace(YAFFS_TRACE_VERIFY,+			"Too many collecting blocks %d (max is 1)",+			state_count[YAFFS_BLOCK_STATE_COLLECTING]);+}++/*+ * Verify the object header. oh must be valid, but obj and tags may be NULL in+ * which case those tests will not be performed.+ */+void yaffs_verify_oh(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh,+		     struct yaffs_ext_tags *tags, int parent_check)+{+	if (obj && yaffs_skip_verification(obj->my_dev))+		return;++	if (!(tags && obj && oh)) {+		yaffs_trace(YAFFS_TRACE_VERIFY,+			"Verifying object header tags %p obj %p oh %p",+			tags, obj, oh);+		return;+	}++	if (oh->type <= YAFFS_OBJECT_TYPE_UNKNOWN ||+	    oh->type > YAFFS_OBJECT_TYPE_MAX)+		yaffs_trace(YAFFS_TRACE_VERIFY,+			"Obj %d header type is illegal value 0x%x",+			tags->obj_id, oh->type);++	if (tags->obj_id != obj->obj_id)+		yaffs_trace(YAFFS_TRACE_VERIFY,+			"Obj %d header mismatch obj_id %d",+			tags->obj_id, obj->obj_id);++	/*+	 * Check that the object's parent ids match if parent_check requested.+	 *+	 * Tests do not apply to the root object.+	 */++	if (parent_check && tags->obj_id > 1 && !obj->parent)+		yaffs_trace(YAFFS_TRACE_VERIFY,+			"Obj %d header mismatch parent_id %d obj->parent is NULL",+			tags->obj_id, oh->parent_obj_id);++	if (parent_check && obj->parent &&+	    oh->parent_obj_id != obj->parent->obj_id &&+	    (oh->parent_obj_id != YAFFS_OBJECTID_UNLINKED ||+	     obj->parent->obj_id != YAFFS_OBJECTID_DELETED))+		yaffs_trace(YAFFS_TRACE_VERIFY,+			"Obj %d header mismatch parent_id %d parent_obj_id %d",+			tags->obj_id, oh->parent_obj_id,+			obj->parent->obj_id);++	if (tags->obj_id > 1 && oh->name[0] == 0)	/* Null name */+		yaffs_trace(YAFFS_TRACE_VERIFY,+			"Obj %d header name is NULL",+			obj->obj_id);++	if (tags->obj_id > 1 && ((u8) (oh->name[0])) == 0xff)	/* Junk name */+		yaffs_trace(YAFFS_TRACE_VERIFY,+			"Obj %d header name is 0xff",+			obj->obj_id);+}++void yaffs_verify_file(struct yaffs_obj *obj)+{+	u32 x;+	int required_depth;+	int actual_depth;+	int last_chunk;+	u32 offset_in_chunk;+	u32 the_chunk;++	u32 i;+	struct yaffs_dev *dev;+	struct yaffs_ext_tags tags;+	struct yaffs_tnode *tn;+	u32 obj_id;++	if (!obj)+		return;++	if (yaffs_skip_verification(obj->my_dev))+		return;++	dev = obj->my_dev;+	obj_id = obj->obj_id;+++	/* Check file size is consistent with tnode depth */+	yaffs_addr_to_chunk(dev, obj->variant.file_variant.file_size,+				&last_chunk, &offset_in_chunk);+	last_chunk++;+	x = last_chunk >> YAFFS_TNODES_LEVEL0_BITS;+	required_depth = 0;+	while (x > 0) {+		x >>= YAFFS_TNODES_INTERNAL_BITS;+		required_depth++;+	}++	actual_depth = obj->variant.file_variant.top_level;++	/* 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_skip_nand_verification(dev))+		return;++	for (i = 1; i <= last_chunk; i++) {+		tn = yaffs_find_tnode_0(dev, &obj->variant.file_variant, i);++		if (!tn)+			continue;++		the_chunk = yaffs_get_group_base(dev, tn, i);+		if (the_chunk > 0) {+			yaffs_rd_chunk_tags_nand(dev, the_chunk, NULL,+						 &tags);+			if (tags.obj_id != obj_id || tags.chunk_id != i)+				yaffs_trace(YAFFS_TRACE_VERIFY,+					"Object %d chunk_id %d NAND mismatch chunk %d tags (%d:%d)",+					obj_id, i, the_chunk,+					tags.obj_id, tags.chunk_id);+		}+	}+}++void yaffs_verify_link(struct yaffs_obj *obj)+{+	if (obj && yaffs_skip_verification(obj->my_dev))+		return;++	/* Verify sane equivalent object */+}++void yaffs_verify_symlink(struct yaffs_obj *obj)+{+	if (obj && yaffs_skip_verification(obj->my_dev))+		return;++	/* Verify symlink string */+}++void yaffs_verify_special(struct yaffs_obj *obj)+{+	if (obj && yaffs_skip_verification(obj->my_dev))+		return;+}++void yaffs_verify_obj(struct yaffs_obj *obj)+{+	struct yaffs_dev *dev;+	u32 chunk_min;+	u32 chunk_max;+	u32 chunk_id_ok;+	u32 chunk_in_range;+	u32 chunk_wrongly_deleted;+	u32 chunk_valid;++	if (!obj)+		return;++	if (obj->being_created)+		return;++	dev = obj->my_dev;++	if (yaffs_skip_verification(dev))+		return;++	/* Check sane object header chunk */++	chunk_min = dev->internal_start_block * dev->param.chunks_per_block;+	chunk_max =+	    (dev->internal_end_block + 1) * dev->param.chunks_per_block - 1;++	chunk_in_range = (((unsigned)(obj->hdr_chunk)) >= chunk_min &&+			  ((unsigned)(obj->hdr_chunk)) <= chunk_max);+	chunk_id_ok = chunk_in_range || (obj->hdr_chunk == 0);+	chunk_valid = chunk_in_range &&+	    yaffs_check_chunk_bit(dev,+				  obj->hdr_chunk / dev->param.chunks_per_block,+				  obj->hdr_chunk % dev->param.chunks_per_block);+	chunk_wrongly_deleted = chunk_in_range && !chunk_valid;++	if (!obj->fake && (!chunk_id_ok || chunk_wrongly_deleted))+		yaffs_trace(YAFFS_TRACE_VERIFY,+			"Obj %d has chunk_id %d %s %s",+			obj->obj_id, obj->hdr_chunk,+			chunk_id_ok ? "" : ",out of range",+			chunk_wrongly_deleted ? ",marked as deleted" : "");++	if (chunk_valid && !yaffs_skip_nand_verification(dev)) {+		struct yaffs_ext_tags tags;+		struct yaffs_obj_hdr *oh;+		u8 *buffer = yaffs_get_temp_buffer(dev);++		oh = (struct yaffs_obj_hdr *)buffer;++		yaffs_rd_chunk_tags_nand(dev, obj->hdr_chunk, buffer, &tags);++		yaffs_verify_oh(obj, oh, &tags, 1);++		yaffs_release_temp_buffer(dev, buffer);+	}++	/* Verify it has a parent */+	if (obj && !obj->fake && (!obj->parent || obj->parent->my_dev != dev)) {+		yaffs_trace(YAFFS_TRACE_VERIFY,+			"Obj %d has parent pointer %p which does not look like an object",+			obj->obj_id, obj->parent);+	}++	/* Verify parent is a directory */+	if (obj->parent &&+	    obj->parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {+		yaffs_trace(YAFFS_TRACE_VERIFY,+			"Obj %d's parent is not a directory (type %d)",+			obj->obj_id, obj->parent->variant_type);+	}++	switch (obj->variant_type) {+	case YAFFS_OBJECT_TYPE_FILE:+		yaffs_verify_file(obj);+		break;+	case YAFFS_OBJECT_TYPE_SYMLINK:+		yaffs_verify_symlink(obj);+		break;+	case YAFFS_OBJECT_TYPE_DIRECTORY:+		yaffs_verify_dir(obj);+		break;+	case YAFFS_OBJECT_TYPE_HARDLINK:+		yaffs_verify_link(obj);+		break;+	case YAFFS_OBJECT_TYPE_SPECIAL:+		yaffs_verify_special(obj);+		break;+	case YAFFS_OBJECT_TYPE_UNKNOWN:+	default:+		yaffs_trace(YAFFS_TRACE_VERIFY,+			"Obj %d has illegaltype %d",+		   obj->obj_id, obj->variant_type);+		break;+	}+}++void yaffs_verify_objects(struct yaffs_dev *dev)+{+	struct yaffs_obj *obj;+	int i;+	struct list_head *lh;++	if (yaffs_skip_verification(dev))+		return;++	/* Iterate through the objects in each hash entry */++	for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {+		list_for_each(lh, &dev->obj_bucket[i].list) {+			obj = list_entry(lh, struct yaffs_obj, hash_link);+			yaffs_verify_obj(obj);+		}+	}+}++void yaffs_verify_obj_in_dir(struct yaffs_obj *obj)+{+	struct list_head *lh;+	struct yaffs_obj *list_obj;+	int count = 0;++	if (!obj) {+		yaffs_trace(YAFFS_TRACE_ALWAYS, "No object to verify");+		BUG();+		return;+	}++	if (yaffs_skip_verification(obj->my_dev))+		return;++	if (!obj->parent) {+		yaffs_trace(YAFFS_TRACE_ALWAYS, "Object does not have parent");+		BUG();+		return;+	}++	if (obj->parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {+		yaffs_trace(YAFFS_TRACE_ALWAYS, "Parent is not directory");+		BUG();+	}++	/* Iterate through the objects in each hash entry */++	list_for_each(lh, &obj->parent->variant.dir_variant.children) {+		list_obj = list_entry(lh, struct yaffs_obj, siblings);+		yaffs_verify_obj(list_obj);+		if (obj == list_obj)+			count++;+	}++	if (count != 1) {+		yaffs_trace(YAFFS_TRACE_ALWAYS,+			"Object in directory %d times",+			count);+		BUG();+	}+}++void yaffs_verify_dir(struct yaffs_obj *directory)+{+	struct list_head *lh;+	struct yaffs_obj *list_obj;++	if (!directory) {+		BUG();+		return;+	}++	if (yaffs_skip_full_verification(directory->my_dev))+		return;++	if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {+		yaffs_trace(YAFFS_TRACE_ALWAYS,+			"Directory has wrong type: %d",+			directory->variant_type);+		BUG();+	}++	/* Iterate through the objects in each hash entry */++	list_for_each(lh, &directory->variant.dir_variant.children) {+		list_obj = list_entry(lh, struct yaffs_obj, siblings);+		if (list_obj->parent != directory) {+			yaffs_trace(YAFFS_TRACE_ALWAYS,+				"Object in directory list has wrong parent %p",+				list_obj->parent);+			BUG();+		}+		yaffs_verify_obj_in_dir(list_obj);+	}+}++static int yaffs_free_verification_failures;++void yaffs_verify_free_chunks(struct yaffs_dev *dev)+{+	int counted;+	int difference;++	if (yaffs_skip_verification(dev))+		return;++	counted = yaffs_count_free_chunks(dev);++	difference = dev->n_free_chunks - counted;++	if (difference) {+		yaffs_trace(YAFFS_TRACE_ALWAYS,+			"Freechunks verification failure %d %d %d",+			dev->n_free_chunks, counted, difference);+		yaffs_free_verification_failures++;+	}+}++int yaffs_verify_file_sane(struct yaffs_obj *in)+{+	(void) in;+	return YAFFS_OK;+}diff -Nur linux-3.15-rc5.orig/fs/yaffs2/yaffs_verify.h linux-3.15-rc5/fs/yaffs2/yaffs_verify.h--- linux-3.15-rc5.orig/fs/yaffs2/yaffs_verify.h	1970-01-01 01:00:00.000000000 +0100+++ linux-3.15-rc5/fs/yaffs2/yaffs_verify.h	2014-05-17 01:53:27.000000000 +0200@@ -0,0 +1,43 @@+/*+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.+ *+ * Copyright (C) 2002-2011 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_VERIFY_H__+#define __YAFFS_VERIFY_H__++#include "yaffs_guts.h"++void yaffs_verify_blk(struct yaffs_dev *dev, struct yaffs_block_info *bi,+		      int n);+void yaffs_verify_collected_blk(struct yaffs_dev *dev,+				struct yaffs_block_info *bi, int n);+void yaffs_verify_blocks(struct yaffs_dev *dev);++void yaffs_verify_oh(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh,+		     struct yaffs_ext_tags *tags, int parent_check);+void yaffs_verify_file(struct yaffs_obj *obj);+void yaffs_verify_link(struct yaffs_obj *obj);+void yaffs_verify_symlink(struct yaffs_obj *obj);+void yaffs_verify_special(struct yaffs_obj *obj);+void yaffs_verify_obj(struct yaffs_obj *obj);+void yaffs_verify_objects(struct yaffs_dev *dev);+void yaffs_verify_obj_in_dir(struct yaffs_obj *obj);+void yaffs_verify_dir(struct yaffs_obj *directory);+void yaffs_verify_free_chunks(struct yaffs_dev *dev);++int yaffs_verify_file_sane(struct yaffs_obj *obj);++int yaffs_skip_verification(struct yaffs_dev *dev);++#endifdiff -Nur linux-3.15-rc5.orig/fs/yaffs2/yaffs_vfs.c linux-3.15-rc5/fs/yaffs2/yaffs_vfs.c--- linux-3.15-rc5.orig/fs/yaffs2/yaffs_vfs.c	1970-01-01 01:00:00.000000000 +0100+++ linux-3.15-rc5/fs/yaffs2/yaffs_vfs.c	2014-05-17 02:52:54.000000000 +0200@@ -0,0 +1,3604 @@+/*+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.+ *+ * Copyright (C) 2002-2011 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 struct yaffs_dev associated with+ *         this superblock+ * >> 2.6: sb->s_fs_info  points to the struct yaffs_dev associated with this+ *         superblock+ * >> inode->u.generic_ip points to the associated struct yaffs_obj.+ */++/*+ * There are two variants of the VFS glue code. This variant should compile+ * for any version of Linux.+ */+#include <linux/version.h>++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10))+#define YAFFS_COMPILE_BACKGROUND+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23))+#define YAFFS_COMPILE_FREEZER+#endif+#endif++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28))+#define YAFFS_COMPILE_EXPORTFS+#endif++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 35))+#define YAFFS_USE_SETATTR_COPY+#define YAFFS_USE_TRUNCATE_SETSIZE+#endif+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 35))+#define YAFFS_HAS_EVICT_INODE+#endif++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))+#define YAFFS_NEW_FOLLOW_LINK 1+#else+#define YAFFS_NEW_FOLLOW_LINK 0+#endif++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0))+#define YAFFS_HAS_WRITE_SUPER+#endif+++#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>+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39))+#include <linux/smp_lock.h>+#endif+#include <linux/pagemap.h>+#include <linux/mtd/mtd.h>+#include <linux/interrupt.h>+#include <linux/string.h>+#include <linux/ctype.h>++#if (YAFFS_NEW_FOLLOW_LINK == 1)+#include <linux/namei.h>+#endif++#ifdef YAFFS_COMPILE_EXPORTFS+#include <linux/exportfs.h>+#endif++#ifdef YAFFS_COMPILE_BACKGROUND+#include <linux/kthread.h>+#include <linux/delay.h>+#endif+#ifdef YAFFS_COMPILE_FREEZER+#include <linux/freezer.h>+#endif++#include <asm/div64.h>++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))++#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, 26))+#define Y_INIT_TIMER(a)	init_timer(a)+#else+#define Y_INIT_TIMER(a)	init_timer_on_stack(a)+#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(3, 6, 0))+#define YAFFS_SUPER_HAS_DIRTY+#endif+++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0))+#define set_nlink(inode, count)  do { (inode)->i_nlink = (count); } while(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 <linux/mtd/mtd.h>++#include "yportenv.h"+#include "yaffs_trace.h"+#include "yaffs_guts.h"+#include "yaffs_attribs.h"++#include "yaffs_linux.h"++#include "yaffs_mtdif.h"+#include "yaffs_packedtags2.h"+#include "yaffs_getblockinfo.h"++unsigned int yaffs_trace_mask =+		YAFFS_TRACE_BAD_BLOCKS |+		YAFFS_TRACE_ALWAYS |+		0;++unsigned int yaffs_wr_attempts = YAFFS_WR_ATTEMPTS;+unsigned int yaffs_auto_checkpoint = 1;+unsigned int yaffs_gc_control = 1;+unsigned int yaffs_bg_enable = 1;+unsigned int yaffs_auto_select = 1;+/* Module Parameters */+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))+module_param(yaffs_trace_mask, uint, 0644);+module_param(yaffs_wr_attempts, uint, 0644);+module_param(yaffs_auto_checkpoint, uint, 0644);+module_param(yaffs_gc_control, uint, 0644);+module_param(yaffs_bg_enable, uint, 0644);+#else+MODULE_PARM(yaffs_trace_mask, "i");+MODULE_PARM(yaffs_wr_attempts, "i");+MODULE_PARM(yaffs_auto_checkpoint, "i");+MODULE_PARM(yaffs_gc_control, "i");+#endif++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25))+/* use iget and read_inode */+#define Y_IGET(sb, inum) iget((sb), (inum))++#else+/* Call local equivalent */+#define YAFFS_USE_OWN_IGET+#define Y_IGET(sb, inum) yaffs_iget((sb), (inum))++#endif++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18))+#define yaffs_inode_to_obj_lv(iptr) ((iptr)->i_private)+#else+#define yaffs_inode_to_obj_lv(iptr) ((iptr)->u.generic_ip)+#endif++#define yaffs_inode_to_obj(iptr) \+	((struct yaffs_obj *)(yaffs_inode_to_obj_lv(iptr)))+#define yaffs_dentry_to_obj(dptr) yaffs_inode_to_obj((dptr)->d_inode)++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))+#define yaffs_super_to_dev(sb)	((struct yaffs_dev *)sb->s_fs_info)+#else+#define yaffs_super_to_dev(sb)	((struct yaffs_dev *)sb->u.generic_sbp)+#endif++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))+#define Y_CLEAR_INODE(i) clear_inode(i)+#else+#define Y_CLEAR_INODE(i) end_writeback(i)+#endif+++#define update_dir_time(dir) do {\+			(dir)->i_ctime = (dir)->i_mtime = CURRENT_TIME; \+		} while (0)++static void yaffs_fill_inode_from_obj(struct inode *inode,+				      struct yaffs_obj *obj);+++static void yaffs_gross_lock(struct yaffs_dev *dev)+{+	yaffs_trace(YAFFS_TRACE_LOCK, "yaffs locking %p", current);+	mutex_lock(&(yaffs_dev_to_lc(dev)->gross_lock));+	yaffs_trace(YAFFS_TRACE_LOCK, "yaffs locked %p", current);+}++static void yaffs_gross_unlock(struct yaffs_dev *dev)+{+	yaffs_trace(YAFFS_TRACE_LOCK, "yaffs unlocking %p", current);+	mutex_unlock(&(yaffs_dev_to_lc(dev)->gross_lock));+}+++static int yaffs_readpage_nolock(struct file *f, struct page *pg)+{+	/* Lifted from jffs2 */++	struct yaffs_obj *obj;+	unsigned char *pg_buf;+	int ret;+	loff_t pos = ((loff_t) pg->index) << PAGE_CACHE_SHIFT;+	struct yaffs_dev *dev;++	yaffs_trace(YAFFS_TRACE_OS,+		"yaffs_readpage_nolock at %lld, size %08x",+		(long long)pos,+		(unsigned)PAGE_CACHE_SIZE);++	obj = yaffs_dentry_to_obj(f->f_dentry);++	dev = obj->my_dev;++#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_gross_lock(dev);++	ret = yaffs_file_rd(obj, pg_buf, pos, PAGE_CACHE_SIZE);++	yaffs_gross_unlock(dev);++	if (ret >= 0)+		ret = 0;++	if (ret) {+		ClearPageUptodate(pg);+		SetPageError(pg);+	} else {+		SetPageUptodate(pg);+		ClearPageError(pg);+	}++	flush_dcache_page(pg);+	kunmap(pg);++	yaffs_trace(YAFFS_TRACE_OS, "yaffs_readpage_nolock done");+	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)+{+	int ret;++	yaffs_trace(YAFFS_TRACE_OS, "yaffs_readpage");+	ret = yaffs_readpage_unlock(f, pg);+	yaffs_trace(YAFFS_TRACE_OS, "yaffs_readpage done");+	return ret;+}++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))+#define YCRED_FSUID()	from_kuid(&init_user_ns, current_fsuid())+#define YCRED_FSGID()	from_kgid(&init_user_ns, current_fsgid())+#else+#define YCRED_FSUID()	YCRED(current)->fsuid+#define YCRED_FSGID()	YCRED(current)->fsgid++static inline uid_t i_uid_read(const struct inode *inode)+{+	return inode->i_uid;+}++static inline gid_t i_gid_read(const struct inode *inode)+{+	return inode->i_gid;+}++static inline void i_uid_write(struct inode *inode, uid_t uid)+{+	inode->i_uid = uid;+}++static inline void i_gid_write(struct inode *inode, gid_t gid)+{+	inode->i_gid = gid;+}+#endif++static void yaffs_set_super_dirty_val(struct yaffs_dev *dev, int val)+{+	struct yaffs_linux_context *lc = yaffs_dev_to_lc(dev);++	if (lc)+		lc->dirty = val;++# ifdef YAFFS_SUPER_HAS_DIRTY+	{+		struct super_block *sb = lc->super;++		if (sb)+			sb->s_dirt = val;+	}+#endif++}++static void yaffs_set_super_dirty(struct yaffs_dev *dev)+{+	yaffs_set_super_dirty_val(dev, 1);+}++static void yaffs_clear_super_dirty(struct yaffs_dev *dev)+{+	yaffs_set_super_dirty_val(dev, 0);+}++static int yaffs_check_super_dirty(struct yaffs_dev *dev)+{+	struct yaffs_linux_context *lc = yaffs_dev_to_lc(dev);++	if (lc && lc->dirty)+		return 1;++# ifdef YAFFS_SUPER_HAS_DIRTY+	{+		struct super_block *sb = lc->super;++		if (sb && sb->s_dirt)+			return 1;+	}+#endif+	return 0;++}++#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 yaffs_dev *dev;+	struct address_space *mapping = page->mapping;+	struct inode *inode;+	unsigned long end_index;+	char *buffer;+	struct yaffs_obj *obj;+	int n_written = 0;+	unsigned n_bytes;+	loff_t i_size;++	if (!mapping)+		BUG();+	inode = mapping->host;+	if (!inode)+		BUG();+	i_size = i_size_read(inode);++	end_index = i_size >> PAGE_CACHE_SHIFT;++	if (page->index < end_index)+		n_bytes = PAGE_CACHE_SIZE;+	else {+		n_bytes = i_size & (PAGE_CACHE_SIZE - 1);++		if (page->index > end_index || !n_bytes) {+			yaffs_trace(YAFFS_TRACE_OS,+				"yaffs_writepage at %lld, inode size = %lld!!",+				((loff_t)page->index) << PAGE_CACHE_SHIFT,+				inode->i_size);+			yaffs_trace(YAFFS_TRACE_OS,+				"                -> don't care!!");++			zero_user_segment(page, 0, PAGE_CACHE_SIZE);+			set_page_writeback(page);+			unlock_page(page);+			end_page_writeback(page);+			return 0;+		}+	}++	if (n_bytes != PAGE_CACHE_SIZE)+		zero_user_segment(page, n_bytes, PAGE_CACHE_SIZE);++	get_page(page);++	buffer = kmap(page);++	obj = yaffs_inode_to_obj(inode);+	dev = obj->my_dev;+	yaffs_gross_lock(dev);++	yaffs_trace(YAFFS_TRACE_OS,+		"yaffs_writepage at %lld, size %08x",+		((loff_t)page->index) << PAGE_CACHE_SHIFT, n_bytes);+	yaffs_trace(YAFFS_TRACE_OS,+		"writepag0: obj = %lld, ino = %lld",+		obj->variant.file_variant.file_size, inode->i_size);++	n_written = yaffs_wr_file(obj, buffer,+				  ((loff_t)page->index) << PAGE_CACHE_SHIFT, n_bytes, 0);++	yaffs_set_super_dirty(dev);++	yaffs_trace(YAFFS_TRACE_OS,+		"writepag1: obj = %lld, ino = %lld",+		obj->variant.file_variant.file_size, inode->i_size);++	yaffs_gross_unlock(dev);++	kunmap(page);+	set_page_writeback(page);+	unlock_page(page);+	end_page_writeback(page);+	put_page(page);++	return (n_written == n_bytes) ? 0 : -ENOSPC;+}++/* 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)+{+	struct yaffs_obj *obj;+	struct yaffs_dev *dev;++	int n_free_chunks;++	obj = yaffs_dentry_to_obj(f->f_dentry);++	dev = obj->my_dev;++	yaffs_gross_lock(dev);++	n_free_chunks = yaffs_get_n_free_chunks(dev);++	yaffs_gross_unlock(dev);++	return (n_free_chunks > 20) ? 1 : 0;+}++static void yaffs_release_space(struct file *f)+{+	struct yaffs_obj *obj;+	struct yaffs_dev *dev;++	obj = yaffs_dentry_to_obj(f->f_dentry);++	dev = obj->my_dev;++	yaffs_gross_lock(dev);++	yaffs_gross_unlock(dev);+}++#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;++	int ret = 0;+	int space_held = 0;++	/* 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;+	}+	yaffs_trace(YAFFS_TRACE_OS,+		"start yaffs_write_begin index %d(%x) uptodate %d",+		(int)index, (int)index, Page_Uptodate(pg) ? 1 : 0);++	/* Get fs space */+	space_held = yaffs_hold_space(filp);++	if (!space_held) {+		ret = -ENOSPC;+		goto out;+	}++	/* Update page if required */++	if (!Page_Uptodate(pg))+		ret = yaffs_readpage_nolock(filp, pg);++	if (ret)+		goto out;++	/* Happy path return */+	yaffs_trace(YAFFS_TRACE_OS, "end yaffs_write_begin - ok");++	return 0;++out:+	yaffs_trace(YAFFS_TRACE_OS,+		"end yaffs_write_begin fail returning %d", 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)+{+	yaffs_trace(YAFFS_TRACE_OS, "yaffs_prepair_write");++	if (!Page_Uptodate(pg))+		return yaffs_readpage_nolock(f, pg);+	return 0;+}+#endif+++static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,+				loff_t * pos)+{+	struct yaffs_obj *obj;+	int n_written;+	loff_t ipos;+	struct inode *inode;+	struct yaffs_dev *dev;++	obj = yaffs_dentry_to_obj(f->f_dentry);++	if (!obj) {+		yaffs_trace(YAFFS_TRACE_OS,+			"yaffs_file_write: hey obj is null!");+                return -EINVAL;+        }++	dev = obj->my_dev;++	yaffs_gross_lock(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;++	yaffs_trace(YAFFS_TRACE_OS,+		"yaffs_file_write about to write writing %u(%x) bytes to object %d at %lld",+		(unsigned)n, (unsigned)n, obj->obj_id, ipos);++	n_written = yaffs_wr_file(obj, buf, ipos, n, 0);++	yaffs_set_super_dirty(dev);++	yaffs_trace(YAFFS_TRACE_OS,+		"yaffs_file_write: %d(%x) bytes written",+		(unsigned)n, (unsigned)n);++	if (n_written > 0) {+		ipos += n_written;+		*pos = ipos;+		if (ipos > inode->i_size) {+			inode->i_size = ipos;+			inode->i_blocks = (ipos + 511) >> 9;++			yaffs_trace(YAFFS_TRACE_OS,+				"yaffs_file_write size updated to %lld bytes, %d blocks",+				ipos, (int)(inode->i_blocks));+		}++	}+	yaffs_gross_unlock(dev);+	return (n_written == 0) && (n > 0) ? -ENOSPC : n_written;+}+++#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;++	yaffs_trace(YAFFS_TRACE_OS,+		"yaffs_write_end addr %p pos %lld n_bytes %d",+		addr, pos, copied);++	ret = yaffs_file_write(filp, addr, copied, &pos);++	if (ret != copied) {+		yaffs_trace(YAFFS_TRACE_OS,+			"yaffs_write_end not same size ret %d  copied %d",+			ret, copied);+		SetPageError(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 n_bytes = to - offset;+	int n_written;++	kva = kmap(pg);+	addr = kva + offset;++	yaffs_trace(YAFFS_TRACE_OS,+		"yaffs_commit_write addr %p pos %lld n_bytes %d",+		addr, pos, n_bytes);++	n_written = yaffs_file_write(f, addr, n_bytes, &pos);++	if (n_written != n_bytes) {+		yaffs_trace(YAFFS_TRACE_OS,+			"yaffs_commit_write not same size n_written %d  n_bytes %d",+			n_written, n_bytes);+		SetPageError(pg);+	}+	kunmap(pg);++	yaffs_trace(YAFFS_TRACE_OS,+		"yaffs_commit_write returning %d",+		n_written == n_bytes ? 0 : n_written);++	return n_written == n_bytes ? 0 : n_written;+}+#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, 17))+static int yaffs_file_flush(struct file *file, fl_owner_t id)+#else+static int yaffs_file_flush(struct file *file)+#endif+{+	struct yaffs_obj *obj = yaffs_dentry_to_obj(file->f_dentry);++	struct yaffs_dev *dev = obj->my_dev;++	yaffs_trace(YAFFS_TRACE_OS,+		"yaffs_file_flush object %d (%s)",+		obj->obj_id,+		obj->dirty ? "dirty" : "clean");++	yaffs_gross_lock(dev);++	yaffs_flush_file(obj, 1, 0);++	yaffs_gross_unlock(dev);++	return 0;+}+++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))+static int yaffs_sync_object(struct file *file, loff_t start, loff_t end, int datasync)+#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34))+static int yaffs_sync_object(struct file *file, int datasync)+#else+static int yaffs_sync_object(struct file *file, struct dentry *dentry,+			     int datasync)+#endif+{+	struct yaffs_obj *obj;+	struct yaffs_dev *dev;+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34))+	struct dentry *dentry = file->f_path.dentry;+#endif++	obj = yaffs_dentry_to_obj(dentry);++	dev = obj->my_dev;++	yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC,+		"yaffs_sync_object");+	yaffs_gross_lock(dev);+	yaffs_flush_file(obj, 1, datasync);+	yaffs_gross_unlock(dev);+	return 0;+}+++#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+++++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25))+static void zero_user_segment(struct page *page, unsigned start, unsigned end)+{+	void *kaddr = kmap_atomic(page, KM_USER0);+	memset(kaddr + start, 0, end - start);+	kunmap_atomic(kaddr, KM_USER0);+	flush_dcache_page(page);+}+#endif+++static int yaffs_vfs_setsize(struct inode *inode, loff_t newsize)+{+#ifdef YAFFS_USE_TRUNCATE_SETSIZE+	truncate_setsize(inode, newsize);+	return 0;+#else+	truncate_inode_pages(&inode->i_data, newsize);+	return 0;+#endif++}+++static int yaffs_vfs_setattr(struct inode *inode, struct iattr *attr)+{+#ifdef YAFFS_USE_SETATTR_COPY+	setattr_copy(inode, attr);+	return 0;+#else+	return inode_setattr(inode, attr);+#endif++}++static int yaffs_setattr(struct dentry *dentry, struct iattr *attr)+{+	struct inode *inode = dentry->d_inode;+	int error = 0;+	struct yaffs_dev *dev;++	yaffs_trace(YAFFS_TRACE_OS,+		"yaffs_setattr of object %d",+		yaffs_inode_to_obj(inode)->obj_id);+#if 0+	/* Fail if a requested resize >= 2GB */+	if (attr->ia_valid & ATTR_SIZE && (attr->ia_size >> 31))+		error = -EINVAL;+#endif++	if (error == 0)+		error = inode_change_ok(inode, attr);+	if (error == 0) {+		int result;+		if (!error) {+			error = yaffs_vfs_setattr(inode, attr);+			yaffs_trace(YAFFS_TRACE_OS, "inode_setattr called");+			if (attr->ia_valid & ATTR_SIZE) {+				yaffs_vfs_setsize(inode, attr->ia_size);+				inode->i_blocks = (inode->i_size + 511) >> 9;+			}+		}+		dev = yaffs_inode_to_obj(inode)->my_dev;+		if (attr->ia_valid & ATTR_SIZE) {+			yaffs_trace(YAFFS_TRACE_OS,+				"resize to %d(%x)",+				(int)(attr->ia_size),+				(int)(attr->ia_size));+		}+		yaffs_gross_lock(dev);+		result = yaffs_set_attribs(yaffs_inode_to_obj(inode), attr);+		if (result == YAFFS_OK) {+			error = 0;+		} else {+			error = -EPERM;+		}+		yaffs_gross_unlock(dev);++	}++	yaffs_trace(YAFFS_TRACE_OS, "yaffs_setattr done returning %d", error);++	return error;+}++static int yaffs_setxattr(struct dentry *dentry, const char *name,+		   const void *value, size_t size, int flags)+{+	struct inode *inode = dentry->d_inode;+	int error = 0;+	struct yaffs_dev *dev;+	struct yaffs_obj *obj = yaffs_inode_to_obj(inode);++	yaffs_trace(YAFFS_TRACE_OS, "yaffs_setxattr of object %d", obj->obj_id);++	if (error == 0) {+		int result;+		dev = obj->my_dev;+		yaffs_gross_lock(dev);+		result = yaffs_set_xattrib(obj, name, value, size, flags);+		if (result == YAFFS_OK)+			error = 0;+		else if (result < 0)+			error = result;+		yaffs_gross_unlock(dev);++	}+	yaffs_trace(YAFFS_TRACE_OS, "yaffs_setxattr done returning %d", error);++	return error;+}++static ssize_t yaffs_getxattr(struct dentry * dentry, const char *name,+			void *buff, size_t size)+{+	struct inode *inode = dentry->d_inode;+	int error = 0;+	struct yaffs_dev *dev;+	struct yaffs_obj *obj = yaffs_inode_to_obj(inode);++	yaffs_trace(YAFFS_TRACE_OS,+		"yaffs_getxattr \"%s\" from object %d",+		name, obj->obj_id);++	if (error == 0) {+		dev = obj->my_dev;+		yaffs_gross_lock(dev);+		error = yaffs_get_xattrib(obj, name, buff, size);+		yaffs_gross_unlock(dev);++	}+	yaffs_trace(YAFFS_TRACE_OS, "yaffs_getxattr done returning %d", error);++	return error;+}++static int yaffs_removexattr(struct dentry *dentry, const char *name)+{+	struct inode *inode = dentry->d_inode;+	int error = 0;+	struct yaffs_dev *dev;+	struct yaffs_obj *obj = yaffs_inode_to_obj(inode);++	yaffs_trace(YAFFS_TRACE_OS,+		"yaffs_removexattr of object %d", obj->obj_id);++	if (error == 0) {+		int result;+		dev = obj->my_dev;+		yaffs_gross_lock(dev);+		result = yaffs_remove_xattrib(obj, name);+		if (result == YAFFS_OK)+			error = 0;+		else if (result < 0)+			error = result;+		yaffs_gross_unlock(dev);++	}+	yaffs_trace(YAFFS_TRACE_OS,+		"yaffs_removexattr done returning %d", error);++	return error;+}++static ssize_t yaffs_listxattr(struct dentry * dentry, char *buff, size_t size)+{+	struct inode *inode = dentry->d_inode;+	int error = 0;+	struct yaffs_dev *dev;+	struct yaffs_obj *obj = yaffs_inode_to_obj(inode);++	yaffs_trace(YAFFS_TRACE_OS,+		"yaffs_listxattr of object %d", obj->obj_id);++	if (error == 0) {+		dev = obj->my_dev;+		yaffs_gross_lock(dev);+		error = yaffs_list_xattrib(obj, buff, size);+		yaffs_gross_unlock(dev);++	}+	yaffs_trace(YAFFS_TRACE_OS,+		"yaffs_listxattr done returning %d", error);++	return error;+}+++static const struct inode_operations yaffs_file_inode_operations = {+	.setattr = yaffs_setattr,+	.setxattr = yaffs_setxattr,+	.getxattr = yaffs_getxattr,+	.listxattr = yaffs_listxattr,+	.removexattr = yaffs_removexattr,+};+++static int yaffs_readlink(struct dentry *dentry, char __user * buffer,+			  int buflen)+{+	unsigned char *alias;+	int ret;++	struct yaffs_dev *dev = yaffs_dentry_to_obj(dentry)->my_dev;++	yaffs_gross_lock(dev);++	alias = yaffs_get_symlink_alias(yaffs_dentry_to_obj(dentry));++	yaffs_gross_unlock(dev);++	if (!alias)+		return -ENOMEM;++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0))+	ret = readlink_copy(buffer, buflen, alias);+#else+	ret = vfs_readlink(dentry, buffer, buflen, alias);+#endif+	kfree(alias);+	return ret;+}++#if (YAFFS_NEW_FOLLOW_LINK == 1)+static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)+{+	void *ret;+#else+static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)+{+	int ret+#endif+	unsigned char *alias;+	int ret_int = 0;+	struct yaffs_dev *dev = yaffs_dentry_to_obj(dentry)->my_dev;++	yaffs_gross_lock(dev);++	alias = yaffs_get_symlink_alias(yaffs_dentry_to_obj(dentry));+	yaffs_gross_unlock(dev);++	if (!alias) {+		ret_int = -ENOMEM;+		goto out;+	}+#if (YAFFS_NEW_FOLLOW_LINK == 1)+	nd_set_link(nd, alias);+	ret = alias;+out:+	if (ret_int)+		ret = ERR_PTR(ret_int);+	return ret;+#else+	ret = vfs_follow_link(nd, alias);+	kfree(alias);+out:+	if (ret_int)+		ret = ret_int;+	return ret;+#endif+}+++#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)+{+	yaffs_trace(YAFFS_TRACE_OS,+		"yaffs_put_inode: ino %d, count %d"),+		(int)inode->i_ino, atomic_read(&inode->i_count);++}+#endif++#if (YAFFS_NEW_FOLLOW_LINK == 1)+void yaffs_put_link(struct dentry *dentry, struct nameidata *nd, void *alias)+{+	kfree(alias);+}+#endif++static const struct inode_operations yaffs_symlink_inode_operations = {+	.readlink = yaffs_readlink,+	.follow_link = yaffs_follow_link,+#if (YAFFS_NEW_FOLLOW_LINK == 1)+	.put_link = yaffs_put_link,+#endif+	.setattr = yaffs_setattr,+	.setxattr = yaffs_setxattr,+	.getxattr = yaffs_getxattr,+	.listxattr = yaffs_listxattr,+	.removexattr = yaffs_removexattr,+};++#ifdef YAFFS_USE_OWN_IGET++static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino)+{+	struct inode *inode;+	struct yaffs_obj *obj;+	struct yaffs_dev *dev = yaffs_super_to_dev(sb);++	yaffs_trace(YAFFS_TRACE_OS, "yaffs_iget for %lu", 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_gross_lock(dev);++	obj = yaffs_find_by_number(dev, inode->i_ino);++	yaffs_fill_inode_from_obj(inode, obj);++	yaffs_gross_unlock(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.+	 */++	struct yaffs_obj *obj;+	struct yaffs_dev *dev = yaffs_super_to_dev(inode->i_sb);++	yaffs_trace(YAFFS_TRACE_OS,+		"yaffs_read_inode for %d", (int)inode->i_ino);++	if (current != yaffs_dev_to_lc(dev)->readdir_process)+		yaffs_gross_lock(dev);++	obj = yaffs_find_by_number(dev, inode->i_ino);++	yaffs_fill_inode_from_obj(inode, obj);++	if (current != yaffs_dev_to_lc(dev)->readdir_process)+		yaffs_gross_unlock(dev);+}++#endif++++struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev,+			      struct yaffs_obj *obj)+{+	struct inode *inode;++	if (!sb) {+		yaffs_trace(YAFFS_TRACE_OS,+			"yaffs_get_inode for NULL super_block!!");+		return NULL;++	}++	if (!obj) {+		yaffs_trace(YAFFS_TRACE_OS,+			"yaffs_get_inode for NULL object!!");+		return NULL;++	}++	yaffs_trace(YAFFS_TRACE_OS,+		"yaffs_get_inode for object %d", obj->obj_id);++	inode = Y_IGET(sb, obj->obj_id);+	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 gross_lock or deadlock will happen! */++	return inode;+}++++#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(3, 4, 0))+static int yaffs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode,+		       dev_t rdev)+#elif (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;++	struct yaffs_obj *obj = NULL;+	struct yaffs_dev *dev;++	struct yaffs_obj *parent = yaffs_inode_to_obj(dir);++	int error = -ENOSPC;+	uid_t uid = YCRED_FSUID();+	gid_t gid =+	    (dir->i_mode & S_ISGID) ? i_gid_read(dir) : YCRED_FSGID();++	if ((dir->i_mode & S_ISGID) && S_ISDIR(mode))+		mode |= S_ISGID;++	if (parent) {+		yaffs_trace(YAFFS_TRACE_OS,+			"yaffs_mknod: parent object %d type %d",+			parent->obj_id, parent->variant_type);+	} else {+		yaffs_trace(YAFFS_TRACE_OS,+			"yaffs_mknod: could not get parent object");+		return -EPERM;+	}++	yaffs_trace(YAFFS_TRACE_OS,+		"yaffs_mknod: making oject for %s, mode %x dev %x",+		dentry->d_name.name, mode, rdev);++	dev = parent->my_dev;++	yaffs_gross_lock(dev);++	switch (mode & S_IFMT) {+	default:+		/* Special (socket, fifo, device...) */+		yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod: making special");+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))+		obj =+		    yaffs_create_special(parent, dentry->d_name.name, mode, uid,+					 gid, old_encode_dev(rdev));+#else+		obj =+		    yaffs_create_special(parent, dentry->d_name.name, mode, uid,+					 gid, rdev);+#endif+		break;+	case S_IFREG:		/* file          */+		yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod: making file");+		obj = yaffs_create_file(parent, dentry->d_name.name, mode, uid,+					gid);+		break;+	case S_IFDIR:		/* directory */+		yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod: making directory");+		obj = yaffs_create_dir(parent, dentry->d_name.name, mode,+				       uid, gid);+		break;+	case S_IFLNK:		/* symlink */+		yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod: making symlink");+		obj = NULL;	/* Do we ever get here? */+		break;+	}++	/* Can not call yaffs_get_inode() with gross lock held */+	yaffs_gross_unlock(dev);++	if (obj) {+		inode = yaffs_get_inode(dir->i_sb, mode, rdev, obj);+		d_instantiate(dentry, inode);+		update_dir_time(dir);+		yaffs_trace(YAFFS_TRACE_OS,+			"yaffs_mknod created object %d count = %d",+			obj->obj_id, atomic_read(&inode->i_count));+		error = 0;+		yaffs_fill_inode_from_obj(dir, parent);+	} else {+		yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod failed making object");+		error = -ENOMEM;+	}++	return error;+}++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))+static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)+#else+static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode)+#endif+{+	int ret_val;+	yaffs_trace(YAFFS_TRACE_OS, "yaffs_mkdir");+	ret_val = yaffs_mknod(dir, dentry, mode | S_IFDIR, 0);+	return ret_val;+}+++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))+static int yaffs_create(struct inode *dir, struct dentry *dentry, umode_t mode,+			bool dummy)+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))+static int yaffs_create(struct inode *dir, struct dentry *dentry, umode_t mode,+			struct nameidata *n)+#elif (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+{+	yaffs_trace(YAFFS_TRACE_OS, "yaffs_create");+	return yaffs_mknod(dir, dentry, mode | S_IFREG, 0);+}++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))+static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,+				   unsigned int dummy)+#elif (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+{+	struct yaffs_obj *obj;+	struct inode *inode = NULL;	/* NCB 2.5/2.6 needs NULL here */++	struct yaffs_dev *dev = yaffs_inode_to_obj(dir)->my_dev;++	if (current != yaffs_dev_to_lc(dev)->readdir_process)+		yaffs_gross_lock(dev);++	yaffs_trace(YAFFS_TRACE_OS, "yaffs_lookup for %d:%s",+		yaffs_inode_to_obj(dir)->obj_id, dentry->d_name.name);++	obj = yaffs_find_by_name(yaffs_inode_to_obj(dir), dentry->d_name.name);++	obj = yaffs_get_equivalent_obj(obj);	/* in case it was a hardlink */++	/* Can't hold gross lock when calling yaffs_get_inode() */+	if (current != yaffs_dev_to_lc(dev)->readdir_process)+		yaffs_gross_unlock(dev);++	if (obj) {+		yaffs_trace(YAFFS_TRACE_OS,+			"yaffs_lookup found %d", obj->obj_id);++		inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);+	} else {+		yaffs_trace(YAFFS_TRACE_OS, "yaffs_lookup not found");++	}++/* added NCB for 2.5/6 compatability - forces add even if inode is+ * NULL which creates dentry hash */+	d_add(dentry, inode);++	return NULL;+}++/*+ * Create a link...+ */+static int yaffs_link(struct dentry *old_dentry, struct inode *dir,+		      struct dentry *dentry)+{+	struct inode *inode = old_dentry->d_inode;+	struct yaffs_obj *obj = NULL;+	struct yaffs_obj *link = NULL;+	struct yaffs_dev *dev;++	yaffs_trace(YAFFS_TRACE_OS, "yaffs_link");++	obj = yaffs_inode_to_obj(inode);+	dev = obj->my_dev;++	yaffs_gross_lock(dev);++	if (!S_ISDIR(inode->i_mode))	/* Don't link directories */+		link =+		    yaffs_link_obj(yaffs_inode_to_obj(dir), dentry->d_name.name,+				   obj);++	if (link) {+		set_nlink(old_dentry->d_inode, yaffs_get_obj_link_count(obj));+		d_instantiate(dentry, old_dentry->d_inode);+		atomic_inc(&old_dentry->d_inode->i_count);+		yaffs_trace(YAFFS_TRACE_OS,+			"yaffs_link link count %d i_count %d",+			old_dentry->d_inode->i_nlink,+			atomic_read(&old_dentry->d_inode->i_count));+	}++	yaffs_gross_unlock(dev);++	if (link) {+		update_dir_time(dir);+		return 0;+	}++	return -EPERM;+}++static int yaffs_symlink(struct inode *dir, struct dentry *dentry,+			 const char *symname)+{+	struct yaffs_obj *obj;+	struct yaffs_dev *dev;+	uid_t uid = YCRED_FSUID();+	gid_t gid =+	    (dir->i_mode & S_ISGID) ? i_gid_read(dir) : YCRED_FSGID();++	yaffs_trace(YAFFS_TRACE_OS, "yaffs_symlink");++	if (strnlen(dentry->d_name.name, YAFFS_MAX_NAME_LENGTH + 1) >+				YAFFS_MAX_NAME_LENGTH)+		return -ENAMETOOLONG;++	if (strnlen(symname, YAFFS_MAX_ALIAS_LENGTH + 1) >+				YAFFS_MAX_ALIAS_LENGTH)+		return -ENAMETOOLONG;++	dev = yaffs_inode_to_obj(dir)->my_dev;+	yaffs_gross_lock(dev);+	obj = yaffs_create_symlink(yaffs_inode_to_obj(dir), dentry->d_name.name,+				   S_IFLNK | S_IRWXUGO, uid, gid, symname);+	yaffs_gross_unlock(dev);++	if (obj) {+		struct inode *inode;++		inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);+		d_instantiate(dentry, inode);+		update_dir_time(dir);+		yaffs_trace(YAFFS_TRACE_OS, "symlink created OK");+		return 0;+	} else {+		yaffs_trace(YAFFS_TRACE_OS, "symlink not created");+	}++	return -ENOMEM;+}++/*+ * 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)+{+	struct yaffs_dev *dev;+	int ret_val = YAFFS_FAIL;+	struct yaffs_obj *target;++	yaffs_trace(YAFFS_TRACE_OS, "yaffs_rename");+	dev = yaffs_inode_to_obj(old_dir)->my_dev;++	yaffs_gross_lock(dev);++	/* Check if the target is an existing directory that is not empty. */+	target = yaffs_find_by_name(yaffs_inode_to_obj(new_dir),+				    new_dentry->d_name.name);++	if (target && target->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY &&+	    !list_empty(&target->variant.dir_variant.children)) {++		yaffs_trace(YAFFS_TRACE_OS, "target is non-empty dir");++		ret_val = YAFFS_FAIL;+	} else {+		/* Now does unlinking internally using shadowing mechanism */+		yaffs_trace(YAFFS_TRACE_OS, "calling yaffs_rename_obj");++		ret_val = yaffs_rename_obj(yaffs_inode_to_obj(old_dir),+					   old_dentry->d_name.name,+					   yaffs_inode_to_obj(new_dir),+					   new_dentry->d_name.name);+	}+	yaffs_gross_unlock(dev);++	if (ret_val == YAFFS_OK) {+		if (target)+			inode_dec_link_count(new_dentry->d_inode);++		update_dir_time(old_dir);+		if (old_dir != new_dir)+			update_dir_time(new_dir);+		return 0;+	} else {+		return -ENOTEMPTY;+	}+}+++++static int yaffs_unlink(struct inode *dir, struct dentry *dentry)+{+	int ret_val;++	struct yaffs_dev *dev;+	struct yaffs_obj *obj;++	yaffs_trace(YAFFS_TRACE_OS, "yaffs_unlink %d:%s",+		(int)(dir->i_ino), dentry->d_name.name);+	obj = yaffs_inode_to_obj(dir);+	dev = obj->my_dev;++	yaffs_gross_lock(dev);++	ret_val = yaffs_unlinker(obj, dentry->d_name.name);++	if (ret_val == YAFFS_OK) {+		inode_dec_link_count(dentry->d_inode);+		dir->i_version++;+		yaffs_gross_unlock(dev);+		update_dir_time(dir);+		return 0;+	}+	yaffs_gross_unlock(dev);+	return -ENOTEMPTY;+}++++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,+	.setxattr = yaffs_setxattr,+	.getxattr = yaffs_getxattr,+	.listxattr = yaffs_listxattr,+	.removexattr = yaffs_removexattr,+};++/*-----------------------------------------------------------------*/+/* Directory search context allows us to unlock access to yaffs during+ * filldir without causing problems with the directory being modified.+ * This is similar to the tried and tested mechanism used in yaffs direct.+ *+ * A search context iterates along a doubly linked list of siblings in the+ * directory. If the iterating object is deleted then this would corrupt+ * the list iteration, likely causing a crash. The search context avoids+ * this by using the remove_obj_fn to move the search context to the+ * next object before the object is deleted.+ *+ * Many readdirs (and thus seach conexts) may be alive simulateously so+ * each struct yaffs_dev has a list of these.+ *+ * A seach context lives for the duration of a readdir.+ *+ * All these functions must be called while yaffs is locked.+ */++struct yaffs_search_context {+	struct yaffs_dev *dev;+	struct yaffs_obj *dir_obj;+	struct yaffs_obj *next_return;+	struct list_head others;+};++/*+ * yaffs_new_search() creates a new search context, initialises it and+ * adds it to the device's search context list.+ *+ * Called at start of readdir.+ */+static struct yaffs_search_context *yaffs_new_search(struct yaffs_obj *dir)+{+	struct yaffs_dev *dev = dir->my_dev;+	struct yaffs_search_context *sc =+	    kmalloc(sizeof(struct yaffs_search_context), GFP_NOFS);+	if (sc) {+		sc->dir_obj = dir;+		sc->dev = dev;+		if (list_empty(&sc->dir_obj->variant.dir_variant.children))+			sc->next_return = NULL;+		else+			sc->next_return =+			    list_entry(dir->variant.dir_variant.children.next,+				       struct yaffs_obj, siblings);+		INIT_LIST_HEAD(&sc->others);+		list_add(&sc->others, &(yaffs_dev_to_lc(dev)->search_contexts));+	}+	return sc;+}++/*+ * yaffs_search_end() disposes of a search context and cleans up.+ */+static void yaffs_search_end(struct yaffs_search_context *sc)+{+	if (sc) {+		list_del(&sc->others);+		kfree(sc);+	}+}++/*+ * yaffs_search_advance() moves a search context to the next object.+ * Called when the search iterates or when an object removal causes+ * the search context to be moved to the next object.+ */+static void yaffs_search_advance(struct yaffs_search_context *sc)+{+	if (!sc)+		return;++	if (sc->next_return == NULL ||+	    list_empty(&sc->dir_obj->variant.dir_variant.children))+		sc->next_return = NULL;+	else {+		struct list_head *next = sc->next_return->siblings.next;++		if (next == &sc->dir_obj->variant.dir_variant.children)+			sc->next_return = NULL;	/* end of list */+		else+			sc->next_return =+			    list_entry(next, struct yaffs_obj, siblings);+	}+}++/*+ * yaffs_remove_obj_callback() is called when an object is unlinked.+ * We check open search contexts and advance any which are currently+ * on the object being iterated.+ */+static void yaffs_remove_obj_callback(struct yaffs_obj *obj)+{++	struct list_head *i;+	struct yaffs_search_context *sc;+	struct list_head *search_contexts =+	    &(yaffs_dev_to_lc(obj->my_dev)->search_contexts);++	/* Iterate through the directory search contexts.+	 * If any are currently on the object being removed, then advance+	 * the search context to the next object to prevent a hanging pointer.+	 */+	list_for_each(i, search_contexts) {+		sc = list_entry(i, struct yaffs_search_context, others);+		if (sc->next_return == obj)+			yaffs_search_advance(sc);+	}++}+++/*-----------------------------------------------------------------*/++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))+static int yaffs_readdir(struct file *file, struct dir_context *ctx)+{+	struct yaffs_obj *obj;+	struct yaffs_dev *dev;+	struct yaffs_search_context *sc;+	struct inode *inode = file->f_dentry->d_inode;+	unsigned long offset, curoffs;+	struct yaffs_obj *l;+	int ret_val = 0;++	char name[YAFFS_MAX_NAME_LENGTH + 1];++	obj = yaffs_dentry_to_obj(file->f_dentry);+	dev = obj->my_dev;++	yaffs_gross_lock(dev);++	yaffs_dev_to_lc(dev)->readdir_process = current;++	offset = ctx->pos;++	sc = yaffs_new_search(obj);+	if (!sc) {+		ret_val = -ENOMEM;+		goto out;+	}++	yaffs_trace(YAFFS_TRACE_OS,+		"yaffs_readdir: starting at %d", (int)offset);++	if (offset == 0) {+		yaffs_trace(YAFFS_TRACE_OS,+			"yaffs_readdir: entry . ino %d",+			(int)inode->i_ino);+		yaffs_gross_unlock(dev);+		if (!dir_emit_dot(file, ctx)) {+			yaffs_gross_lock(dev);+			goto out;+		}+		yaffs_gross_lock(dev);+		offset++;+		ctx->pos++;+	}+	if (offset == 1) {+		yaffs_trace(YAFFS_TRACE_OS,+			"yaffs_readdir: entry .. ino %d",+			(int)file->f_dentry->d_parent->d_inode->i_ino);+		yaffs_gross_unlock(dev);+		if (!dir_emit_dotdot(file, ctx)) {+			yaffs_gross_lock(dev);+			goto out;+		}+		yaffs_gross_lock(dev);+		offset++;+		ctx->pos++;+	}++	curoffs = 1;++	/* If the directory has changed since the open or last call to+	   readdir, rewind to after the 2 canned entries. */+	if (file->f_version != inode->i_version) {+		offset = 2;+		ctx->pos = offset;+		file->f_version = inode->i_version;+	}++	while (sc->next_return) {+		curoffs++;+		l = sc->next_return;+		if (curoffs >= offset) {+			int this_inode = yaffs_get_obj_inode(l);+			int this_type = yaffs_get_obj_type(l);++			yaffs_get_obj_name(l, name, YAFFS_MAX_NAME_LENGTH + 1);+			yaffs_trace(YAFFS_TRACE_OS,+				"yaffs_readdir: %s inode %d",+				name, yaffs_get_obj_inode(l));++			yaffs_gross_unlock(dev);++			if (!dir_emit(ctx, name, strlen(name),+				      this_inode, this_type) < 0) {+				yaffs_gross_lock(dev);+				goto out;+			}++			yaffs_gross_lock(dev);++			offset++;+			ctx->pos++;+		}+		yaffs_search_advance(sc);+	}++out:+	yaffs_search_end(sc);+	yaffs_dev_to_lc(dev)->readdir_process = NULL;+	yaffs_gross_unlock(dev);++	return ret_val;+}+#else+static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir)+{+	struct yaffs_obj *obj;+	struct yaffs_dev *dev;+	struct yaffs_search_context *sc;+	struct inode *inode = f->f_dentry->d_inode;+	unsigned long offset, curoffs;+	struct yaffs_obj *l;+	int ret_val = 0;++	char name[YAFFS_MAX_NAME_LENGTH + 1];++	obj = yaffs_dentry_to_obj(f->f_dentry);+	dev = obj->my_dev;++	yaffs_gross_lock(dev);++	yaffs_dev_to_lc(dev)->readdir_process = current;++	offset = f->f_pos;++	sc = yaffs_new_search(obj);+	if (!sc) {+		ret_val = -ENOMEM;+		goto out;+	}++	yaffs_trace(YAFFS_TRACE_OS,+		"yaffs_readdir: starting at %d", (int)offset);++	if (offset == 0) {+		yaffs_trace(YAFFS_TRACE_OS,+			"yaffs_readdir: entry . ino %d",+			(int)inode->i_ino);+		yaffs_gross_unlock(dev);+		if (filldir(dirent, ".", 1, offset, inode->i_ino, DT_DIR) < 0) {+			yaffs_gross_lock(dev);+			goto out;+		}+		yaffs_gross_lock(dev);+		offset++;+		f->f_pos++;+	}+	if (offset == 1) {+		yaffs_trace(YAFFS_TRACE_OS,+			"yaffs_readdir: entry .. ino %d",+			(int)f->f_dentry->d_parent->d_inode->i_ino);+		yaffs_gross_unlock(dev);+		if (filldir(dirent, "..", 2, offset,+			    f->f_dentry->d_parent->d_inode->i_ino,+			    DT_DIR) < 0) {+			yaffs_gross_lock(dev);+			goto out;+		}+		yaffs_gross_lock(dev);+		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;+	}++	while (sc->next_return) {+		curoffs++;+		l = sc->next_return;+		if (curoffs >= offset) {+			int this_inode = yaffs_get_obj_inode(l);+			int this_type = yaffs_get_obj_type(l);++			yaffs_get_obj_name(l, name, YAFFS_MAX_NAME_LENGTH + 1);+			yaffs_trace(YAFFS_TRACE_OS,+				"yaffs_readdir: %s inode %d",+				name, yaffs_get_obj_inode(l));++			yaffs_gross_unlock(dev);++			if (filldir(dirent,+				    name,+				    strlen(name),+				    offset, this_inode, this_type) < 0) {+				yaffs_gross_lock(dev);+				goto out;+			}++			yaffs_gross_lock(dev);++			offset++;+			f->f_pos++;+		}+		yaffs_search_advance(sc);+	}++out:+	yaffs_search_end(sc);+	yaffs_dev_to_lc(dev)->readdir_process = NULL;+	yaffs_gross_unlock(dev);++	return ret_val;+}+#endif++static const struct file_operations yaffs_dir_operations = {+	.read = generic_read_dir,+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))+	.iterate = yaffs_readdir,+#else+	.readdir = yaffs_readdir,+#endif+	.fsync = yaffs_sync_object,+	.llseek = generic_file_llseek,+};++static void yaffs_fill_inode_from_obj(struct inode *inode,+				      struct yaffs_obj *obj)+{+	if (inode && obj) {++		/* Check mode against the variant type and attempt to repair if broken. */+		u32 mode = obj->yst_mode;+		switch (obj->variant_type) {+		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->obj_id;+		inode->i_mode = obj->yst_mode;+		i_uid_write(inode, obj->yst_uid);+		i_gid_write(inode, 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_get_obj_length(obj);+		inode->i_blocks = (inode->i_size + 511) >> 9;++		set_nlink(inode, yaffs_get_obj_link_count(obj));++		yaffs_trace(YAFFS_TRACE_OS,+			"yaffs_fill_inode mode %x uid %d gid %d size %lld count %d",+			inode->i_mode, i_uid_read(inode), i_gid_read(inode),+			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_inode_to_obj_lv(inode) = obj;++		obj->my_inode = inode;++	} else {+		yaffs_trace(YAFFS_TRACE_OS,+			"yaffs_fill_inode invalid parameters");+	}++}++++/*+ * yaffs background thread functions .+ * yaffs_bg_thread_fn() the thread function+ * yaffs_bg_start() launches the background thread.+ * yaffs_bg_stop() cleans up the background thread.+ *+ * NB:+ * The thread should only run after the yaffs is initialised+ * The thread should be stopped before yaffs is unmounted.+ * The thread should not do any writing while the fs is in read only.+ */++static unsigned yaffs_bg_gc_urgency(struct yaffs_dev *dev)+{+	unsigned erased_chunks =+	    dev->n_erased_blocks * dev->param.chunks_per_block;+	struct yaffs_linux_context *context = yaffs_dev_to_lc(dev);+	unsigned scattered = 0;	/* Free chunks not in an erased block */++	if (erased_chunks < dev->n_free_chunks)+		scattered = (dev->n_free_chunks - erased_chunks);++	if (!context->bg_running)+		return 0;+	else if (scattered < (dev->param.chunks_per_block * 2))+		return 0;+	else if (erased_chunks > dev->n_free_chunks / 2)+		return 0;+	else if (erased_chunks > dev->n_free_chunks / 4)+		return 1;+	else+		return 2;+}++#ifdef YAFFS_COMPILE_BACKGROUND++void yaffs_background_waker(unsigned long data)+{+	wake_up_process((struct task_struct *)data);+}++static int yaffs_bg_thread_fn(void *data)+{+	struct yaffs_dev *dev = (struct yaffs_dev *)data;+	struct yaffs_linux_context *context = yaffs_dev_to_lc(dev);+	unsigned long now = jiffies;+	unsigned long next_dir_update = now;+	unsigned long next_gc = now;+	unsigned long expires;+	unsigned int urgency;++	int gc_result;+	struct timer_list timer;++	yaffs_trace(YAFFS_TRACE_BACKGROUND,+		"yaffs_background starting for dev %p", (void *)dev);++#ifdef YAFFS_COMPILE_FREEZER+	set_freezable();+#endif+	while (context->bg_running) {+		yaffs_trace(YAFFS_TRACE_BACKGROUND, "yaffs_background");++		if (kthread_should_stop())+			break;++#ifdef YAFFS_COMPILE_FREEZER+		if (try_to_freeze())+			continue;+#endif+		yaffs_gross_lock(dev);++		now = jiffies;++		if (time_after(now, next_dir_update) && yaffs_bg_enable) {+			yaffs_update_dirty_dirs(dev);+			next_dir_update = now + HZ;+		}++		if (time_after(now, next_gc) && yaffs_bg_enable) {+			if (!dev->is_checkpointed) {+				urgency = yaffs_bg_gc_urgency(dev);+				gc_result = yaffs_bg_gc(dev, urgency);+				if (urgency > 1)+					next_gc = now + HZ / 20 + 1;+				else if (urgency > 0)+					next_gc = now + HZ / 10 + 1;+				else+					next_gc = now + HZ * 2;+			} else	{+			        /*+				 * gc not running so set to next_dir_update+				 * to cut down on wake ups+				 */+				next_gc = next_dir_update;+                        }+		}+		yaffs_gross_unlock(dev);+#if 1+		expires = next_dir_update;+		if (time_before(next_gc, expires))+			expires = next_gc;+		if (time_before(expires, now))+			expires = now + HZ;++		Y_INIT_TIMER(&timer);+		timer.expires = expires + 1;+		timer.data = (unsigned long)current;+		timer.function = yaffs_background_waker;++		set_current_state(TASK_INTERRUPTIBLE);+		add_timer(&timer);+		schedule();+		del_timer_sync(&timer);+#else+		msleep(10);+#endif+	}++	return 0;+}++static int yaffs_bg_start(struct yaffs_dev *dev)+{+	int retval = 0;+	struct yaffs_linux_context *context = yaffs_dev_to_lc(dev);++	if (dev->read_only)+		return -1;++	context->bg_running = 1;++	context->bg_thread = kthread_run(yaffs_bg_thread_fn,+					 (void *)dev, "yaffs-bg-%d",+					 context->mount_id);++	if (IS_ERR(context->bg_thread)) {+		retval = PTR_ERR(context->bg_thread);+		context->bg_thread = NULL;+		context->bg_running = 0;+	}+	return retval;+}++static void yaffs_bg_stop(struct yaffs_dev *dev)+{+	struct yaffs_linux_context *ctxt = yaffs_dev_to_lc(dev);++	ctxt->bg_running = 0;++	if (ctxt->bg_thread) {+		kthread_stop(ctxt->bg_thread);+		ctxt->bg_thread = NULL;+	}+}+#else+static int yaffs_bg_thread_fn(void *data)+{+	return 0;+}++static int yaffs_bg_start(struct yaffs_dev *dev)+{+	return 0;+}++static void yaffs_bg_stop(struct yaffs_dev *dev)+{+}+#endif+++static void yaffs_flush_inodes(struct super_block *sb)+{+	struct inode *iptr;+	struct yaffs_obj *obj;++	list_for_each_entry(iptr, &sb->s_inodes, i_sb_list) {+		obj = yaffs_inode_to_obj(iptr);+		if (obj) {+			yaffs_trace(YAFFS_TRACE_OS,+				"flushing obj %d",+				obj->obj_id);+			yaffs_flush_file(obj, 1, 0);+		}+	}+}++static void yaffs_flush_super(struct super_block *sb, int do_checkpoint)+{+	struct yaffs_dev *dev = yaffs_super_to_dev(sb);+	if (!dev)+		return;++	yaffs_flush_inodes(sb);+	yaffs_update_dirty_dirs(dev);+	yaffs_flush_whole_cache(dev);+	if (do_checkpoint)+		yaffs_checkpoint_save(dev);+}++static LIST_HEAD(yaffs_context_list);+struct mutex yaffs_context_lock;++static void yaffs_put_super(struct super_block *sb)+{+	struct yaffs_dev *dev = yaffs_super_to_dev(sb);+	struct mtd_info *mtd = yaffs_dev_to_mtd(dev);++	yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_ALWAYS,+			"yaffs_put_super");++	yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_BACKGROUND,+		"Shutting down yaffs background thread");+	yaffs_bg_stop(dev);+	yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_BACKGROUND,+		"yaffs background thread shut down");++	yaffs_gross_lock(dev);++	yaffs_flush_super(sb, 1);++	yaffs_deinitialise(dev);++	yaffs_gross_unlock(dev);++	mutex_lock(&yaffs_context_lock);+	list_del_init(&(yaffs_dev_to_lc(dev)->context_list));+	mutex_unlock(&yaffs_context_lock);++	if (yaffs_dev_to_lc(dev)->spare_buffer) {+		kfree(yaffs_dev_to_lc(dev)->spare_buffer);+		yaffs_dev_to_lc(dev)->spare_buffer = NULL;+	}++	kfree(dev);++	yaffs_put_mtd_device(mtd);++	yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_ALWAYS,+			"yaffs_put_super done");+}+++static unsigned yaffs_gc_control_callback(struct yaffs_dev *dev)+{+	return yaffs_gc_control;+}+++#ifdef YAFFS_COMPILE_EXPORTFS++static struct inode *yaffs2_nfs_get_inode(struct super_block *sb, uint64_t ino,+					  uint32_t generation)+{+	return Y_IGET(sb, ino);+}++static struct dentry *yaffs2_fh_to_dentry(struct super_block *sb,+					  struct fid *fid, int fh_len,+					  int fh_type)+{+	return generic_fh_to_dentry(sb, fid, fh_len, fh_type,+				    yaffs2_nfs_get_inode);+}++static struct dentry *yaffs2_fh_to_parent(struct super_block *sb,+					  struct fid *fid, int fh_len,+					  int fh_type)+{+	return generic_fh_to_parent(sb, fid, fh_len, fh_type,+				    yaffs2_nfs_get_inode);+}++struct dentry *yaffs2_get_parent(struct dentry *dentry)+{++	struct super_block *sb = dentry->d_inode->i_sb;+	struct dentry *parent = ERR_PTR(-ENOENT);+	struct inode *inode;+	unsigned long parent_ino;+	struct yaffs_obj *d_obj;+	struct yaffs_obj *parent_obj;++	d_obj = yaffs_inode_to_obj(dentry->d_inode);++	if (d_obj) {+		parent_obj = d_obj->parent;+		if (parent_obj) {+			parent_ino = yaffs_get_obj_inode(parent_obj);+			inode = Y_IGET(sb, parent_ino);++			if (IS_ERR(inode)) {+				parent = ERR_CAST(inode);+			} else {+				parent = d_obtain_alias(inode);+				if (!IS_ERR(parent)) {+					parent = ERR_PTR(-ENOMEM);+					iput(inode);+				}+			}+		}+	}++	return parent;+}++/* Just declare a zero structure as a NULL value implies+ * using the default functions of exportfs.+ */++static struct export_operations yaffs_export_ops = {+	.fh_to_dentry = yaffs2_fh_to_dentry,+	.fh_to_parent = yaffs2_fh_to_parent,+	.get_parent = yaffs2_get_parent,+};++#endif++static void yaffs_unstitch_obj(struct inode *inode, struct yaffs_obj *obj)+{+	/* Clear the association between the inode and+	 * the struct yaffs_obj.+	 */+	obj->my_inode = NULL;+	yaffs_inode_to_obj_lv(inode) = NULL;++	/* If the object freeing was deferred, then the real+	 * free happens now.+	 * This should fix the inode inconsistency problem.+	 */+	yaffs_handle_defered_free(obj);+}++#ifdef YAFFS_HAS_EVICT_INODE+/* yaffs_evict_inode combines into one operation what was previously done in+ * yaffs_clear_inode() and yaffs_delete_inode()+ *+ */+static void yaffs_evict_inode(struct inode *inode)+{+	struct yaffs_obj *obj;+	struct yaffs_dev *dev;+	int deleteme = 0;++	obj = yaffs_inode_to_obj(inode);++	yaffs_trace(YAFFS_TRACE_OS,+		"yaffs_evict_inode: ino %d, count %d %s",+		(int)inode->i_ino, atomic_read(&inode->i_count),+		obj ? "object exists" : "null object");++	if (!inode->i_nlink && !is_bad_inode(inode))+		deleteme = 1;+	truncate_inode_pages(&inode->i_data, 0);+	Y_CLEAR_INODE(inode);++	if (deleteme && obj) {+		dev = obj->my_dev;+		yaffs_gross_lock(dev);+		yaffs_del_obj(obj);+		yaffs_gross_unlock(dev);+	}+	if (obj) {+		dev = obj->my_dev;+		yaffs_gross_lock(dev);+		yaffs_unstitch_obj(inode, obj);+		yaffs_gross_unlock(dev);+	}+}+#else++/* clear is called to tell the fs to release any per-inode data it holds.+ * The object might still exist on disk and is just being thrown out of the cache+ * or else the object has actually been deleted and we're being called via+ * the chain+ *   yaffs_delete_inode() -> clear_inode()->yaffs_clear_inode()+ */++static void yaffs_clear_inode(struct inode *inode)+{+	struct yaffs_obj *obj;+	struct yaffs_dev *dev;++	obj = yaffs_inode_to_obj(inode);++	yaffs_trace(YAFFS_TRACE_OS,+		"yaffs_clear_inode: ino %d, count %d %s",+		(int)inode->i_ino, atomic_read(&inode->i_count),+		obj ? "object exists" : "null object");++	if (obj) {+		dev = obj->my_dev;+		yaffs_gross_lock(dev);+		yaffs_unstitch_obj(inode, obj);+		yaffs_gross_unlock(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)+{+	struct yaffs_obj *obj = yaffs_inode_to_obj(inode);+	struct yaffs_dev *dev;++	yaffs_trace(YAFFS_TRACE_OS,+		"yaffs_delete_inode: ino %d, count %d %s",+		(int)inode->i_ino, atomic_read(&inode->i_count),+		obj ? "object exists" : "null object");++	if (obj) {+		dev = obj->my_dev;+		yaffs_gross_lock(dev);+		yaffs_del_obj(obj);+		yaffs_gross_unlock(dev);+	}+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))+	truncate_inode_pages(&inode->i_data, 0);+#endif+	clear_inode(inode);+}+#endif+++++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))+static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf)+{+	struct yaffs_dev *dev = yaffs_dentry_to_obj(dentry)->my_dev;+	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)+{+	struct yaffs_dev *dev = yaffs_super_to_dev(sb);+#else+static int yaffs_statfs(struct super_block *sb, struct statfs *buf)+{+	struct yaffs_dev *dev = yaffs_super_to_dev(sb);+#endif++	yaffs_trace(YAFFS_TRACE_OS, "yaffs_statfs");++	yaffs_gross_lock(dev);++	buf->f_type = YAFFS_MAGIC;+	buf->f_bsize = sb->s_blocksize;+	buf->f_namelen = 255;++	if (dev->data_bytes_per_chunk & (dev->data_bytes_per_chunk - 1)) {+		/* Do this if chunk size is not a power of 2 */++		uint64_t bytes_in_dev;+		uint64_t bytes_free;++		bytes_in_dev =+		    ((uint64_t)+		     ((dev->param.end_block - dev->param.start_block ++		       1))) * ((uint64_t) (dev->param.chunks_per_block *+					   dev->data_bytes_per_chunk));++		do_div(bytes_in_dev, sb->s_blocksize);	/* bytes_in_dev becomes the number of blocks */+		buf->f_blocks = bytes_in_dev;++		bytes_free = ((uint64_t) (yaffs_get_n_free_chunks(dev))) *+		    ((uint64_t) (dev->data_bytes_per_chunk));++		do_div(bytes_free, sb->s_blocksize);++		buf->f_bfree = bytes_free;++	} else if (sb->s_blocksize > dev->data_bytes_per_chunk) {++		buf->f_blocks =+		    (dev->param.end_block - dev->param.start_block + 1) *+		    dev->param.chunks_per_block /+		    (sb->s_blocksize / dev->data_bytes_per_chunk);+		buf->f_bfree =+		    yaffs_get_n_free_chunks(dev) /+		    (sb->s_blocksize / dev->data_bytes_per_chunk);+	} else {+		buf->f_blocks =+		    (dev->param.end_block - dev->param.start_block + 1) *+		    dev->param.chunks_per_block *+		    (dev->data_bytes_per_chunk / sb->s_blocksize);++		buf->f_bfree =+		    yaffs_get_n_free_chunks(dev) *+		    (dev->data_bytes_per_chunk / sb->s_blocksize);+	}++	buf->f_files = 0;+	buf->f_ffree = 0;+	buf->f_bavail = buf->f_bfree;++	yaffs_gross_unlock(dev);+	return 0;+}++++static int yaffs_do_sync_fs(struct super_block *sb, int request_checkpoint)+{++	struct yaffs_dev *dev = yaffs_super_to_dev(sb);+	unsigned int oneshot_checkpoint = (yaffs_auto_checkpoint & 4);+	unsigned gc_urgent = yaffs_bg_gc_urgency(dev);+	int do_checkpoint;+	int dirty = yaffs_check_super_dirty(dev);++	yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC | YAFFS_TRACE_BACKGROUND,+		"yaffs_do_sync_fs: gc-urgency %d %s %s%s",+		gc_urgent,+		dirty ? "dirty" : "clean",+		request_checkpoint ? "checkpoint requested" : "no checkpoint",+		oneshot_checkpoint ? " one-shot" : "");++	yaffs_gross_lock(dev);+	do_checkpoint = ((request_checkpoint && !gc_urgent) ||+			 oneshot_checkpoint) && !dev->is_checkpointed;++	if (dirty || do_checkpoint) {+		yaffs_flush_super(sb, !dev->is_checkpointed && do_checkpoint);+		yaffs_clear_super_dirty(dev);+		if (oneshot_checkpoint)+			yaffs_auto_checkpoint &= ~4;+	}+	yaffs_gross_unlock(dev);++	return 0;+}+++#ifdef YAFFS_HAS_WRITE_SUPER+#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+{+	unsigned request_checkpoint = (yaffs_auto_checkpoint >= 2);++	yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC | YAFFS_TRACE_BACKGROUND,+		"yaffs_write_super %s",+		request_checkpoint ? " checkpt" : "");++	yaffs_do_sync_fs(sb, request_checkpoint);++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18))+	return 0;+#endif+}+#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+{+	unsigned request_checkpoint = (yaffs_auto_checkpoint >= 1);++	yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC,+		"yaffs_sync_fs%s", request_checkpoint ? " checkpt" : "");++	yaffs_do_sync_fs(sb, request_checkpoint);++	return 0;+}++++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,+#ifdef YAFFS_HAS_EVICT_INODE+	.evict_inode = yaffs_evict_inode,+#else+	.delete_inode = yaffs_delete_inode,+	.clear_inode = yaffs_clear_inode,+#endif+	.sync_fs = yaffs_sync_fs,+#ifdef YAFFS_HAS_WRITE_SUPER+	.write_super = yaffs_write_super,+#endif+};++struct yaffs_options {+	int inband_tags;+	int skip_checkpoint_read;+	int skip_checkpoint_write;+	int no_cache;+	int tags_ecc_on;+	int tags_ecc_overridden;+	int lazy_loading_enabled;+	int lazy_loading_overridden;+	int empty_lost_and_found;+	int empty_lost_and_found_overridden;+	int disable_summary;+};++#define MAX_OPT_LEN 30+static int yaffs_parse_options(struct 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++;++		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, "tags-ecc-off")) {+			options->tags_ecc_on = 0;+			options->tags_ecc_overridden = 1;+		} else if (!strcmp(cur_opt, "tags-ecc-on")) {+			options->tags_ecc_on = 1;+			options->tags_ecc_overridden = 1;+		} else if (!strcmp(cur_opt, "lazy-loading-off")) {+			options->lazy_loading_enabled = 0;+			options->lazy_loading_overridden = 1;+		} else if (!strcmp(cur_opt, "lazy-loading-on")) {+			options->lazy_loading_enabled = 1;+			options->lazy_loading_overridden = 1;+		} else if (!strcmp(cur_opt, "disable-summary")) {+			options->disable_summary = 1;+		} else if (!strcmp(cur_opt, "empty-lost-and-found-off")) {+			options->empty_lost_and_found = 0;+			options->empty_lost_and_found_overridden = 1;+		} else if (!strcmp(cur_opt, "empty-lost-and-found-on")) {+			options->empty_lost_and_found = 1;+			options->empty_lost_and_found_overridden = 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 dentry *yaffs_make_root(struct inode *inode)+{+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0))+	struct dentry *root = d_alloc_root(inode);++	if (!root)+		iput(inode);++        return root;+#else+        return d_make_root(inode);+#endif+}+++++static struct super_block *yaffs_internal_read_super(int yaffs_version,+						     struct super_block *sb,+						     void *data, int silent)+{+	int n_blocks;+	struct inode *inode = NULL;+	struct dentry *root;+	struct yaffs_dev *dev = 0;+	char devname_buf[BDEVNAME_SIZE + 1];+	struct mtd_info *mtd;+	int err;+	char *data_str = (char *)data;+	struct yaffs_linux_context *context = NULL;+	struct yaffs_param *param;++	int read_only = 0;+	int inband_tags = 0;++	struct yaffs_options options;++	unsigned mount_id;+	int found;+	struct yaffs_linux_context *context_iterator;+	struct list_head *l;++	if (!sb) {+		printk(KERN_INFO "yaffs: sb is NULL\n");+		return NULL;+        }++	sb->s_magic = YAFFS_MAGIC;+	sb->s_op = &yaffs_super_ops;+	sb->s_flags |= MS_NOATIME;++	read_only = ((sb->s_flags & MS_RDONLY) != 0);++#ifdef YAFFS_COMPILE_EXPORTFS+	sb->s_export_op = &yaffs_export_ops;+#endif++	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\" %s\n",+		       sb->s_dev,+		       yaffs_devname(sb, devname_buf), read_only ? "ro" : "rw");++	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;++	yaffs_trace(YAFFS_TRACE_OS,+		"yaffs_read_super: Using yaffs%d", yaffs_version);+	yaffs_trace(YAFFS_TRACE_OS,+		"yaffs_read_super: block size %d", (int)(sb->s_blocksize));++	yaffs_trace(YAFFS_TRACE_ALWAYS,+		"yaffs: Attempting MTD mount of %u.%u,\"%s\"",+		MAJOR(sb->s_dev), MINOR(sb->s_dev),+		yaffs_devname(sb, devname_buf));++	/* Get the device */+	mtd = get_mtd_device(NULL, MINOR(sb->s_dev));+	if (IS_ERR(mtd)) {+		yaffs_trace(YAFFS_TRACE_ALWAYS,+			"yaffs: MTD device %u either not valid or unavailable",+			MINOR(sb->s_dev));+		return NULL;+	}++	if (yaffs_auto_select && yaffs_version == 1 && WRITE_SIZE(mtd) >= 2048) {+		yaffs_trace(YAFFS_TRACE_ALWAYS, "auto selecting yaffs2");+		yaffs_version = 2;+	}++	/* Added NCB 26/5/2006 for completeness */+	if (yaffs_version == 2 && !options.inband_tags+	    && WRITE_SIZE(mtd) == 512) {+		yaffs_trace(YAFFS_TRACE_ALWAYS, "auto selecting yaffs1");+		yaffs_version = 1;+	}++	if (mtd->oobavail < sizeof(struct yaffs_packed_tags2) ||+	    options.inband_tags)+		inband_tags = 1;++	if(yaffs_verify_mtd(mtd, yaffs_version, inband_tags) < 0)+		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 struct yaffs_dev up for mtd+	 */++	if (!read_only && !(mtd->flags & MTD_WRITEABLE)) {+		read_only = 1;+		printk(KERN_INFO+		       "yaffs: mtd is read only, setting superblock read only\n"+		);+		sb->s_flags |= MS_RDONLY;+	}++	dev = kmalloc(sizeof(struct yaffs_dev), GFP_KERNEL);+	context = kmalloc(sizeof(struct yaffs_linux_context), GFP_KERNEL);++	if (!dev || !context) {+		kfree(dev);+		kfree(context);+		dev = NULL;+		context = NULL;++		/* Deep shit could not allocate device structure */+		yaffs_trace(YAFFS_TRACE_ALWAYS,+			"yaffs_read_super: Failed trying to allocate struct yaffs_dev."+		);+		return NULL;+	}+	memset(dev, 0, sizeof(struct yaffs_dev));+	param = &(dev->param);++	memset(context, 0, sizeof(struct yaffs_linux_context));+	dev->os_context = context;+	INIT_LIST_HEAD(&(context->context_list));+	context->dev = dev;+	context->super = sb;++	dev->read_only = read_only;++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))+	sb->s_fs_info = dev;+#else+	sb->u.generic_sbp = dev;+#endif+++	dev->driver_context = mtd;+	param->name = mtd->name;++	/* Set up the memory size parameters.... */+++	param->n_reserved_blocks = 5;+	param->n_caches = (options.no_cache) ? 0 : 10;+	param->inband_tags = inband_tags;++	param->enable_xattr = 1;+	if (options.lazy_loading_overridden)+		param->disable_lazy_load = !options.lazy_loading_enabled;++	param->defered_dir_update = 1;++	if (options.tags_ecc_overridden)+		param->no_tags_ecc = !options.tags_ecc_on;++	param->empty_lost_n_found = 1;+	param->refresh_period = 500;+	param->disable_summary = options.disable_summary;+++#ifdef CONFIG_YAFFS_DISABLE_BAD_BLOCK_MARKING+	param->disable_bad_block_marking  = 1;+#endif+	if (options.empty_lost_and_found_overridden)+		param->empty_lost_n_found = options.empty_lost_and_found;++	/* ... and the functions. */+	if (yaffs_version == 2) {+		param->is_yaffs2 = 1;+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))+		param->total_bytes_per_chunk = mtd->writesize;+		param->chunks_per_block = mtd->erasesize / mtd->writesize;+#else+		param->total_bytes_per_chunk = mtd->oobblock;+		param->chunks_per_block = mtd->erasesize / mtd->oobblock;+#endif+		n_blocks = YCALCBLOCKS(mtd->size, mtd->erasesize);++		param->start_block = 0;+		param->end_block = n_blocks - 1;+	} else {+		param->is_yaffs2 = 0;+		n_blocks = YCALCBLOCKS(mtd->size,+			     YAFFS_CHUNKS_PER_BLOCK * YAFFS_BYTES_PER_CHUNK);++		param->chunks_per_block = YAFFS_CHUNKS_PER_BLOCK;+		param->total_bytes_per_chunk = YAFFS_BYTES_PER_CHUNK;+	}++	param->start_block = 0;+	param->end_block = n_blocks - 1;++	yaffs_mtd_drv_install(dev);++	param->sb_dirty_fn = yaffs_set_super_dirty;+	param->gc_control_fn = yaffs_gc_control_callback;++	yaffs_dev_to_lc(dev)->super = sb;++	param->use_nand_ecc = 1;++	param->skip_checkpt_rd = options.skip_checkpoint_read;+	param->skip_checkpt_wr = options.skip_checkpoint_write;++	mutex_lock(&yaffs_context_lock);+	/* Get a mount id */+	found = 0;+	for (mount_id = 0; !found; mount_id++) {+		found = 1;+		list_for_each(l, &yaffs_context_list) {+			context_iterator =+			    list_entry(l, struct yaffs_linux_context,+				       context_list);+			if (context_iterator->mount_id == mount_id)+				found = 0;+		}+	}+	context->mount_id = mount_id;++	list_add_tail(&(yaffs_dev_to_lc(dev)->context_list),+		      &yaffs_context_list);+	mutex_unlock(&yaffs_context_lock);++	/* Directory search handling... */+	INIT_LIST_HEAD(&(yaffs_dev_to_lc(dev)->search_contexts));+	param->remove_obj_fn = yaffs_remove_obj_callback;++	mutex_init(&(yaffs_dev_to_lc(dev)->gross_lock));++	yaffs_gross_lock(dev);++	err = yaffs_guts_initialise(dev);++	yaffs_trace(YAFFS_TRACE_OS,+		"yaffs_read_super: guts initialised %s",+		(err == YAFFS_OK) ? "OK" : "FAILED");++	if (err == YAFFS_OK)+		yaffs_bg_start(dev);++	if (!context->bg_thread)+		param->defered_dir_update = 0;++	sb->s_maxbytes = yaffs_max_file_size(dev);++	/* Release lock before yaffs_get_inode() */+	yaffs_gross_unlock(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;++	yaffs_trace(YAFFS_TRACE_OS, "yaffs_read_super: got root inode");++	root = yaffs_make_root(inode);++	if (!root)+		return NULL;++	sb->s_root = root;+	if(!dev->is_checkpointed)+		yaffs_set_super_dirty(dev);++	yaffs_trace(YAFFS_TRACE_ALWAYS,+		"yaffs_read_super: is_checkpointed %d",+		dev->is_checkpointed);++	yaffs_trace(YAFFS_TRACE_OS, "yaffs_read_super: done");+	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, 39))+static struct dentry *yaffs_mount(struct file_system_type *fs_type, int flags,+        const char *dev_name, void *data)+{+    return mount_bdev(fs_type, flags, dev_name, data, yaffs_internal_read_super_mtd);+}+#elif (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",+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))+        .mount = yaffs_mount,+#else+        .get_sb = yaffs_read_super,+#endif+     	.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+++#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, 39))+static struct dentry *yaffs2_mount(struct file_system_type *fs_type, int flags,+        const char *dev_name, void *data)+{+        return mount_bdev(fs_type, flags, dev_name, data, yaffs2_internal_read_super_mtd);+}+#elif (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",+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))+        .mount = yaffs2_mount,+#else+        .get_sb = yaffs2_read_super,+#endif+     	.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+++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0))+static struct proc_dir_entry *my_proc_entry;++static char *yaffs_dump_dev_part0(char *buf, struct yaffs_dev *dev)+{+	struct yaffs_param *param = &dev->param;+	int bs[10];++	yaffs_count_blocks_by_state(dev,bs);++	buf += sprintf(buf, "start_block.......... %d\n", param->start_block);+	buf += sprintf(buf, "end_block............ %d\n", param->end_block);+	buf += sprintf(buf, "total_bytes_per_chunk %d\n",+				param->total_bytes_per_chunk);+	buf += sprintf(buf, "use_nand_ecc......... %d\n", param->use_nand_ecc);+	buf += sprintf(buf, "no_tags_ecc.......... %d\n", param->no_tags_ecc);+	buf += sprintf(buf, "is_yaffs2............ %d\n", param->is_yaffs2);+	buf += sprintf(buf, "inband_tags.......... %d\n", param->inband_tags);+	buf += sprintf(buf, "empty_lost_n_found... %d\n",+				param->empty_lost_n_found);+	buf += sprintf(buf, "disable_lazy_load.... %d\n",+				param->disable_lazy_load);+	buf += sprintf(buf, "disable_bad_block_mrk %d\n",+				param->disable_bad_block_marking);+	buf += sprintf(buf, "refresh_period....... %d\n",+				param->refresh_period);+	buf += sprintf(buf, "n_caches............. %d\n", param->n_caches);+	buf += sprintf(buf, "n_reserved_blocks.... %d\n",+				param->n_reserved_blocks);+	buf += sprintf(buf, "always_check_erased.. %d\n",+				param->always_check_erased);+	buf += sprintf(buf, "\n");+	buf += sprintf(buf, "block count by state\n");+	buf += sprintf(buf, "0:%d 1:%d 2:%d 3:%d 4:%d\n",+				bs[0], bs[1], bs[2], bs[3], bs[4]);+	buf += sprintf(buf, "5:%d 6:%d 7:%d 8:%d 9:%d\n",+				bs[5], bs[6], bs[7], bs[8], bs[9]);++	return buf;+}++static char *yaffs_dump_dev_part1(char *buf, struct yaffs_dev *dev)+{+	buf += sprintf(buf, "max file size....... %lld\n",+				(long long) yaffs_max_file_size(dev));+	buf += sprintf(buf, "data_bytes_per_chunk. %d\n",+				dev->data_bytes_per_chunk);+	buf += sprintf(buf, "chunk_grp_bits....... %d\n", dev->chunk_grp_bits);+	buf += sprintf(buf, "chunk_grp_size....... %d\n", dev->chunk_grp_size);+	buf += sprintf(buf, "n_erased_blocks...... %d\n", dev->n_erased_blocks);+	buf += sprintf(buf, "blocks_in_checkpt.... %d\n",+				dev->blocks_in_checkpt);+	buf += sprintf(buf, "\n");+	buf += sprintf(buf, "n_tnodes............. %d\n", dev->n_tnodes);+	buf += sprintf(buf, "n_obj................ %d\n", dev->n_obj);+	buf += sprintf(buf, "n_free_chunks........ %d\n", dev->n_free_chunks);+	buf += sprintf(buf, "\n");+	buf += sprintf(buf, "n_page_writes........ %u\n", dev->n_page_writes);+	buf += sprintf(buf, "n_page_reads......... %u\n", dev->n_page_reads);+	buf += sprintf(buf, "n_erasures........... %u\n", dev->n_erasures);+	buf += sprintf(buf, "n_gc_copies.......... %u\n", dev->n_gc_copies);+	buf += sprintf(buf, "all_gcs.............. %u\n", dev->all_gcs);+	buf += sprintf(buf, "passive_gc_count..... %u\n",+				dev->passive_gc_count);+	buf += sprintf(buf, "oldest_dirty_gc_count %u\n",+				dev->oldest_dirty_gc_count);+	buf += sprintf(buf, "n_gc_blocks.......... %u\n", dev->n_gc_blocks);+	buf += sprintf(buf, "bg_gcs............... %u\n", dev->bg_gcs);+	buf += sprintf(buf, "n_retried_writes..... %u\n",+				dev->n_retried_writes);+	buf += sprintf(buf, "n_retired_blocks..... %u\n",+				dev->n_retired_blocks);+	buf += sprintf(buf, "n_ecc_fixed.......... %u\n", dev->n_ecc_fixed);+	buf += sprintf(buf, "n_ecc_unfixed........ %u\n", dev->n_ecc_unfixed);+	buf += sprintf(buf, "n_tags_ecc_fixed..... %u\n",+				dev->n_tags_ecc_fixed);+	buf += sprintf(buf, "n_tags_ecc_unfixed... %u\n",+				dev->n_tags_ecc_unfixed);+	buf += sprintf(buf, "cache_hits........... %u\n", dev->cache_hits);+	buf += sprintf(buf, "n_deleted_files...... %u\n", dev->n_deleted_files);+	buf += sprintf(buf, "n_unlinked_files..... %u\n",+				dev->n_unlinked_files);+	buf += sprintf(buf, "refresh_count........ %u\n", dev->refresh_count);+	buf += sprintf(buf, "n_bg_deletions....... %u\n", dev->n_bg_deletions);+	buf += sprintf(buf, "tags_used............ %u\n", dev->tags_used);+	buf += sprintf(buf, "summary_used......... %u\n", dev->summary_used);++	return buf;+}++static int yaffs_proc_read(char *page,+			   char **start,+			   off_t offset, int count, int *eof, void *data)+{+	struct list_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 dev_list.+	 * 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,+			    "Multi-version YAFFS built:" __DATE__ " " __TIME__+			    "\n");+	else if (step == 1)+		buf += sprintf(buf, "\n");+	else {+		step -= 2;++		mutex_lock(&yaffs_context_lock);++		/* Locate and print the Nth entry.  Order N-squared but N is small. */+		list_for_each(item, &yaffs_context_list) {+			struct yaffs_linux_context *dc =+			    list_entry(item, struct yaffs_linux_context,+				       context_list);+			struct yaffs_dev *dev = dc->dev;++			if (n < (step & ~1)) {+				n += 2;+				continue;+			}+			if ((step & 1) == 0) {+				buf +=+				    sprintf(buf, "\nDevice %d \"%s\"\n", n,+					    dev->param.name);+				buf = yaffs_dump_dev_part0(buf, dev);+			} else {+				buf = yaffs_dump_dev_part1(buf, dev);+                        }++			break;+		}+		mutex_unlock(&yaffs_context_lock);+	}++	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},+	{"background", YAFFS_TRACE_BACKGROUND},+	{"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},+	{"lock", YAFFS_TRACE_LOCK},+	{"mtd", YAFFS_TRACE_MTD},+	{"nandaccess", YAFFS_TRACE_NANDACCESS},+	{"os", YAFFS_TRACE_OS},+	{"scan_debug", YAFFS_TRACE_SCAN_DEBUG},+	{"scan", YAFFS_TRACE_SCAN},+	{"mount", YAFFS_TRACE_MOUNT},+	{"tracing", YAFFS_TRACE_TRACING},+	{"sync", YAFFS_TRACE_SYNC},+	{"write", YAFFS_TRACE_WRITE},+	{"verify", YAFFS_TRACE_VERIFY},+	{"verify_nand", YAFFS_TRACE_VERIFY_NAND},+	{"verify_full", YAFFS_TRACE_VERIFY_FULL},+	{"verify_all", YAFFS_TRACE_VERIFY_ALL},+	{"all", 0xffffffff},+	{"none", 0},+	{NULL, 0},+};++#define MAX_MASK_NAME_LENGTH 40+static int yaffs_proc_write_trace_options(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_trace_mask;++	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_trace_mask = rg | YAFFS_TRACE_ALWAYS;++	printk(KERN_DEBUG "new trace = 0x%08X\n", yaffs_trace_mask);++	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;+}++/* Debug strings are of the form:+ * .bnnn         print info on block n+ * .cobjn,chunkn print nand chunk id for objn:chunkn+ */++static int yaffs_proc_debug_write(struct file *file, const char *buf,+					  unsigned long count, void *data)+{++	char str[100];+	char *p0;+	char *p1;+	long p1_val;+	long p0_val;+	char cmd;+	struct list_head *item;++	memset(str, 0, sizeof(str));+	memcpy(str, buf, min(count, sizeof(str) -1));++	cmd = str[1];++	p0 = str + 2;++	p1 = p0;++	while (*p1 && *p1 != ',') {+		p1++;+	}+	*p1 = '\0';+	p1++;++	p0_val = simple_strtol(p0, NULL, 0);+	p1_val = simple_strtol(p1, NULL, 0);+++	mutex_lock(&yaffs_context_lock);++	/* Locate and print the Nth entry.  Order N-squared but N is small. */+	list_for_each(item, &yaffs_context_list) {+		struct yaffs_linux_context *dc =+		    list_entry(item, struct yaffs_linux_context,+			       context_list);+		struct yaffs_dev *dev = dc->dev;++		if (cmd == 'b') {+			struct yaffs_block_info *bi;++			bi = yaffs_get_block_info(dev,p0_val);++			if(bi) {+				printk("Block %d: state %d, retire %d, use %d, seq %d\n",+					(int)p0_val, bi->block_state,+					bi->needs_retiring, bi->pages_in_use,+					bi->seq_number);+			}+		} else if (cmd == 'c') {+			struct yaffs_obj *obj;+			int nand_chunk;++			obj = yaffs_find_by_number(dev, p0_val);+			if (!obj)+				printk("No obj %d\n", (int)p0_val);+			else {+				if(p1_val == 0)+					nand_chunk = obj->hdr_chunk;+				else+					nand_chunk =+						yaffs_find_chunk_in_file(obj,+							p1_val, NULL);+				printk("Nand chunk for %d:%d is %d\n",+					(int)p0_val, (int)p1_val, nand_chunk);+			}+		}+	}++	mutex_unlock(&yaffs_context_lock);++	return count;+}++static int yaffs_proc_write(struct file *file, const char *buf,+			    unsigned long count, void *data)+{+	if (buf[0] == '.')+		return yaffs_proc_debug_write(file, buf, count, data);+	return yaffs_proc_write_trace_options(file, buf, count, data);+}+#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0)) */++/* 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;++	yaffs_trace(YAFFS_TRACE_ALWAYS,+		"yaffs built " __DATE__ " " __TIME__ " Installing.");++	mutex_init(&yaffs_context_lock);++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0))+	/* Install the proc_fs entries */+	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;+        }+#endif++	/* 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;++	yaffs_trace(YAFFS_TRACE_ALWAYS,+		"yaffs built " __DATE__ " " __TIME__ " removing.");++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0))+	remove_proc_entry("yaffs", YPROC_ROOT);+#endif++	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-2011");+MODULE_LICENSE("GPL");diff -Nur linux-3.15-rc5.orig/fs/yaffs2/yaffs_yaffs1.c linux-3.15-rc5/fs/yaffs2/yaffs_yaffs1.c--- linux-3.15-rc5.orig/fs/yaffs2/yaffs_yaffs1.c	1970-01-01 01:00:00.000000000 +0100+++ linux-3.15-rc5/fs/yaffs2/yaffs_yaffs1.c	2014-05-17 01:53:27.000000000 +0200@@ -0,0 +1,422 @@+/*+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.+ *+ * Copyright (C) 2002-2011 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_yaffs1.h"+#include "yportenv.h"+#include "yaffs_trace.h"+#include "yaffs_bitmap.h"+#include "yaffs_getblockinfo.h"+#include "yaffs_nand.h"+#include "yaffs_attribs.h"++int yaffs1_scan(struct yaffs_dev *dev)+{+	struct yaffs_ext_tags tags;+	int blk;+	int result;+	int chunk;+	int c;+	int deleted;+	enum yaffs_block_state state;+	LIST_HEAD(hard_list);+	struct yaffs_block_info *bi;+	u32 seq_number;+	struct yaffs_obj_hdr *oh;+	struct yaffs_obj *in;+	struct yaffs_obj *parent;+	int alloc_failed = 0;+	struct yaffs_shadow_fixer *shadow_fixers = NULL;+	u8 *chunk_data;++	yaffs_trace(YAFFS_TRACE_SCAN,+		"yaffs1_scan starts  intstartblk %d intendblk %d...",+		dev->internal_start_block, dev->internal_end_block);++	chunk_data = yaffs_get_temp_buffer(dev);++	dev->seq_number = YAFFS_LOWEST_SEQUENCE_NUMBER;++	/* Scan all the blocks to determine their state */+	bi = dev->block_info;+	for (blk = dev->internal_start_block; blk <= dev->internal_end_block;+	     blk++) {+		yaffs_clear_chunk_bits(dev, blk);+		bi->pages_in_use = 0;+		bi->soft_del_pages = 0;++		yaffs_query_init_block_state(dev, blk, &state, &seq_number);++		bi->block_state = state;+		bi->seq_number = seq_number;++		if (bi->seq_number == YAFFS_SEQUENCE_BAD_BLOCK)+			bi->block_state = state = YAFFS_BLOCK_STATE_DEAD;++		yaffs_trace(YAFFS_TRACE_SCAN_DEBUG,+			"Block scanning block %d state %d seq %d",+			blk, state, seq_number);++		if (state == YAFFS_BLOCK_STATE_DEAD) {+			yaffs_trace(YAFFS_TRACE_BAD_BLOCKS,+				"block %d is bad", blk);+		} else if (state == YAFFS_BLOCK_STATE_EMPTY) {+			yaffs_trace(YAFFS_TRACE_SCAN_DEBUG, "Block empty ");+			dev->n_erased_blocks++;+			dev->n_free_chunks += dev->param.chunks_per_block;+		}+		bi++;+	}++	/* For each block.... */+	for (blk = dev->internal_start_block;+	     !alloc_failed && blk <= dev->internal_end_block; blk++) {++		cond_resched();++		bi = yaffs_get_block_info(dev, blk);+		state = bi->block_state;++		deleted = 0;++		/* For each chunk in each block that needs scanning.... */+		for (c = 0;+			!alloc_failed && c < dev->param.chunks_per_block &&+			state == YAFFS_BLOCK_STATE_NEEDS_SCAN; c++) {+			/* Read the tags and decide what to do */+			chunk = blk * dev->param.chunks_per_block + c;++			result = yaffs_rd_chunk_tags_nand(dev, chunk, NULL,+							  &tags);++			/* Let's have a good look at this chunk... */++			if (tags.ecc_result == YAFFS_ECC_RESULT_UNFIXED ||+			    tags.is_deleted) {+				/* YAFFS1 only...+				 * A deleted chunk+				 */+				deleted++;+				dev->n_free_chunks++;+			} else if (!tags.chunk_used) {+				/* 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->n_erased_blocks++;+				} else {+					/* this is the block being allocated */+					yaffs_trace(YAFFS_TRACE_SCAN,+						" Allocating from %d %d",+						blk, c);+					state = YAFFS_BLOCK_STATE_ALLOCATING;+					dev->alloc_block = blk;+					dev->alloc_page = c;+					dev->alloc_block_finder = blk;++				}++				dev->n_free_chunks +=+				    (dev->param.chunks_per_block - c);+			} else if (tags.chunk_id > 0) {+				/* chunk_id > 0 so it is a data chunk... */+				unsigned int endpos;++				yaffs_set_chunk_bit(dev, blk, c);+				bi->pages_in_use++;++				in = yaffs_find_or_create_by_number(dev,+							tags.obj_id,+							YAFFS_OBJECT_TYPE_FILE);+				/* PutChunkIntoFile checks for a clash+				 * (two data chunks with the same chunk_id).+				 */++				if (!in)+					alloc_failed = 1;++				if (in) {+					if (!yaffs_put_chunk_in_file+					    (in, tags.chunk_id, chunk, 1))+						alloc_failed = 1;+				}++				endpos =+				    (tags.chunk_id - 1) *+				    dev->data_bytes_per_chunk ++				    tags.n_bytes;+				if (in &&+				    in->variant_type ==+				     YAFFS_OBJECT_TYPE_FILE &&+				    in->variant.file_variant.scanned_size <+				      endpos) {+					in->variant.file_variant.scanned_size =+					    endpos;+					if (!dev->param.use_header_file_size) {+						in->variant.+						    file_variant.file_size =+						    in->variant.+						    file_variant.scanned_size;+					}++				}+			} else {+				/* chunk_id == 0, so it is an ObjectHeader.+				 * Make the object+				 */+				yaffs_set_chunk_bit(dev, blk, c);+				bi->pages_in_use++;++				result = yaffs_rd_chunk_tags_nand(dev, chunk,+								  chunk_data,+								  NULL);++				oh = (struct yaffs_obj_hdr *)chunk_data;++				in = yaffs_find_by_number(dev, tags.obj_id);+				if (in && in->variant_type != oh->type) {+					/* This should not happen, but somehow+					 * Wev'e ended up with an obj_id that+					 * has been reused but not yet deleted,+					 * and worse still it has changed type.+					 * Delete the old object.+					 */++					yaffs_del_obj(in);+					in = NULL;+				}++				in = yaffs_find_or_create_by_number(dev,+								tags.obj_id,+								oh->type);++				if (!in)+					alloc_failed = 1;++				if (in && oh->shadows_obj > 0) {++					struct yaffs_shadow_fixer *fixer;+					fixer =+						kmalloc(sizeof+						(struct yaffs_shadow_fixer),+						GFP_NOFS);+					if (fixer) {+						fixer->next = shadow_fixers;+						shadow_fixers = fixer;+						fixer->obj_id = tags.obj_id;+						fixer->shadowed_id =+						    oh->shadows_obj;+						yaffs_trace(YAFFS_TRACE_SCAN,+							" Shadow fixer: %d shadows %d",+							fixer->obj_id,+							fixer->shadowed_id);++					}++				}++				if (in && in->valid) {+					/* We have already filled this one.+					 * We have a duplicate and need to+					 * resolve it. */++					unsigned existing_serial = in->serial;+					unsigned new_serial =+					    tags.serial_number;++					if (((existing_serial + 1) & 3) ==+					    new_serial) {+						/* Use new one - destroy the+						 * exisiting one */+						yaffs_chunk_del(dev,+								in->hdr_chunk,+								1, __LINE__);+						in->valid = 0;+					} else {+						/* Use existing - destroy+						 * this one. */+						yaffs_chunk_del(dev, chunk, 1,+								__LINE__);+					}+				}++				if (in && !in->valid &&+				    (tags.obj_id == YAFFS_OBJECTID_ROOT ||+				     tags.obj_id ==+				     YAFFS_OBJECTID_LOSTNFOUND)) {+					/* We only load some info, don't fiddle+					 * with directory structure */+					in->valid = 1;+					in->variant_type = oh->type;++					in->yst_mode = oh->yst_mode;+					yaffs_load_attribs(in, oh);+					in->hdr_chunk = chunk;+					in->serial = tags.serial_number;++				} else if (in && !in->valid) {+					/* we need to load this info */++					in->valid = 1;+					in->variant_type = oh->type;++					in->yst_mode = oh->yst_mode;+					yaffs_load_attribs(in, oh);+					in->hdr_chunk = chunk;+					in->serial = tags.serial_number;++					yaffs_set_obj_name_from_oh(in, oh);+					in->dirty = 0;++					/* directory stuff...+					 * hook up to parent+					 */++					parent =+					    yaffs_find_or_create_by_number+					    (dev, oh->parent_obj_id,+					     YAFFS_OBJECT_TYPE_DIRECTORY);+					if (!parent)+						alloc_failed = 1;+					if (parent && parent->variant_type ==+					    YAFFS_OBJECT_TYPE_UNKNOWN) {+						/* Set up as a directory */+						parent->variant_type =+						    YAFFS_OBJECT_TYPE_DIRECTORY;+						INIT_LIST_HEAD(&parent->+							variant.dir_variant.+							children);+					} else if (!parent ||+						parent->variant_type !=+						YAFFS_OBJECT_TYPE_DIRECTORY) {+						/* Hoosterman, a problem....+						 * We're trying to use a+						 * non-directory as a directory+						 */++						yaffs_trace(YAFFS_TRACE_ERROR,+							"yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."+							);+						parent = dev->lost_n_found;+					}++					yaffs_add_obj_to_dir(parent, in);++					switch (in->variant_type) {+					case YAFFS_OBJECT_TYPE_UNKNOWN:+						/* Todo got a problem */+						break;+					case YAFFS_OBJECT_TYPE_FILE:+						if (dev->param.+						    use_header_file_size)+							in->variant.+							file_variant.file_size+							= yaffs_oh_to_size(oh);+						break;+					case YAFFS_OBJECT_TYPE_HARDLINK:+						in->variant.+						    hardlink_variant.equiv_id =+						    oh->equiv_id;+						list_add(&in->hard_links,+								&hard_list);+						break;+					case YAFFS_OBJECT_TYPE_DIRECTORY:+						/* Do nothing */+						break;+					case YAFFS_OBJECT_TYPE_SPECIAL:+						/* Do nothing */+						break;+					case YAFFS_OBJECT_TYPE_SYMLINK:+						in->variant.symlink_variant.+						    alias =+						    yaffs_clone_str(oh->alias);+						if (!in->variant.+						    symlink_variant.alias)+							alloc_failed = 1;+						break;+					}+				}+			}+		}++		if (state == YAFFS_BLOCK_STATE_NEEDS_SCAN) {+			/* If we got this far while scanning,+			 * then the block is fully allocated. */+			state = YAFFS_BLOCK_STATE_FULL;+		}++		if (state == YAFFS_BLOCK_STATE_ALLOCATING) {+			/* If the block was partially allocated then+			 * treat it as fully allocated. */+			state = YAFFS_BLOCK_STATE_FULL;+			dev->alloc_block = -1;+		}++		bi->block_state = state;++		/* Now let's see if it was dirty */+		if (bi->pages_in_use == 0 &&+		    !bi->has_shrink_hdr &&+		    bi->block_state == YAFFS_BLOCK_STATE_FULL)+			yaffs_block_became_dirty(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_link_fixup(dev, &hard_list);++	/*+	 * Fix up any shadowed objects.+	 * There should not be more than one of these.+	 */+	{+		struct yaffs_shadow_fixer *fixer;+		struct yaffs_obj *obj;++		while (shadow_fixers) {+			fixer = shadow_fixers;+			shadow_fixers = fixer->next;+			/* Complete the rename transaction by deleting the+			 * shadowed object then setting the object header+			 to unshadowed.+			 */+			obj = yaffs_find_by_number(dev, fixer->shadowed_id);+			if (obj)+				yaffs_del_obj(obj);++			obj = yaffs_find_by_number(dev, fixer->obj_id);++			if (obj)+				yaffs_update_oh(obj, NULL, 1, 0, 0, NULL);++			kfree(fixer);+		}+	}++	yaffs_release_temp_buffer(dev, chunk_data);++	if (alloc_failed)+		return YAFFS_FAIL;++	yaffs_trace(YAFFS_TRACE_SCAN, "yaffs1_scan ends");++	return YAFFS_OK;+}diff -Nur linux-3.15-rc5.orig/fs/yaffs2/yaffs_yaffs1.h linux-3.15-rc5/fs/yaffs2/yaffs_yaffs1.h--- linux-3.15-rc5.orig/fs/yaffs2/yaffs_yaffs1.h	1970-01-01 01:00:00.000000000 +0100+++ linux-3.15-rc5/fs/yaffs2/yaffs_yaffs1.h	2014-05-17 01:53:27.000000000 +0200@@ -0,0 +1,22 @@+/*+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.+ *+ * Copyright (C) 2002-2011 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_YAFFS1_H__+#define __YAFFS_YAFFS1_H__++#include "yaffs_guts.h"+int yaffs1_scan(struct yaffs_dev *dev);++#endifdiff -Nur linux-3.15-rc5.orig/fs/yaffs2/yaffs_yaffs2.c linux-3.15-rc5/fs/yaffs2/yaffs_yaffs2.c--- linux-3.15-rc5.orig/fs/yaffs2/yaffs_yaffs2.c	1970-01-01 01:00:00.000000000 +0100+++ linux-3.15-rc5/fs/yaffs2/yaffs_yaffs2.c	2014-05-17 01:53:27.000000000 +0200@@ -0,0 +1,1534 @@+/*+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.+ *+ * Copyright (C) 2002-2011 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_trace.h"+#include "yaffs_yaffs2.h"+#include "yaffs_checkptrw.h"+#include "yaffs_bitmap.h"+#include "yaffs_nand.h"+#include "yaffs_getblockinfo.h"+#include "yaffs_verify.h"+#include "yaffs_attribs.h"+#include "yaffs_summary.h"++/*+ * Checkpoints are really no benefit on very small partitions.+ *+ * To save space on small partitions don't bother with checkpoints unless+ * the partition is at least this big.+ */+#define YAFFS_CHECKPOINT_MIN_BLOCKS 60+#define YAFFS_SMALL_HOLE_THRESHOLD 4++/*+ * Oldest Dirty Sequence Number handling.+ */++/* yaffs_calc_oldest_dirty_seq()+ * yaffs2_find_oldest_dirty_seq()+ * Calculate the oldest dirty sequence number if we don't know it.+ */+void yaffs_calc_oldest_dirty_seq(struct yaffs_dev *dev)+{+	int i;+	unsigned seq;+	unsigned block_no = 0;+	struct yaffs_block_info *b;++	if (!dev->param.is_yaffs2)+		return;++	/* Find the oldest dirty sequence number. */+	seq = dev->seq_number + 1;+	b = dev->block_info;+	for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {+		if (b->block_state == YAFFS_BLOCK_STATE_FULL &&+		    (b->pages_in_use - b->soft_del_pages) <+		    dev->param.chunks_per_block &&+		    b->seq_number < seq) {+			seq = b->seq_number;+			block_no = i;+		}+		b++;+	}++	if (block_no) {+		dev->oldest_dirty_seq = seq;+		dev->oldest_dirty_block = block_no;+	}+}++void yaffs2_find_oldest_dirty_seq(struct yaffs_dev *dev)+{+	if (!dev->param.is_yaffs2)+		return;++	if (!dev->oldest_dirty_seq)+		yaffs_calc_oldest_dirty_seq(dev);+}++/*+ * yaffs_clear_oldest_dirty_seq()+ * Called when a block is erased or marked bad. (ie. when its seq_number+ * becomes invalid). If the value matches the oldest then we clear+ * dev->oldest_dirty_seq to force its recomputation.+ */+void yaffs2_clear_oldest_dirty_seq(struct yaffs_dev *dev,+				   struct yaffs_block_info *bi)+{++	if (!dev->param.is_yaffs2)+		return;++	if (!bi || bi->seq_number == dev->oldest_dirty_seq) {+		dev->oldest_dirty_seq = 0;+		dev->oldest_dirty_block = 0;+	}+}++/*+ * yaffs2_update_oldest_dirty_seq()+ * Update the oldest dirty sequence number whenever we dirty a block.+ * Only do this if the oldest_dirty_seq is actually being tracked.+ */+void yaffs2_update_oldest_dirty_seq(struct yaffs_dev *dev, unsigned block_no,+				    struct yaffs_block_info *bi)+{+	if (!dev->param.is_yaffs2)+		return;++	if (dev->oldest_dirty_seq) {+		if (dev->oldest_dirty_seq > bi->seq_number) {+			dev->oldest_dirty_seq = bi->seq_number;+			dev->oldest_dirty_block = block_no;+		}+	}+}++int yaffs_block_ok_for_gc(struct yaffs_dev *dev, struct yaffs_block_info *bi)+{++	if (!dev->param.is_yaffs2)+		return 1;	/* disqualification only applies to yaffs2. */++	if (!bi->has_shrink_hdr)+		return 1;	/* can gc */++	yaffs2_find_oldest_dirty_seq(dev);++	/* Can't do gc of this block if there are any blocks older than this+	 * one that have discarded pages.+	 */+	return (bi->seq_number <= dev->oldest_dirty_seq);+}++/*+ * yaffs2_find_refresh_block()+ * periodically finds the oldest full block by sequence number for refreshing.+ * Only for yaffs2.+ */+u32 yaffs2_find_refresh_block(struct yaffs_dev *dev)+{+	u32 b;+	u32 oldest = 0;+	u32 oldest_seq = 0;+	struct yaffs_block_info *bi;++	if (!dev->param.is_yaffs2)+		return oldest;++	/*+	 * If refresh period < 10 then refreshing is disabled.+	 */+	if (dev->param.refresh_period < 10)+		return oldest;++	/*+	 * Fix broken values.+	 */+	if (dev->refresh_skip > dev->param.refresh_period)+		dev->refresh_skip = dev->param.refresh_period;++	if (dev->refresh_skip > 0)+		return oldest;++	/*+	 * Refresh skip is now zero.+	 * We'll do a refresh this time around....+	 * Update the refresh skip and find the oldest block.+	 */+	dev->refresh_skip = dev->param.refresh_period;+	dev->refresh_count++;+	bi = dev->block_info;+	for (b = dev->internal_start_block; b <= dev->internal_end_block; b++) {++		if (bi->block_state == YAFFS_BLOCK_STATE_FULL) {++			if (oldest < 1 || bi->seq_number < oldest_seq) {+				oldest = b;+				oldest_seq = bi->seq_number;+			}+		}+		bi++;+	}++	if (oldest > 0) {+		yaffs_trace(YAFFS_TRACE_GC,+			"GC refresh count %d selected block %d with seq_number %d",+			dev->refresh_count, oldest, oldest_seq);+	}++	return oldest;+}++int yaffs2_checkpt_required(struct yaffs_dev *dev)+{+	int nblocks;++	if (!dev->param.is_yaffs2)+		return 0;++	nblocks = dev->internal_end_block - dev->internal_start_block + 1;++	return !dev->param.skip_checkpt_wr &&+	    !dev->read_only && (nblocks >= YAFFS_CHECKPOINT_MIN_BLOCKS);+}++int yaffs_calc_checkpt_blocks_required(struct yaffs_dev *dev)+{+	int retval;+	int n_bytes = 0;+	int n_blocks;+	int dev_blocks;++	if (!dev->param.is_yaffs2)+		return 0;++	if (!dev->checkpoint_blocks_required && yaffs2_checkpt_required(dev)) {+		/* Not a valid value so recalculate */+		dev_blocks = dev->param.end_block - dev->param.start_block + 1;+		n_bytes += sizeof(struct yaffs_checkpt_validity);+		n_bytes += sizeof(struct yaffs_checkpt_dev);+		n_bytes += dev_blocks * sizeof(struct yaffs_block_info);+		n_bytes += dev_blocks * dev->chunk_bit_stride;+		n_bytes +=+		    (sizeof(struct yaffs_checkpt_obj) + sizeof(u32)) *+		    dev->n_obj;+		n_bytes += (dev->tnode_size + sizeof(u32)) * dev->n_tnodes;+		n_bytes += sizeof(struct yaffs_checkpt_validity);+		n_bytes += sizeof(u32);	/* checksum */++		/* Round up and add 2 blocks to allow for some bad blocks,+		 * so add 3 */++		n_blocks =+		    (n_bytes /+		     (dev->data_bytes_per_chunk *+		      dev->param.chunks_per_block)) + 3;++		dev->checkpoint_blocks_required = n_blocks;+	}++	retval = dev->checkpoint_blocks_required - dev->blocks_in_checkpt;+	if (retval < 0)+		retval = 0;+	return retval;+}++/*--------------------- Checkpointing --------------------*/++static int yaffs2_wr_checkpt_validity_marker(struct yaffs_dev *dev, int head)+{+	struct yaffs_checkpt_validity cp;++	memset(&cp, 0, sizeof(cp));++	cp.struct_type = sizeof(cp);+	cp.magic = YAFFS_MAGIC;+	cp.version = YAFFS_CHECKPOINT_VERSION;+	cp.head = (head) ? 1 : 0;++	return (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp)) ? 1 : 0;+}++static int yaffs2_rd_checkpt_validity_marker(struct yaffs_dev *dev, int head)+{+	struct yaffs_checkpt_validity cp;+	int ok;++	ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp));++	if (ok)+		ok = (cp.struct_type == sizeof(cp)) &&+		    (cp.magic == YAFFS_MAGIC) &&+		    (cp.version == YAFFS_CHECKPOINT_VERSION) &&+		    (cp.head == ((head) ? 1 : 0));+	return ok ? 1 : 0;+}++static void yaffs2_dev_to_checkpt_dev(struct yaffs_checkpt_dev *cp,+				      struct yaffs_dev *dev)+{+	cp->n_erased_blocks = dev->n_erased_blocks;+	cp->alloc_block = dev->alloc_block;+	cp->alloc_page = dev->alloc_page;+	cp->n_free_chunks = dev->n_free_chunks;++	cp->n_deleted_files = dev->n_deleted_files;+	cp->n_unlinked_files = dev->n_unlinked_files;+	cp->n_bg_deletions = dev->n_bg_deletions;+	cp->seq_number = dev->seq_number;++}++static void yaffs_checkpt_dev_to_dev(struct yaffs_dev *dev,+				     struct yaffs_checkpt_dev *cp)+{+	dev->n_erased_blocks = cp->n_erased_blocks;+	dev->alloc_block = cp->alloc_block;+	dev->alloc_page = cp->alloc_page;+	dev->n_free_chunks = cp->n_free_chunks;++	dev->n_deleted_files = cp->n_deleted_files;+	dev->n_unlinked_files = cp->n_unlinked_files;+	dev->n_bg_deletions = cp->n_bg_deletions;+	dev->seq_number = cp->seq_number;+}++static int yaffs2_wr_checkpt_dev(struct yaffs_dev *dev)+{+	struct yaffs_checkpt_dev cp;+	u32 n_bytes;+	u32 n_blocks = dev->internal_end_block - dev->internal_start_block + 1;+	int ok;++	/* Write device runtime values */+	yaffs2_dev_to_checkpt_dev(&cp, dev);+	cp.struct_type = sizeof(cp);++	ok = (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp));+	if (!ok)+		return 0;++	/* Write block info */+	n_bytes = n_blocks * sizeof(struct yaffs_block_info);+	ok = (yaffs2_checkpt_wr(dev, dev->block_info, n_bytes) == n_bytes);+	if (!ok)+		return 0;++	/* Write chunk bits */+	n_bytes = n_blocks * dev->chunk_bit_stride;+	ok = (yaffs2_checkpt_wr(dev, dev->chunk_bits, n_bytes) == n_bytes);++	return ok ? 1 : 0;+}++static int yaffs2_rd_checkpt_dev(struct yaffs_dev *dev)+{+	struct yaffs_checkpt_dev cp;+	u32 n_bytes;+	u32 n_blocks =+	    (dev->internal_end_block - dev->internal_start_block + 1);+	int ok;++	ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp));+	if (!ok)+		return 0;++	if (cp.struct_type != sizeof(cp))+		return 0;++	yaffs_checkpt_dev_to_dev(dev, &cp);++	n_bytes = n_blocks * sizeof(struct yaffs_block_info);++	ok = (yaffs2_checkpt_rd(dev, dev->block_info, n_bytes) == n_bytes);++	if (!ok)+		return 0;++	n_bytes = n_blocks * dev->chunk_bit_stride;++	ok = (yaffs2_checkpt_rd(dev, dev->chunk_bits, n_bytes) == n_bytes);++	return ok ? 1 : 0;+}++static void yaffs2_obj_checkpt_obj(struct yaffs_checkpt_obj *cp,+				   struct yaffs_obj *obj)+{+	cp->obj_id = obj->obj_id;+	cp->parent_id = (obj->parent) ? obj->parent->obj_id : 0;+	cp->hdr_chunk = obj->hdr_chunk;+	cp->variant_type = obj->variant_type;+	cp->deleted = obj->deleted;+	cp->soft_del = obj->soft_del;+	cp->unlinked = obj->unlinked;+	cp->fake = obj->fake;+	cp->rename_allowed = obj->rename_allowed;+	cp->unlink_allowed = obj->unlink_allowed;+	cp->serial = obj->serial;+	cp->n_data_chunks = obj->n_data_chunks;++	if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE)+		cp->size_or_equiv_obj = obj->variant.file_variant.file_size;+	else if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK)+		cp->size_or_equiv_obj = obj->variant.hardlink_variant.equiv_id;+}++static int yaffs2_checkpt_obj_to_obj(struct yaffs_obj *obj,+				     struct yaffs_checkpt_obj *cp)+{+	struct yaffs_obj *parent;++	if (obj->variant_type != cp->variant_type) {+		yaffs_trace(YAFFS_TRACE_ERROR,+			"Checkpoint read object %d type %d chunk %d does not match existing object type %d",+			cp->obj_id, cp->variant_type, cp->hdr_chunk,+			obj->variant_type);+		return 0;+	}++	obj->obj_id = cp->obj_id;++	if (cp->parent_id)+		parent = yaffs_find_or_create_by_number(obj->my_dev,+						cp->parent_id,+						YAFFS_OBJECT_TYPE_DIRECTORY);+	else+		parent = NULL;++	if (parent) {+		if (parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {+			yaffs_trace(YAFFS_TRACE_ALWAYS,+				"Checkpoint read object %d parent %d type %d chunk %d Parent type, %d, not directory",+				cp->obj_id, cp->parent_id,+				cp->variant_type, cp->hdr_chunk,+				parent->variant_type);+			return 0;+		}+		yaffs_add_obj_to_dir(parent, obj);+	}++	obj->hdr_chunk = cp->hdr_chunk;+	obj->variant_type = cp->variant_type;+	obj->deleted = cp->deleted;+	obj->soft_del = cp->soft_del;+	obj->unlinked = cp->unlinked;+	obj->fake = cp->fake;+	obj->rename_allowed = cp->rename_allowed;+	obj->unlink_allowed = cp->unlink_allowed;+	obj->serial = cp->serial;+	obj->n_data_chunks = cp->n_data_chunks;++	if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE)+		obj->variant.file_variant.file_size = cp->size_or_equiv_obj;+	else if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK)+		obj->variant.hardlink_variant.equiv_id = cp->size_or_equiv_obj;++	if (obj->hdr_chunk > 0)+		obj->lazy_loaded = 1;+	return 1;+}++static int yaffs2_checkpt_tnode_worker(struct yaffs_obj *in,+				       struct yaffs_tnode *tn, u32 level,+				       int chunk_offset)+{+	int i;+	struct yaffs_dev *dev = in->my_dev;+	int ok = 1;+	u32 base_offset;++	if (!tn)+		return 1;++	if (level > 0) {+		for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) {+			if (!tn->internal[i])+				continue;+			ok = yaffs2_checkpt_tnode_worker(in,+				 tn->internal[i],+				 level - 1,+				 (chunk_offset <<+				  YAFFS_TNODES_INTERNAL_BITS) + i);+		}+		return ok;+	}++	/* Level 0 tnode */+	base_offset = chunk_offset << YAFFS_TNODES_LEVEL0_BITS;+	ok = (yaffs2_checkpt_wr(dev, &base_offset, sizeof(base_offset)) ==+			sizeof(base_offset));+	if (ok)+		ok = (yaffs2_checkpt_wr(dev, tn, dev->tnode_size) ==+			dev->tnode_size);++	return ok;+}++static int yaffs2_wr_checkpt_tnodes(struct yaffs_obj *obj)+{+	u32 end_marker = ~0;+	int ok = 1;++	if (obj->variant_type != YAFFS_OBJECT_TYPE_FILE)+		return ok;++	ok = yaffs2_checkpt_tnode_worker(obj,+					 obj->variant.file_variant.top,+					 obj->variant.file_variant.+					 top_level, 0);+	if (ok)+		ok = (yaffs2_checkpt_wr(obj->my_dev, &end_marker,+				sizeof(end_marker)) == sizeof(end_marker));++	return ok ? 1 : 0;+}++static int yaffs2_rd_checkpt_tnodes(struct yaffs_obj *obj)+{+	u32 base_chunk;+	int ok = 1;+	struct yaffs_dev *dev = obj->my_dev;+	struct yaffs_file_var *file_stuct_ptr = &obj->variant.file_variant;+	struct yaffs_tnode *tn;+	int nread = 0;++	ok = (yaffs2_checkpt_rd(dev, &base_chunk, sizeof(base_chunk)) ==+	      sizeof(base_chunk));++	while (ok && (~base_chunk)) {+		nread++;+		/* Read level 0 tnode */++		tn = yaffs_get_tnode(dev);+		if (tn)+			ok = (yaffs2_checkpt_rd(dev, tn, dev->tnode_size) ==+				dev->tnode_size);+		else+			ok = 0;++		if (tn && ok)+			ok = yaffs_add_find_tnode_0(dev,+						    file_stuct_ptr,+						    base_chunk, tn) ? 1 : 0;++		if (ok)+			ok = (yaffs2_checkpt_rd+			      (dev, &base_chunk,+			       sizeof(base_chunk)) == sizeof(base_chunk));+	}++	yaffs_trace(YAFFS_TRACE_CHECKPOINT,+		"Checkpoint read tnodes %d records, last %d. ok %d",+		nread, base_chunk, ok);++	return ok ? 1 : 0;+}++static int yaffs2_wr_checkpt_objs(struct yaffs_dev *dev)+{+	struct yaffs_obj *obj;+	struct yaffs_checkpt_obj cp;+	int i;+	int ok = 1;+	struct list_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++) {+		list_for_each(lh, &dev->obj_bucket[i].list) {+			obj = list_entry(lh, struct yaffs_obj, hash_link);+			if (!obj->defered_free) {+				yaffs2_obj_checkpt_obj(&cp, obj);+				cp.struct_type = sizeof(cp);++				yaffs_trace(YAFFS_TRACE_CHECKPOINT,+					"Checkpoint write object %d parent %d type %d chunk %d obj addr %p",+					cp.obj_id, cp.parent_id,+					cp.variant_type, cp.hdr_chunk, obj);++				ok = (yaffs2_checkpt_wr(dev, &cp,+						sizeof(cp)) == sizeof(cp));++				if (ok &&+					obj->variant_type ==+					YAFFS_OBJECT_TYPE_FILE)+					ok = yaffs2_wr_checkpt_tnodes(obj);+			}+		}+	}++	/* Dump end of list */+	memset(&cp, 0xff, sizeof(struct yaffs_checkpt_obj));+	cp.struct_type = sizeof(cp);++	if (ok)+		ok = (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp));++	return ok ? 1 : 0;+}++static int yaffs2_rd_checkpt_objs(struct yaffs_dev *dev)+{+	struct yaffs_obj *obj;+	struct yaffs_checkpt_obj cp;+	int ok = 1;+	int done = 0;+	LIST_HEAD(hard_list);+++	while (ok && !done) {+		ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp));+		if (cp.struct_type != sizeof(cp)) {+			yaffs_trace(YAFFS_TRACE_CHECKPOINT,+				"struct size %d instead of %d ok %d",+				cp.struct_type, (int)sizeof(cp), ok);+			ok = 0;+		}++		yaffs_trace(YAFFS_TRACE_CHECKPOINT,+			"Checkpoint read object %d parent %d type %d chunk %d ",+			cp.obj_id, cp.parent_id, cp.variant_type,+			cp.hdr_chunk);++		if (ok && cp.obj_id == ~0) {+			done = 1;+		} else if (ok) {+			obj =+			    yaffs_find_or_create_by_number(dev, cp.obj_id,+							   cp.variant_type);+			if (obj) {+				ok = yaffs2_checkpt_obj_to_obj(obj, &cp);+				if (!ok)+					break;+				if (obj->variant_type ==+					YAFFS_OBJECT_TYPE_FILE) {+					ok = yaffs2_rd_checkpt_tnodes(obj);+				} else if (obj->variant_type ==+					YAFFS_OBJECT_TYPE_HARDLINK) {+					list_add(&obj->hard_links, &hard_list);+				}+			} else {+				ok = 0;+			}+		}+	}++	if (ok)+		yaffs_link_fixup(dev, &hard_list);++	return ok ? 1 : 0;+}++static int yaffs2_wr_checkpt_sum(struct yaffs_dev *dev)+{+	u32 checkpt_sum;+	int ok;++	yaffs2_get_checkpt_sum(dev, &checkpt_sum);++	ok = (yaffs2_checkpt_wr(dev, &checkpt_sum, sizeof(checkpt_sum)) ==+		sizeof(checkpt_sum));++	if (!ok)+		return 0;++	return 1;+}++static int yaffs2_rd_checkpt_sum(struct yaffs_dev *dev)+{+	u32 checkpt_sum0;+	u32 checkpt_sum1;+	int ok;++	yaffs2_get_checkpt_sum(dev, &checkpt_sum0);++	ok = (yaffs2_checkpt_rd(dev, &checkpt_sum1, sizeof(checkpt_sum1)) ==+		sizeof(checkpt_sum1));++	if (!ok)+		return 0;++	if (checkpt_sum0 != checkpt_sum1)+		return 0;++	return 1;+}++static int yaffs2_wr_checkpt_data(struct yaffs_dev *dev)+{+	int ok = 1;++	if (!yaffs2_checkpt_required(dev)) {+		yaffs_trace(YAFFS_TRACE_CHECKPOINT,+			"skipping checkpoint write");+		ok = 0;+	}++	if (ok)+		ok = yaffs2_checkpt_open(dev, 1);++	if (ok) {+		yaffs_trace(YAFFS_TRACE_CHECKPOINT,+			"write checkpoint validity");+		ok = yaffs2_wr_checkpt_validity_marker(dev, 1);+	}+	if (ok) {+		yaffs_trace(YAFFS_TRACE_CHECKPOINT,+			"write checkpoint device");+		ok = yaffs2_wr_checkpt_dev(dev);+	}+	if (ok) {+		yaffs_trace(YAFFS_TRACE_CHECKPOINT,+			"write checkpoint objects");+		ok = yaffs2_wr_checkpt_objs(dev);+	}+	if (ok) {+		yaffs_trace(YAFFS_TRACE_CHECKPOINT,+			"write checkpoint validity");+		ok = yaffs2_wr_checkpt_validity_marker(dev, 0);+	}++	if (ok)+		ok = yaffs2_wr_checkpt_sum(dev);++	if (!yaffs_checkpt_close(dev))+		ok = 0;++	if (ok)+		dev->is_checkpointed = 1;+	else+		dev->is_checkpointed = 0;++	return dev->is_checkpointed;+}++static int yaffs2_rd_checkpt_data(struct yaffs_dev *dev)+{+	int ok = 1;++	if (!dev->param.is_yaffs2)+		ok = 0;++	if (ok && dev->param.skip_checkpt_rd) {+		yaffs_trace(YAFFS_TRACE_CHECKPOINT,+			"skipping checkpoint read");+		ok = 0;+	}++	if (ok)+		ok = yaffs2_checkpt_open(dev, 0); /* open for read */++	if (ok) {+		yaffs_trace(YAFFS_TRACE_CHECKPOINT,+			"read checkpoint validity");+		ok = yaffs2_rd_checkpt_validity_marker(dev, 1);+	}+	if (ok) {+		yaffs_trace(YAFFS_TRACE_CHECKPOINT,+			"read checkpoint device");+		ok = yaffs2_rd_checkpt_dev(dev);+	}+	if (ok) {+		yaffs_trace(YAFFS_TRACE_CHECKPOINT,+			"read checkpoint objects");+		ok = yaffs2_rd_checkpt_objs(dev);+	}+	if (ok) {+		yaffs_trace(YAFFS_TRACE_CHECKPOINT,+			"read checkpoint validity");+		ok = yaffs2_rd_checkpt_validity_marker(dev, 0);+	}++	if (ok) {+		ok = yaffs2_rd_checkpt_sum(dev);+		yaffs_trace(YAFFS_TRACE_CHECKPOINT,+			"read checkpoint checksum %d", ok);+	}++	if (!yaffs_checkpt_close(dev))+		ok = 0;++	if (ok)+		dev->is_checkpointed = 1;+	else+		dev->is_checkpointed = 0;++	return ok ? 1 : 0;+}++void yaffs2_checkpt_invalidate(struct yaffs_dev *dev)+{+	if (dev->is_checkpointed || dev->blocks_in_checkpt > 0) {+		dev->is_checkpointed = 0;+		yaffs2_checkpt_invalidate_stream(dev);+	}+	if (dev->param.sb_dirty_fn)+		dev->param.sb_dirty_fn(dev);+}++int yaffs_checkpoint_save(struct yaffs_dev *dev)+{+	yaffs_trace(YAFFS_TRACE_CHECKPOINT,+		"save entry: is_checkpointed %d",+		dev->is_checkpointed);++	yaffs_verify_objects(dev);+	yaffs_verify_blocks(dev);+	yaffs_verify_free_chunks(dev);++	if (!dev->is_checkpointed) {+		yaffs2_checkpt_invalidate(dev);+		yaffs2_wr_checkpt_data(dev);+	}++	yaffs_trace(YAFFS_TRACE_CHECKPOINT | YAFFS_TRACE_MOUNT,+		"save exit: is_checkpointed %d",+		dev->is_checkpointed);++	return dev->is_checkpointed;+}++int yaffs2_checkpt_restore(struct yaffs_dev *dev)+{+	int retval;++	yaffs_trace(YAFFS_TRACE_CHECKPOINT,+		"restore entry: is_checkpointed %d",+		dev->is_checkpointed);++	retval = yaffs2_rd_checkpt_data(dev);++	if (dev->is_checkpointed) {+		yaffs_verify_objects(dev);+		yaffs_verify_blocks(dev);+		yaffs_verify_free_chunks(dev);+	}++	yaffs_trace(YAFFS_TRACE_CHECKPOINT,+		"restore exit: is_checkpointed %d",+		dev->is_checkpointed);++	return retval;+}++int yaffs2_handle_hole(struct yaffs_obj *obj, loff_t new_size)+{+	/* if new_size > old_file_size.+	 * We're going to be writing a hole.+	 * If the hole is small then write zeros otherwise write a start+	 * of hole marker.+	 */+	loff_t old_file_size;+	loff_t increase;+	int small_hole;+	int result = YAFFS_OK;+	struct yaffs_dev *dev = NULL;+	u8 *local_buffer = NULL;+	int small_increase_ok = 0;++	if (!obj)+		return YAFFS_FAIL;++	if (obj->variant_type != YAFFS_OBJECT_TYPE_FILE)+		return YAFFS_FAIL;++	dev = obj->my_dev;++	/* Bail out if not yaffs2 mode */+	if (!dev->param.is_yaffs2)+		return YAFFS_OK;++	old_file_size = obj->variant.file_variant.file_size;++	if (new_size <= old_file_size)+		return YAFFS_OK;++	increase = new_size - old_file_size;++	if (increase < YAFFS_SMALL_HOLE_THRESHOLD * dev->data_bytes_per_chunk &&+	    yaffs_check_alloc_available(dev, YAFFS_SMALL_HOLE_THRESHOLD + 1))+		small_hole = 1;+	else+		small_hole = 0;++	if (small_hole)+		local_buffer = yaffs_get_temp_buffer(dev);++	if (local_buffer) {+		/* fill hole with zero bytes */+		loff_t pos = old_file_size;+		int this_write;+		int written;+		memset(local_buffer, 0, dev->data_bytes_per_chunk);+		small_increase_ok = 1;++		while (increase > 0 && small_increase_ok) {+			this_write = increase;+			if (this_write > dev->data_bytes_per_chunk)+				this_write = dev->data_bytes_per_chunk;+			written =+			    yaffs_do_file_wr(obj, local_buffer, pos, this_write,+					     0);+			if (written == this_write) {+				pos += this_write;+				increase -= this_write;+			} else {+				small_increase_ok = 0;+			}+		}++		yaffs_release_temp_buffer(dev, local_buffer);++		/* If out of space then reverse any chunks we've added */+		if (!small_increase_ok)+			yaffs_resize_file_down(obj, old_file_size);+	}++	if (!small_increase_ok &&+	    obj->parent &&+	    obj->parent->obj_id != YAFFS_OBJECTID_UNLINKED &&+	    obj->parent->obj_id != YAFFS_OBJECTID_DELETED) {+		/* Write a hole start header with the old file size */+		yaffs_update_oh(obj, NULL, 0, 1, 0, NULL);+	}++	return result;+}++struct yaffs_block_index {+	int seq;+	int block;+};++static int yaffs2_ybicmp(const void *a, const void *b)+{+	int aseq = ((struct yaffs_block_index *)a)->seq;+	int bseq = ((struct yaffs_block_index *)b)->seq;+	int ablock = ((struct yaffs_block_index *)a)->block;+	int bblock = ((struct yaffs_block_index *)b)->block;++	if (aseq == bseq)+		return ablock - bblock;++	return aseq - bseq;+}++static inline int yaffs2_scan_chunk(struct yaffs_dev *dev,+		struct yaffs_block_info *bi,+		int blk, int chunk_in_block,+		int *found_chunks,+		u8 *chunk_data,+		struct list_head *hard_list,+		int summary_available)+{+	struct yaffs_obj_hdr *oh;+	struct yaffs_obj *in;+	struct yaffs_obj *parent;+	int equiv_id;+	loff_t file_size;+	int is_shrink;+	int is_unlinked;+	struct yaffs_ext_tags tags;+	int result;+	int alloc_failed = 0;+	int chunk = blk * dev->param.chunks_per_block + chunk_in_block;+	struct yaffs_file_var *file_var;+	struct yaffs_hardlink_var *hl_var;+	struct yaffs_symlink_var *sl_var;++	if (summary_available) {+		result = yaffs_summary_fetch(dev, &tags, chunk_in_block);+		tags.seq_number = bi->seq_number;+	}++	if (!summary_available || tags.obj_id == 0) {+		result = yaffs_rd_chunk_tags_nand(dev, chunk, NULL, &tags);+		dev->tags_used++;+	} else {+		dev->summary_used++;+	}++	/* Let's have a good look at this chunk... */++	if (!tags.chunk_used) {+		/* 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 (*found_chunks) {+			/* This is a chunk that was skipped due+			 * to failing the erased check */+		} else if (chunk_in_block == 0) {+			/* We're looking at the first chunk in+			 * the block so the block is unused */+			bi->block_state = YAFFS_BLOCK_STATE_EMPTY;+			dev->n_erased_blocks++;+		} else {+			if (bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCAN ||+			    bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING) {+				if (dev->seq_number == bi->seq_number) {+					/* Allocating from this block*/+					yaffs_trace(YAFFS_TRACE_SCAN,+					    " Allocating from %d %d",+					    blk, chunk_in_block);++					bi->block_state =+						YAFFS_BLOCK_STATE_ALLOCATING;+					dev->alloc_block = blk;+					dev->alloc_page = chunk_in_block;+					dev->alloc_block_finder = blk;+				} else {+					/* This is a partially written block+					 * that is not the current+					 * allocation block.+					 */+					yaffs_trace(YAFFS_TRACE_SCAN,+						"Partially written block %d detected. gc will fix this.",+						blk);+				}+			}+		}++		dev->n_free_chunks++;++	} else if (tags.ecc_result ==+		YAFFS_ECC_RESULT_UNFIXED) {+		yaffs_trace(YAFFS_TRACE_SCAN,+			" Unfixed ECC in chunk(%d:%d), chunk ignored",+			blk, chunk_in_block);+			dev->n_free_chunks++;+	} else if (tags.obj_id > YAFFS_MAX_OBJECT_ID ||+		   tags.chunk_id > YAFFS_MAX_CHUNK_ID ||+		   tags.obj_id == YAFFS_OBJECTID_SUMMARY ||+		   (tags.chunk_id > 0 &&+		     tags.n_bytes > dev->data_bytes_per_chunk) ||+		   tags.seq_number != bi->seq_number) {+		yaffs_trace(YAFFS_TRACE_SCAN,+			"Chunk (%d:%d) with bad tags:obj = %d, chunk_id = %d, n_bytes = %d, ignored",+			blk, chunk_in_block, tags.obj_id,+			tags.chunk_id, tags.n_bytes);+		dev->n_free_chunks++;+	} else if (tags.chunk_id > 0) {+		/* chunk_id > 0 so it is a data chunk... */+		loff_t endpos;+		loff_t chunk_base = (tags.chunk_id - 1) *+					dev->data_bytes_per_chunk;++		*found_chunks = 1;++		yaffs_set_chunk_bit(dev, blk, chunk_in_block);+		bi->pages_in_use++;++		in = yaffs_find_or_create_by_number(dev,+					tags.obj_id,+					YAFFS_OBJECT_TYPE_FILE);+		if (!in)+			/* Out of memory */+			alloc_failed = 1;++		if (in &&+		    in->variant_type == YAFFS_OBJECT_TYPE_FILE &&+		    chunk_base < in->variant.file_variant.shrink_size) {+			/* This has not been invalidated by+			 * a resize */+			if (!yaffs_put_chunk_in_file(in, tags.chunk_id,+								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 = chunk_base + tags.n_bytes;++			if (!in->valid &&+			    in->variant.file_variant.scanned_size < endpos) {+				in->variant.file_variant.+				    scanned_size = endpos;+				in->variant.file_variant.+				    file_size = endpos;+			}+		} else if (in) {+			/* This chunk has been invalidated by a+			 * resize, or a past file deletion+			 * so delete the chunk*/+			yaffs_chunk_del(dev, chunk, 1, __LINE__);+		}+	} else {+		/* chunk_id == 0, so it is an ObjectHeader.+		 * Thus, we read in the object header and make+		 * the object+		 */+		*found_chunks = 1;++		yaffs_set_chunk_bit(dev, blk, chunk_in_block);+		bi->pages_in_use++;++		oh = NULL;+		in = NULL;++		if (tags.extra_available) {+			in = yaffs_find_or_create_by_number(dev,+					tags.obj_id,+					tags.extra_obj_type);+			if (!in)+				alloc_failed = 1;+		}++		if (!in ||+		    (!in->valid && dev->param.disable_lazy_load) ||+		    tags.extra_shadows ||+		    (!in->valid && (tags.obj_id == YAFFS_OBJECTID_ROOT ||+				 tags.obj_id == 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_rd_chunk_tags_nand(dev,+						  chunk,+						  chunk_data,+						  NULL);++			oh = (struct yaffs_obj_hdr *)chunk_data;++			if (dev->param.inband_tags) {+				/* Fix up the header if they got+				 * corrupted by inband tags */+				oh->shadows_obj =+				    oh->inband_shadowed_obj_id;+				oh->is_shrink =+				    oh->inband_is_shrink;+			}++			if (!in) {+				in = yaffs_find_or_create_by_number(dev,+							tags.obj_id, oh->type);+				if (!in)+					alloc_failed = 1;+			}+		}++		if (!in) {+			/* TODO Hoosterman we have a problem! */+			yaffs_trace(YAFFS_TRACE_ERROR,+				"yaffs tragedy: Could not make object for object  %d at chunk %d during scan",+				tags.obj_id, chunk);+			return YAFFS_FAIL;+		}++		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->variant_type == YAFFS_OBJECT_TYPE_FILE) &&+				((oh && oh->type == YAFFS_OBJECT_TYPE_FILE) ||+				 (tags.extra_available &&+				  tags.extra_obj_type == YAFFS_OBJECT_TYPE_FILE)+				)) {+				loff_t this_size = (oh) ?+					yaffs_oh_to_size(oh) :+					tags.extra_file_size;+				u32 parent_obj_id = (oh) ?+					oh->parent_obj_id :+					tags.extra_parent_id;++				is_shrink = (oh) ?+					oh->is_shrink :+					tags.extra_is_shrink;++				/* If it is deleted (unlinked+				 * at start also means deleted)+				 * we treat the file size as+				 * being zeroed at this point.+				 */+				if (parent_obj_id == YAFFS_OBJECTID_DELETED ||+				    parent_obj_id == YAFFS_OBJECTID_UNLINKED) {+					this_size = 0;+					is_shrink = 1;+				}++				if (is_shrink &&+				    in->variant.file_variant.shrink_size >+				    this_size)+					in->variant.file_variant.shrink_size =+					this_size;++				if (is_shrink)+					bi->has_shrink_hdr = 1;+			}+			/* Use existing - destroy this one. */+			yaffs_chunk_del(dev, chunk, 1, __LINE__);+		}++		if (!in->valid && in->variant_type !=+		    (oh ? oh->type : tags.extra_obj_type)) {+			yaffs_trace(YAFFS_TRACE_ERROR,+				"yaffs tragedy: Bad type, %d != %d, for object %d at chunk %d during scan",+				oh ? oh->type : tags.extra_obj_type,+				in->variant_type, tags.obj_id,+				chunk);+			in = yaffs_retype_obj(in, oh ? oh->type : tags.extra_obj_type);+		}++		if (!in->valid &&+		    (tags.obj_id == YAFFS_OBJECTID_ROOT ||+		     tags.obj_id == YAFFS_OBJECTID_LOSTNFOUND)) {+			/* We only load some info, don't fiddle+			 * with directory structure */+			in->valid = 1;++			if (oh) {+				in->yst_mode = oh->yst_mode;+				yaffs_load_attribs(in, oh);+				in->lazy_loaded = 0;+			} else {+				in->lazy_loaded = 1;+			}+			in->hdr_chunk = chunk;++		} else if (!in->valid) {+			/* we need to load this info */+			in->valid = 1;+			in->hdr_chunk = chunk;+			if (oh) {+				in->variant_type = oh->type;+				in->yst_mode = oh->yst_mode;+				yaffs_load_attribs(in, oh);++				if (oh->shadows_obj > 0)+					yaffs_handle_shadowed_obj(dev,+					     oh->shadows_obj, 1);++				yaffs_set_obj_name_from_oh(in, oh);+				parent = yaffs_find_or_create_by_number(dev,+						oh->parent_obj_id,+						YAFFS_OBJECT_TYPE_DIRECTORY);+				file_size = yaffs_oh_to_size(oh);+				is_shrink = oh->is_shrink;+				equiv_id = oh->equiv_id;+			} else {+				in->variant_type = tags.extra_obj_type;+				parent = yaffs_find_or_create_by_number(dev,+						tags.extra_parent_id,+						YAFFS_OBJECT_TYPE_DIRECTORY);+				file_size = tags.extra_file_size;+				is_shrink = tags.extra_is_shrink;+				equiv_id = tags.extra_equiv_id;+				in->lazy_loaded = 1;+			}+			in->dirty = 0;++			if (!parent)+				alloc_failed = 1;++			/* directory stuff...+			 * hook up to parent+			 */++			if (parent &&+			    parent->variant_type == YAFFS_OBJECT_TYPE_UNKNOWN) {+				/* Set up as a directory */+				parent->variant_type =+					YAFFS_OBJECT_TYPE_DIRECTORY;+				INIT_LIST_HEAD(&parent->+						variant.dir_variant.children);+			} else if (!parent ||+				   parent->variant_type !=+					YAFFS_OBJECT_TYPE_DIRECTORY) {+				/* Hoosterman, another problem....+				 * Trying to use a non-directory as a directory+				 */++				yaffs_trace(YAFFS_TRACE_ERROR,+					"yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."+					);+				parent = dev->lost_n_found;+			}+			yaffs_add_obj_to_dir(parent, in);++			is_unlinked = (parent == dev->del_dir) ||+					(parent == dev->unlinked_dir);++			if (is_shrink)+				/* Mark the block */+				bi->has_shrink_hdr = 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->variant_type) {+			case YAFFS_OBJECT_TYPE_UNKNOWN:+				/* Todo got a problem */+				break;+			case YAFFS_OBJECT_TYPE_FILE:+				file_var = &in->variant.file_variant;+				if (file_var->scanned_size < file_size) {+					/* This covers the case where the file+					 * size is greater than the data held.+					 * This will happen if the file is+					 * resized to be larger than its+					 * current data extents.+					 */+					file_var->file_size = file_size;+					file_var->scanned_size = file_size;+				}++				if (file_var->shrink_size > file_size)+					file_var->shrink_size = file_size;++				break;+			case YAFFS_OBJECT_TYPE_HARDLINK:+				hl_var = &in->variant.hardlink_variant;+				if (!is_unlinked) {+					hl_var->equiv_id = equiv_id;+					list_add(&in->hard_links, hard_list);+				}+				break;+			case YAFFS_OBJECT_TYPE_DIRECTORY:+				/* Do nothing */+				break;+			case YAFFS_OBJECT_TYPE_SPECIAL:+				/* Do nothing */+				break;+			case YAFFS_OBJECT_TYPE_SYMLINK:+				sl_var = &in->variant.symlink_variant;+				if (oh) {+					sl_var->alias =+					    yaffs_clone_str(oh->alias);+					if (!sl_var->alias)+						alloc_failed = 1;+				}+				break;+			}+		}+	}+	return alloc_failed ? YAFFS_FAIL : YAFFS_OK;+}++int yaffs2_scan_backwards(struct yaffs_dev *dev)+{+	int blk;+	int block_iter;+	int start_iter;+	int end_iter;+	int n_to_scan = 0;+	enum yaffs_block_state state;+	int c;+	int deleted;+	LIST_HEAD(hard_list);+	struct yaffs_block_info *bi;+	u32 seq_number;+	int n_blocks = dev->internal_end_block - dev->internal_start_block + 1;+	u8 *chunk_data;+	int found_chunks;+	int alloc_failed = 0;+	struct yaffs_block_index *block_index = NULL;+	int alt_block_index = 0;+	int summary_available;++	yaffs_trace(YAFFS_TRACE_SCAN,+		"yaffs2_scan_backwards starts  intstartblk %d intendblk %d...",+		dev->internal_start_block, dev->internal_end_block);++	dev->seq_number = YAFFS_LOWEST_SEQUENCE_NUMBER;++	block_index =+		kmalloc(n_blocks * sizeof(struct yaffs_block_index), GFP_NOFS);++	if (!block_index) {+		block_index =+		    vmalloc(n_blocks * sizeof(struct yaffs_block_index));+		alt_block_index = 1;+	}++	if (!block_index) {+		yaffs_trace(YAFFS_TRACE_SCAN,+			"yaffs2_scan_backwards() could not allocate block index!"+			);+		return YAFFS_FAIL;+	}++	dev->blocks_in_checkpt = 0;++	chunk_data = yaffs_get_temp_buffer(dev);++	/* Scan all the blocks to determine their state */+	bi = dev->block_info;+	for (blk = dev->internal_start_block; blk <= dev->internal_end_block;+	     blk++) {+		yaffs_clear_chunk_bits(dev, blk);+		bi->pages_in_use = 0;+		bi->soft_del_pages = 0;++		yaffs_query_init_block_state(dev, blk, &state, &seq_number);++		bi->block_state = state;+		bi->seq_number = seq_number;++		if (bi->seq_number == YAFFS_SEQUENCE_CHECKPOINT_DATA)+			bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT;+		if (bi->seq_number == YAFFS_SEQUENCE_BAD_BLOCK)+			bi->block_state = YAFFS_BLOCK_STATE_DEAD;++		yaffs_trace(YAFFS_TRACE_SCAN_DEBUG,+			"Block scanning block %d state %d seq %d",+			blk, bi->block_state, seq_number);++		if (bi->block_state == YAFFS_BLOCK_STATE_CHECKPOINT) {+			dev->blocks_in_checkpt++;++		} else if (bi->block_state == YAFFS_BLOCK_STATE_DEAD) {+			yaffs_trace(YAFFS_TRACE_BAD_BLOCKS,+				"block %d is bad", blk);+		} else if (bi->block_state == YAFFS_BLOCK_STATE_EMPTY) {+			yaffs_trace(YAFFS_TRACE_SCAN_DEBUG, "Block empty ");+			dev->n_erased_blocks++;+			dev->n_free_chunks += dev->param.chunks_per_block;+		} else if (bi->block_state ==+				YAFFS_BLOCK_STATE_NEEDS_SCAN) {+			/* Determine the highest sequence number */+			if (seq_number >= YAFFS_LOWEST_SEQUENCE_NUMBER &&+			    seq_number < YAFFS_HIGHEST_SEQUENCE_NUMBER) {+				block_index[n_to_scan].seq = seq_number;+				block_index[n_to_scan].block = blk;+				n_to_scan++;+				if (seq_number >= dev->seq_number)+					dev->seq_number = seq_number;+			} else {+				/* TODO: Nasty sequence number! */+				yaffs_trace(YAFFS_TRACE_SCAN,+					"Block scanning block %d has bad sequence number %d",+					blk, seq_number);+			}+		}+		bi++;+	}++	yaffs_trace(YAFFS_TRACE_ALWAYS, "%d blocks to be sorted...", n_to_scan);++	cond_resched();++	/* Sort the blocks by sequence number */+	sort(block_index, n_to_scan, sizeof(struct yaffs_block_index),+		   yaffs2_ybicmp, NULL);++	cond_resched();++	yaffs_trace(YAFFS_TRACE_SCAN, "...done");++	/* Now scan the blocks looking at the data. */+	start_iter = 0;+	end_iter = n_to_scan - 1;+	yaffs_trace(YAFFS_TRACE_SCAN_DEBUG, "%d blocks to scan", n_to_scan);++	/* For each block.... backwards */+	for (block_iter = end_iter;+	     !alloc_failed && block_iter >= start_iter;+	     block_iter--) {+		/* Cooperative multitasking! This loop can run for so+		   long that watchdog timers expire. */+		cond_resched();++		/* get the block to scan in the correct order */+		blk = block_index[block_iter].block;+		bi = yaffs_get_block_info(dev, blk);+		deleted = 0;++		summary_available = yaffs_summary_read(dev, dev->sum_tags, blk);++		/* For each chunk in each block that needs scanning.... */+		found_chunks = 0;+		if (summary_available)+			c = dev->chunks_per_summary - 1;+		else+			c = dev->param.chunks_per_block - 1;++		for (/* c is already initialised */;+		     !alloc_failed && c >= 0 &&+		     (bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCAN ||+		      bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING);+		      c--) {+			/* Scan backwards...+			 * Read the tags and decide what to do+			 */+			if (yaffs2_scan_chunk(dev, bi, blk, c,+					&found_chunks, chunk_data,+					&hard_list, summary_available) ==+					YAFFS_FAIL)+				alloc_failed = 1;+		}++		if (bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCAN) {+			/* If we got this far while scanning, then the block+			 * is fully allocated. */+			bi->block_state = YAFFS_BLOCK_STATE_FULL;+		}++		/* Now let's see if it was dirty */+		if (bi->pages_in_use == 0 &&+		    !bi->has_shrink_hdr &&+		    bi->block_state == YAFFS_BLOCK_STATE_FULL) {+			yaffs_block_became_dirty(dev, blk);+		}+	}++	yaffs_skip_rest_of_block(dev);++	if (alt_block_index)+		vfree(block_index);+	else+		kfree(block_index);++	/* Ok, we've done all the scanning.+	 * Fix up the hard link chains.+	 * We have scanned all the objects, now it's time to add these+	 * hardlinks.+	 */+	yaffs_link_fixup(dev, &hard_list);++	yaffs_release_temp_buffer(dev, chunk_data);++	if (alloc_failed)+		return YAFFS_FAIL;++	yaffs_trace(YAFFS_TRACE_SCAN, "yaffs2_scan_backwards ends");++	return YAFFS_OK;+}diff -Nur linux-3.15-rc5.orig/fs/yaffs2/yaffs_yaffs2.h linux-3.15-rc5/fs/yaffs2/yaffs_yaffs2.h--- linux-3.15-rc5.orig/fs/yaffs2/yaffs_yaffs2.h	1970-01-01 01:00:00.000000000 +0100+++ linux-3.15-rc5/fs/yaffs2/yaffs_yaffs2.h	2014-05-17 01:53:27.000000000 +0200@@ -0,0 +1,39 @@+/*+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.+ *+ * Copyright (C) 2002-2011 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_YAFFS2_H__+#define __YAFFS_YAFFS2_H__++#include "yaffs_guts.h"++void yaffs_calc_oldest_dirty_seq(struct yaffs_dev *dev);+void yaffs2_find_oldest_dirty_seq(struct yaffs_dev *dev);+void yaffs2_clear_oldest_dirty_seq(struct yaffs_dev *dev,+				   struct yaffs_block_info *bi);+void yaffs2_update_oldest_dirty_seq(struct yaffs_dev *dev, unsigned block_no,+				    struct yaffs_block_info *bi);+int yaffs_block_ok_for_gc(struct yaffs_dev *dev, struct yaffs_block_info *bi);+u32 yaffs2_find_refresh_block(struct yaffs_dev *dev);+int yaffs2_checkpt_required(struct yaffs_dev *dev);+int yaffs_calc_checkpt_blocks_required(struct yaffs_dev *dev);++void yaffs2_checkpt_invalidate(struct yaffs_dev *dev);+int yaffs2_checkpt_save(struct yaffs_dev *dev);+int yaffs2_checkpt_restore(struct yaffs_dev *dev);++int yaffs2_handle_hole(struct yaffs_obj *obj, loff_t new_size);+int yaffs2_scan_backwards(struct yaffs_dev *dev);++#endifdiff -Nur linux-3.15-rc5.orig/fs/yaffs2/yportenv.h linux-3.15-rc5/fs/yaffs2/yportenv.h--- linux-3.15-rc5.orig/fs/yaffs2/yportenv.h	1970-01-01 01:00:00.000000000 +0100+++ linux-3.15-rc5/fs/yaffs2/yportenv.h	2014-05-17 01:53:27.000000000 +0200@@ -0,0 +1,85 @@+/*+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.+ *+ * Copyright (C) 2002-2011 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))++#ifdef YAFFS_OUT_OF_TREE+#include "moduleconfig.h"+#endif++#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/version.h>+#include <linux/kernel.h>+#include <linux/mm.h>+#include <linux/sched.h>+#include <linux/string.h>+#include <linux/slab.h>+#include <linux/vmalloc.h>+#include <linux/xattr.h>+#include <linux/list.h>+#include <linux/types.h>+#include <linux/fs.h>+#include <linux/stat.h>+#include <linux/sort.h>+#include <linux/bitops.h>++/*  These type wrappings are used to support Unicode names in WinCE. */+#define YCHAR char+#define YUCHAR unsigned char+#define _Y(x)     x++#define YAFFS_LOSTNFOUND_NAME		"lost+found"+#define YAFFS_LOSTNFOUND_PREFIX		"obj"+++#define YAFFS_ROOT_MODE			0755+#define YAFFS_LOSTNFOUND_MODE		0700++#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 compile_time_assertion(assertion) \+	({ int x = __builtin_choose_expr(assertion, 0, (void)0); (void) x; })+++#define yaffs_printf(msk, fmt, ...) \+	printk(KERN_DEBUG "yaffs: " fmt "\n", ##__VA_ARGS__)++#define yaffs_trace(msk, fmt, ...) do { \+	if (yaffs_trace_mask & (msk)) \+		printk(KERN_DEBUG "yaffs: " fmt "\n", ##__VA_ARGS__); \+} while (0)+++#endif
 |