Zaronite u SDCardFS: Kako će Googleova zamjena FUSE smanjiti I/O opterećenje

Detaljno istraživanje SDCardFS-a, Googleove zamjene za FUSE, i načina na koji će njegova implementacija smanjiti I/O opterećenje.

Prije nekoliko mjeseci Google je dodao nešto pod nazivom "SDCardFS” službenim AOSP ograncima za Linux kernel. U to vrijeme potez su primijetili samo neki programeri kernela, ali je inače proletio ispod radara većine korisnika. Nije nikakvo iznenađenje s obzirom na činjenicu da većina korisnika, uključujući mene, zapravo ne znaju što se događa ispod haube OS-a Android i njegove jezgre.

Međutim, najnovija epizoda serije Android Developers Backstage podcast je obnovio interes za ovu temu. Podcast, koji je vodio Chet Haase (viši softverski inženjer u Googleu), istraživao je nedavne i nadolazeće promjene u kernelu. U emisiji je bio programer Linux kernela koji radi u Android timu - Rom Lemarchand. Dvojac je prvenstveno raspravljao o promjenama koje su napravljene kako bi se prilagodile A/B ažuriranjima, ali u posljednjih 5 minuta epizode gospodin Lemarchand govorio je o "sljedećoj velikoj stvari" na kojoj njegov tim radi - SDCardFS.

Moram priznati da sam za postojanje SDCardFS-a saznao nakon slušanja ovog podcasta. Naravno, nisam bio jedini koji se zainteresirao za ovu temu, kao nedavna nit na Redditu pokazao je. Međutim, nisam bio zadovoljan osnovnim objašnjenjem koje je ponuđeno u podcastu, iu nastojanju da se odagnaju neki od dezinformacija koje se šire uokolo, sam sam istražio i razgovarao s nekoliko stručnjaka s relevantnim znanjem o materija.

Veliko hvala razvojnom programeru Michalu Kowalczyku što je svojim znanjem doprinio ovom članku i što je odvojio vrijeme da odgovori na moja pitanja.


"Vanjsko" je zapravo unutarnje

Odmah na početku, sigurno će biti nekih zabluda koje moramo razjasniti - inače će ostatak članka biti vrlo zbunjujući. Korisno je razgovarati o povijesti SD kartica i Android telefona.

U prvim danima Android telefona, gotovo svaki uređaj oslanjao se na korištenje svojih microSD kartica za pohranu. To je bilo zbog činjenice da su se telefoni u to vrijeme isporučivali s minijaturnim internim kapacitetima za pohranu. Međutim, SD kartice koje se koriste za pohranu aplikacija često ne pružaju zvjezdano korisničko iskustvo, barem u usporedbi s brzinom kojom interna flash memorija može čitati/pisati podatke. Stoga je sve veća upotreba SD kartica za vanjsku pohranu podataka postala problem korisničkog iskustva za Google.

Zbog ranog širenja SD kartica kao vanjskih uređaja za pohranu, Androidove konvencije o imenovanju pohrane temeljile su se na činjenici da je svaki uređaj imao stvarni, fizički utor za microSD karticu. Ali čak i na uređajima koji nisu sadržavali utor za SD karticu, oznaka /sdcard još uvijek se koristila za usmjeravanje na stvarni čip za unutarnju pohranu. Više je zbunjujuća činjenica da bi uređaji koji su koristili i fizičku SD karticu kao i čip za pohranu velikog kapaciteta za pohranu često nazivali svoje particije temeljene na SD kartici. Na primjer, u ovim uređajima točka montiranja /sdcard odnosila bi se na stvarni interni čip za pohranu, dok bi se nešto poput /storage/sdcard1 odnosilo na fizičku vanjsku karticu.

Stoga, iako se microSD kartica praktički smatra vanjskom pohranom, konvencija imenovanja rezultirala je time da se "SDCard" zadržala dugo nakon bilo kakve stvarne upotrebe fizičke kartice. Ova zbrka s pohranom također je zadala glavobolju programerima aplikacija zbog činjenice da su podaci aplikacije i njeni mediji bili odvojeni između dvije particije.

Mali prostor za pohranu ranih čipova za internu pohranu rezultirao je time da su korisnici frustrirajuće otkrili da više ne mogu instalirati aplikacije (zbog toga što je particija /data bila puna). U međuvremenu, njihove microSD kartice većeg kapaciteta prebačene su samo na medije (kao što su fotografije, glazba i filmovi). Korisnici koji su nekada pregledavali naše forume mogli bi se sjetiti ovih imena: Link2SD i Apps2SD. Bila su to (root) rješenja koja su korisnicima omogućila instaliranje svojih aplikacija i njihovih podataka na fizičku SD karticu. Ali to su bila daleko od savršenih rješenja, pa je Google morao uskočiti.

Poznato je da je Google vrlo rano ukinuo SD kartice. Nexus One ostaje jedini Nexus uređaj s utorom za microSD karticu (i tako će zauvijek biti jer je brend Nexus zapravo mrtav). Uz Nexus S, sada je postojala samo jedna, objedinjena particija za pohranu svih podataka aplikacija i medija - particija /data. Ono što je nekoć bilo poznato kao točka montiranja /sdcard sada se jednostavno odnosilo na virtualni datotečni sustav (implementiran pod OSIGURAČ protokol kao što je objašnjeno u nastavku) koji se nalazi u podatkovnoj particiji - /data/media/0.

Kako bi održao kompatibilnost i smanjio zabunu, Google je i dalje koristio ovu sada virtualnu "sdcard" particiju za držanje medija. Ali sada kada je ova "sdcard" virtualna particija zapravo smještena unutar /data, sve što je pohranjeno unutar nje uračunavalo bi se u prostor za pohranu internog čipa za pohranu. Stoga je na OEM-u bilo da razmotre koliko prostora dodijeliti aplikacijama (/data) u odnosu na medije (/data/media).

Dvije vrlo različite "SD kartice"

Google se nadao da će proizvođači slijediti njihov primjer i riješiti se SD kartica. Srećom, s vremenom su proizvođači telefona bili u mogućnosti nabaviti te komponente većeg kapaciteta, a da su ostali isplativi, pa je potreba za SD karticama počela nestajati. Ali konvencije o imenovanju ustrajale su kako bi se smanjio napor koji bi programeri i proizvođači originalne opreme morali uložiti da se prilagode. Trenutno, kada govorimo o "vanjskoj pohrani", mislimo na to bilo jednu od dvije stvari: stvarna uklonjiva microSD kartica ili virtualna “SDCard” particija koja se nalazi u /data/media. Potonji od ovih, praktično govoreći, je zapravo unutarnja pohrana, ali ga Googleova konvencija o imenovanju razlikuje zbog činjenice da su ti podaci dostupni korisniku (na primjer kada je priključen na računalo).

Trenutno, kada govorimo o "vanjskoj pohrani", mislimo na to bilo jednu od dvije stvari: stvarna uklonjiva microSD kartica ili virtualna “SDCard” particija koja se nalazi u /data/media.


Povijest Androidovih virtualnih datotečnih sustava

Sada kada se "sdcard" tretira kao virtualni datotečni sustav, to je značilo da se može formatirati kao bilo koji datotečni sustav koji Google želi. Počevši od Nexusa S i Androida 2.3, Google je odlučio formatirati "sdcard" kao VFAT (virtualni FAT). Ovaj je potez imao smisla u to vrijeme, budući da bi montiranje VFAT-a omogućilo gotovo svakom računalu pristup podacima pohranjenim na vašem telefonu. Međutim, postojala su dva glavna problema s ovom početnom implementacijom.

Prvi se prvenstveno odnosi na krajnjeg korisnika (vas). Kako biste svoj uređaj povezali s računalom, za prijenos podataka koristite USB način masovne pohrane. To je, međutim, zahtijevalo da Android uređaj demontira virtualnu particiju prije nego što računalo može pristupiti podacima. Kad bi korisnik želio koristiti svoj uređaj dok je priključen, mnoge stvari bi se pokazale kao nedostupne.

The uvođenje Media Transfer Protokola (MTP) riješio je ovaj prvi problem. Kada je priključeno, vaše računalo vidi vaš uređaj kao uređaj za "medijsku pohranu". Zahtijeva popis datoteka s vašeg telefona, a MTP vraća popis datoteka koje računalo može preuzeti s uređaja. Kada se zatraži brisanje datoteke, MTP šalje naredbu za uklanjanje tražene datoteke iz pohrane. Za razliku od USB Mass Storage Mode koji zapravo postavlja "sdcard", MTP omogućuje korisniku da nastavi koristiti svoj uređaj dok je priključen. Nadalje, datotečni sustav prisutan na Android telefonu više nije bitan da bi računalo prepoznalo datoteke na uređaju.

Drugo, tu je bila činjenica da VFAT nije pružao onu vrstu robusnog upravljanja dozvolama kakvu je Google trebao. U početku su mnogi programeri aplikacija tretirali "sdcard" kao odlagalište podataka svoje aplikacije, bez jedinstvenog osjećaja gdje pohraniti svoje datoteke. Mnoge bi aplikacije jednostavno stvorile mapu s nazivom svoje aplikacije i tamo pohranile svoje datoteke.

Gotovo svaka aplikacija u to vrijeme zahtijevala je WRITE_EXTERNAL_STORAGE dopuštenje za pisanje svojih aplikacijskih datoteka u vanjsku pohranu. Međutim, ono što je više zabrinjavalo bila je činjenica da je gotovo svaka aplikacija također zahtijevala READ_EXTERNAL_STORAGE dopuštenje - samo za čitanje vlastitih datoteka s podacima! To je značilo da aplikacije mogu lako imati pristup podacima pohranjenim bilo gdje na vanjskoj pohrani, a takvo je dopuštenje često davao korisnik jer je bilo potrebno mnogim aplikacijama za čak funkcija.

Google je to očito vidio kao problematičan. Cijela ideja upravljanja dopuštenjima je odvojiti čemu aplikacije mogu, a čemu ne mogu imati pristup. Ako se gotovo svakoj aplikaciji dodijeli pristup za čitanje potencijalno osjetljivih korisničkih podataka, tada je dopuštenje besmisleno. Stoga je Google odlučio da im treba novi pristup. Tu na scenu stupa FUSE.


Datotečni sustav u korisničkom prostoru (FUSE)

Počevši od Androida 4.4, Google je odlučio više ne montirati virtualnu "sdcard" particiju kao VFAT. Umjesto toga, Google je počeo koristiti FUSE za oponašanje FAT32 na "sdcard" virtualnoj particiji. Uz poziv sdcard programa FUSE za oponašanje dopuštenja direktorija u stilu FAT-on-sdcard, aplikacije bi mogle početi pristupati njegovim podacima pohranjenim na vanjskoj pohrani bez potrebe za bilo kakvim dopuštenjima. Doista, počevši od API razine 19, READ_EXTERNAL_STORAGE više nije bio potreban za pristup datotekama koje se nalaze na vanjskoj pohrani - pod uvjetom da mapa podataka koju je stvorio demon FUSE odgovara nazivu paketa aplikacije. OSIGURAČ bi se snašao sintetiziranje vlasnika, grupe i načina datoteka na vanjskoj pohrani kada je aplikacija instalirana.

FUSE se razlikuje od in-kernel modula jer dopušta neprivilegiranim korisnicima pisanje virtualnih datotečnih sustava. Razlog zašto je Google implementirao FUSE je prilično jednostavan - radio je ono što su htjeli i već je bio dobro razumio i dokumentirao u svijetu Linuxa. Da citiram a Google programer o tome:

"Budući da je FUSE lijep stabilan API, u biti nije potreban nikakav rad na održavanju pri prelasku s jedne verzije kernela na drugu. Da smo migrirali na rješenje unutar jezgre, prijavili bismo se za održavanje skupa zakrpa za svaku stabilnu verziju jezgre." - Jeff Sharkey, softverski inženjer u Googleu

Međutim, postajalo je posve jasno da je FUSE-ov režijski trošak predstavljao hit u izvedbi među ostalim problemima. Programer s kojim sam razgovarao o ovom pitanju, Michal Kowalczyk, napisao izvrstan post na blogu prije više od godinu dana s pojedinostima o trenutačnim problemima s FUSE-om. Više tehničkih detalja možete pročitati na njegovom blogu, ali ja ću njegova otkrića (uz njegovo dopuštenje) opisati laički.


Problem s OSIGURAČEM

U Androidu, demon korisničkog prostora "sdcard" koristi FUSE za montiranje /dev/fuse u emulirani vanjski direktorij za pohranu prilikom pokretanja. Nakon toga, demon sdcard ispituje uređaj FUSE za sve poruke na čekanju od kernela. Ako ste slušali podcast, možda ste čuli gospodina Lemarchanda kako je FUSE uveo opterećenje tijekom I/O operacija - evo što se u biti događa.

U stvarnom svijetu, ovaj hit izvedbe utječe bilo koji datoteka pohranjena na vanjskoj pohrani.

Problem #1 - I/O opterećenje

Recimo da smo stvorili jednostavnu tekstualnu datoteku, nazvanu "test.txt", i pohranili je u /sdcard/test.txt (koji, neka podsjećam vas, zapravo /data/media/0/test.txt pretpostavlja da je trenutačni korisnik primarni korisnik na uređaj). Ako bismo željeli pročitati (command cat) ovu datoteku, očekivali bismo da će sustav izdati 3 naredbe: otvori, pročitaj i zatvori. Doista, kao što g. Kowalczyk pokazuje korištenje strace, to se događa:

Ali budući da se datoteka nalazi na vanjskoj pohrani kojom upravlja sdcard daemon, postoje mnoge dodatne operacije koje je potrebno izvesti. Prema g. Kowalczyku, u biti je potrebno 8 dodatnih koraka za svaku od ove 3 pojedinačne naredbe:

  1. Aplikacija korisničkog prostora izdaje sistemski poziv kojim će upravljati FUSE upravljački program u kernelu (vidimo to u prvom izlazu strace)
  2. FUSE driver u kernelu obavještava demona korisničkog prostora (sdcard) o novom zahtjevu
  3. Demon korisničkog prostora čita /dev/fuse
  4. Demon korisničkog prostora analizira naredbu i prepoznaje operaciju datoteke (npr. otvoren)
  5. Demon korisničkog prostora šalje sistemski poziv stvarnom datotečnom sustavu (EXT4)
  6. Kernel upravlja fizičkim pristupom podacima i šalje podatke natrag u korisnički prostor
  7. Korisnički prostor mijenja (ili ne) podatke i ponovno ih prosljeđuje kernelu kroz /dev/fuse
  8. Kernel dovršava izvorni sistemski poziv i premješta podatke u stvarnu aplikaciju korisničkog prostora (u našem primjeru cat)

Ovo izgleda kao puno opterećenja samo na jednu I/O naredbu koju treba pokrenuti. I bili biste u pravu. Kako bi to pokazao, g. Kowalczyk pokušao je testirati dva različita I/O testa: jedan je uključivao kopiranje velike datoteke, a drugi kopiranje puno malih datoteka. Usporedio je brzinu FUSE-a (na virtualnoj particiji montiranoj kao FAT32) koji upravlja ovim operacijama u odnosu na jezgre (na podatkovnoj particiji formatiranoj kao EXT4), i otkrio je da FUSE doista značajno pridonosi iznad glave.

U prvom testu kopirao je datoteku od 725 MB u oba testna uvjeta. Otkrio je da implementacija FUSE prenosi velike datoteke 17% sporije.

U drugom testu kopirao je 10.000 datoteka - svaka od njih veličine 5 KB. U ovom scenariju, implementacija FUSE-a je završena 40 sekundi sporije za kopiranje podataka u vrijednosti od 50 MB.

U stvarnom svijetu, ovaj hit izvedbe utječe bilo koji datoteka pohranjena na vanjskoj pohrani. To znači da aplikacije kao što su Karte pohranjuju velike datoteke na /sdcard, glazbene aplikacije koje pohranjuju tone glazbenih datoteka, aplikacije za kameru i fotografije itd. Na sve I/O operacije koje se izvode, a koje uključuju vanjsku pohranu, utječe opterećenje FUSE-a. Ali I/O opterećenje nije jedini problem s FUSE-om.

Problem #2 - Dvostruko predmemoriranje

Spremanje podataka u predmemoriju važno je za poboljšanje izvedbe pristupa podacima. Pohranjivanjem bitnih dijelova podataka u memoriju, Linux kernel može brzo pozvati te podatke kada su potrebni. Ali zbog načina na koji je FUSE implementiran, Android pohranjuje duplu količinu predmemorije koja je potrebna.

Kao što g. Kowalczyk pokazuje, očekuje se da će datoteka od 10 MB biti spremljena u predmemoriju kao točno 10 MB, ali umjesto toga povećava se do veličine predmemorije za oko 20 MBs. To je problematično na uređajima s manje RAM-a, budući da Linux kernel pohranjuje predmemoriju stranica za pohranu podataka u memorija. Gospodin Kowalczyk testirao je ovaj problem dvostrukog predmemoriranja koristeći ovaj pristup:

  1. Stvorite datoteku poznate veličine (za testiranje, 10 MB)
  2. Kopirajte ga u /sdcard
  3. Ispustite predmemoriju stranice
  4. Napravite snimku korištenja predmemorije stranice
  5. Pročitajte testnu datoteku
  6. Napravite još jednu snimku upotrebe predmemorije stranice

Otkrio je da je prije testa kernel koristio 241 MB za predmemoriju stranice. Nakon što je pročitao svoju testnu datoteku, očekivao je da će vidjeti 251 MB iskorišteno za predmemoriju stranice. Umjesto toga, otkrio je da taj kernel koristi 263 MBs za predmemoriju stranice - oko dvostruko više od očekivanog. Razlog zašto se to događa je taj što podatke prvo predmemorira korisnička aplikacija koja je izvorno poslala I/O poziv (FUSE), a drugi sdcard demon (EXT4 FS).

Problem #3 - Nepotpuna implementacija FAT32

Postoje još dva problema koji proizlaze iz upotrebe FUSE-a koji emulira FAT32 koji su manje poznati u Android zajednici.

Prvi uključuje netočne vremenske oznake. Ako ste ikada prenijeli datoteku (kao što je fotografija) i primijetili da vremenska oznaka nije točna, to je zbog Androidove implementacije FUSE-a. Ovo pitanje ima postojao za godine. Da budemo precizniji, problem uključuje uvrijeme() sistemski poziv koji vam omogućuje promjenu vremena pristupa i izmjene datoteke. Nažalost, pozivi upućeni sdcard demonu kao standardni korisnik nemaju odgovarajuću dozvolu za izvršavanje ovog sistemskog poziva. Za to postoje zaobilazna rješenja, ali to morate učiniti imati root pristup.

Ako ste ikada prenijeli datoteku (kao što je fotografija) i primijetili da vremenska oznaka nije točna, to je zbog Androidove implementacije FUSE-a.

Sljedeći problem je više zabrinut za tvrtke koje koriste nešto poput a smartSD karticu. Prije FUSE-a, proizvođači aplikacija mogli su pratiti O_DIRECT zastavica kako bi komunicirali s ugrađenim mikrokontrolerom u kartici. Uz FUSE programeri mogu pristupiti samo predmemoriranoj verziji datoteke i ne mogu vidjeti nijednu naredbu koju šalje mikrokontroler. Ovo je problematično za neke poslovne/državne/bankarske aplikacije koje komuniciraju s microSD karticama s dodanom vrijednošću.


Damping FUSE za SDCardFS

Neki OEM-ovi su rano prepoznali te probleme i počeli tražiti rješenje u kernelu koje bi zamijenilo FUSE. Samsung je, primjerice, razvio SDCardFS koji se temelji na WrapFS-u. Ovo rješenje unutar jezgre emulira FAT32 baš kao što to čini FUSE, ali se odriče I/O opterećenja, dvostrukog predmemoriranja i drugih problema koje sam gore spomenuo. (Da, dopustite mi da ponovim to, ovo rješenje koje Google sada implementira temelji se na Samsungovom radu).

Sam Google je konačno priznao nedostatke povezane s FUSE-om, zbog čega su se počeli kretati prema in-kernel FAT32 sloju emulacije koji je razvio Samsung. Tvrtka, kako je navedeno u Android Developers Backstage podcast, radi na tome da SDCardFS bude dostupan za sve uređaje u nadolazećoj verziji kernela. Trenutno možete vidjeti njihov napredak rad u AOSP-u.

Kao Googleov programer objasnio je ranije, najveći izazov kod implementacije rješenja unutar jezgre je kako preslikati naziv paketa na ID aplikacije neophodan za pristup paketa vlastitim podacima u vanjskoj pohrani bez ikakve potrebe dozvole. Ali ta je izjava dana prije godinu dana i došli smo do točke u kojoj tim SDCardFS naziva svojom "sljedećom velikom stvari". Već su potvrdili da zastrašujuća pogreška vremenske oznake je popravljen zahvaljujući odlasku s FUSE-a, tako da se možemo radovati što ćemo vidjeti sve promjene koje su proizašle iz napuštanja FUSE-a.


Zablude u provjeravanju činjenica

Ako ste stigli ovako daleko u članku, onda svaka čast što ste bili u toku sa svime dosad! Želio sam razjasniti nekoliko pitanja koja sam i sam imao dok sam pisao ovaj članak:

  • SDCardFS ima nema veze sa stvarnim SD karticama. Nazvan je samo tako jer upravlja I/O pristupom za /sdcard. I kao što se možda sjećate, /sdcard je zastarjela oznaka koja se odnosi na "vanjsku" pohranu vašeg uređaja (gdje aplikacije pohranjuju svoje medije).
  • SDCardFS je nije tradicionalni datotečni sustav poput FAT32, EXT4 ili F2FS. To je omotni datotečni sustav koji se može složiti i prosljeđuje naredbe nižim, emuliranim datotečnim sustavima (u ovom slučaju to bi bio FAT32 na /sdcard).
  • Ništa se neće promijeniti u odnosu na MTP. Nastavit ćete koristiti MTP za prijenos datoteka na/sa svog računala (sve dok se Google ne odluči za bolji protokol). Ali barem će pogreška vremenske oznake biti ispravljena!
  • Kao što je prije spomenuto, kada Google spominje "vanjsku pohranu", oni ili govore o (za sve namjene i svrhe) interna /sdcard virtualna FAT32 particija ILI govore o stvarnom, fizičkom, uklonjivom microSD-u kartica. Terminologija je zbunjujuća, ali to nas je iznenadilo.

Zaključak

Odmicanjem od FUSE-a i implementacijom sloja emulacije FAT32 unutar jezgre (SDCardFS), Google će smanjiti značajno I/O opterećenje, eliminiranje dvostrukog predmemoriranja i rješavanje nekih opskurnih problema povezanih s njegovom FUSE emulacijom FAT32.

Budući da će ove promjene biti unesene u jezgru, mogu se pokrenuti bez velike nove verzije Androida uz nju. Neki korisnici očekuju da će ove promjene biti službeno implementirane u Androidu 8, ali to je moguće za bilo koji budući OTA na uređaju Pixel kako bi se dovela verzija 4.1 jezgre Linuxa na kojoj Google radi na.

Za neke od vas SDCardFS nije nov koncept. Zapravo, Samsung uređaji ga koriste godinama (oni su ga ipak razvili). Otkako je SDCardFS predstavljen u AOSP-u prošle godine, neki prilagođeni programeri ROM-a i kernela odlučili su ga implementirati u svoj rad. CyanogenMOD je u jednom trenutku razmišljao o njegovoj implementaciji, ali je vratio kada su korisnici naišli na probleme sa svojim fotografijama. Ali nadamo se da će Google preuzeti vlast nad ovim projektom i da će korisnici Androida na svim budućim uređajima moći iskoristiti prednosti poboljšanja uvedenih napuštanjem FUSE-a.