Plonger dans SDCardFS: comment le remplacement de FUSE par Google réduira les frais généraux d'E/S

Une exploration approfondie de SDCardFS, le remplacement de FUSE par Google, et de la manière dont sa mise en œuvre réduira les frais d'E/S.

Il y a plusieurs mois, Google a ajouté quelque chose appelé «Carte SDFS» aux branches officielles AOSP pour le noyau Linux. À l'époque, cette décision n'avait été remarquée que par certains développeurs du noyau, mais par ailleurs, il est passé sous le radar de la plupart des utilisateurs. Ce n’est pas surprenant étant donné que la plupart des utilisateurs, moi y compris, ne savent pas vraiment ce qui se passe sous le capot du système d’exploitation Android et de son noyau.

Cependant, l'épisode le plus récent du Les développeurs Android dans les coulisses le podcast a renouvelé l'intérêt pour ce sujet. Le podcast, hébergé par Chet Haase (ingénieur logiciel senior chez Google), a exploré les modifications récentes et à venir apportées au noyau. Lors de l'émission, il y avait un développeur du noyau Linux travaillant dans l'équipe Android - Rom Lemarchand. Le duo a principalement discuté des changements apportés pour s'adapter aux mises à jour A/B, mais dans les 5 dernières minutes de l'épisode, M. Lemarchand a parlé de « la prochaine grande chose » sur laquelle son équipe travaillait:

Carte SDFS.

Je dois admettre que j'ai appris l'existence de SDCardFS après avoir écouté ce podcast. Bien entendu, je n’étais pas le seul à m’intéresser à ce sujet, car fil de discussion Reddit récent a montré. Cependant, je n’étais pas satisfait de l’explication de base proposée dans le podcast et, dans le but de dissiper certaines des la désinformation se répandait, j'ai fait mes propres recherches et j'ai parlé à quelques experts possédant des connaissances pertinentes sur le sujet. matière.

Un grand merci au développeur de logiciels Michal Kowalczyk pour avoir apporté ses connaissances à cet article et pris le temps de répondre à mes questions.


"Externe" est vraiment interne

D’entrée de jeu, il y aura forcément quelques idées fausses que nous devrons dissiper – sinon le reste de l’article sera très déroutant. Il est utile de discuter de l’historique des cartes SD et des téléphones Android.

Au début des téléphones Android, presque tous les appareils utilisaient leurs cartes microSD pour le stockage. Cela était dû au fait que les téléphones de l’époque étaient livrés avec de minuscules capacités de stockage interne. Cependant, les cartes SD utilisées pour stocker des applications n'offrent souvent pas une expérience utilisateur exceptionnelle, du moins par rapport à la vitesse à laquelle la mémoire flash interne peut lire/écrire des données. Par conséquent, l’utilisation croissante de cartes SD pour le stockage de données externes devenait une préoccupation en matière d’expérience utilisateur pour Google.

En raison de la prolifération précoce des cartes SD en tant que périphériques de stockage externes, les conventions de dénomination du stockage d'Android étaient basées sur le fait que chaque appareil disposait d'un véritable emplacement physique pour carte microSD. Mais même sur les appareils qui ne contenaient pas d’emplacement pour carte SD, l’étiquette /sdcard était toujours utilisée pour pointer vers la véritable puce de stockage interne. Plus déroutant est le fait que les appareils qui utilisaient à la fois une carte SD physique et une puce de stockage haute capacité pour le stockage nommaient souvent leurs partitions en fonction de la carte SD. Par exemple, dans ces appareils, le point de montage /sdcard ferait référence à la puce de stockage interne réelle, alors que quelque chose comme /storage/sdcard1 ferait référence à la carte externe physique.

Ainsi, même si la carte microSD est pratiquement considérée comme un stockage externe, la convention de dénomination a fait que « SDCard » est restée bien après toute utilisation réelle d'une carte physique. Cette confusion avec le stockage a également causé des maux de tête aux développeurs d'applications en raison du fait que les données des applications et leurs supports étaient séparés entre les deux partitions.

Le faible espace de stockage des premières puces de stockage interne a amené les utilisateurs à découvrir de manière frustrante qu'ils ne pouvaient plus installer d'applications (en raison de la partition /data étant pleine). Pendant ce temps, leurs cartes microSD de plus grande capacité étaient reléguées à contenir uniquement des médias (tels que des photos, de la musique et des films). Les utilisateurs qui ont parcouru nos forums à l’époque se souviennent peut-être de ces noms: Link2SD et Apps2SD. Il s'agissait de solutions (root) qui permettaient aux utilisateurs d'installer leurs applications et leurs données sur la carte SD physique. Mais ces solutions étaient loin d’être parfaites, et Google a donc dû intervenir.

C’est bien connu, Google a débranché très tôt les cartes SD. Le Nexus One reste le seul appareil Nexus doté d'un emplacement pour carte microSD (et ce le sera pour toujours puisque la marque Nexus est effectivement morte). Avec le Nexus S, il n'existait désormais qu'une seule partition unifiée pour stocker toutes les données et supports d'application: la partition /data. Ce qui était autrefois connu sous le nom de point de montage /sdcard faisait désormais simplement référence à un système de fichiers virtuel (implémenté sous le FUSIBLE protocole comme indiqué ci-dessous) situé dans la partition de données - /data/media/0.

Afin de maintenir la compatibilité et de réduire la confusion, Google utilisait toujours cette partition « carte SD » désormais virtuelle pour contenir les médias. Mais maintenant que cette partition virtuelle « carte SD » était réellement située dans /data, tout ce qui y était stocké serait décompté de l’espace de stockage de la puce de stockage interne. Il appartenait donc aux OEM de déterminer la quantité d'espace à allouer aux applications (/data) par rapport aux médias (/data/media).

Deux "cartes SD" très différentes

Google espérait que les fabricants suivraient son exemple et se débarrasseraient des cartes SD. Heureusement, au fil du temps, les fabricants de téléphones ont pu se procurer ces composants avec des capacités plus élevées tout en restant rentables, de sorte que le besoin en cartes SD commençait à s'amenuiser. Mais les conventions de dénomination ont persisté afin de réduire les efforts d’ajustement que les développeurs et les constructeurs OEM devraient déployer. Actuellement, lorsque nous parlons de « stockage externe », nous faisons référence à soit l'une des deux choses: la carte microSD amovible réelle ou la partition virtuelle « SDCard » située dans /data/media. Ce dernier, en pratique, est en fait un stockage interne, mais la convention de dénomination de Google le différencie du fait que ces données sont accessibles à l'utilisateur (par exemple lorsqu'il est branché sur l'ordinateur).

Actuellement, lorsque nous parlons de « stockage externe », nous faisons référence à soit l'une des deux choses: la carte microSD amovible réelle ou la partition virtuelle « SDCard » située dans /data/media.


L'histoire des systèmes de fichiers virtuels d'Android

Maintenant que la « carte SD » est traitée comme un système de fichiers virtuel, cela signifie qu'elle peut être formatée comme n'importe quel système de fichiers souhaité par Google. À partir du Nexus S et d'Android 2.3, Google a choisi de formater la « carte SD » en VFAT (virtual FAT). Cette décision était logique à l'époque, car le montage de VFAT permettrait à presque n'importe quel ordinateur d'accéder aux données stockées sur votre téléphone. Cependant, cette mise en œuvre initiale présentait deux problèmes majeurs.

La première concerne avant tout l’utilisateur final (vous). Afin de connecter votre appareil à votre ordinateur, vous utiliserez le mode de stockage de masse USB pour transférer des données. Cependant, cela nécessitait que l'appareil Android démonte la partition virtuelle avant que l'ordinateur puisse accéder aux données. Si un utilisateur souhaitait utiliser son appareil alors qu'il était branché, de nombreux éléments s'afficheraient comme indisponibles.

Le introduction du protocole de transfert de médias (MTP) a résolu ce premier problème. Une fois branché, votre ordinateur considère votre appareil comme un périphérique de « stockage multimédia ». Il demande une liste de fichiers à votre téléphone et MTP renvoie une liste de fichiers que l'ordinateur peut télécharger depuis l'appareil. Lorsqu'il est demandé de supprimer un fichier, MTP envoie une commande pour supprimer le fichier demandé du stockage. Contrairement au mode de stockage de masse USB qui monte la « carte SD », MTP permet à l'utilisateur de continuer à utiliser son appareil lorsqu'il est branché. De plus, le système de fichiers présent sur le téléphone Android n'a plus d'importance pour que l'ordinateur reconnaisse les fichiers sur l'appareil.

Deuxièmement, VFAT ne fournissait pas le type de gestion robuste des autorisations dont Google avait besoin. Au début, de nombreux développeurs d’applications considéraient la « carte SD » comme un dépotoir pour les données de leur application, sans aucune idée unifiée de l’endroit où stocker leurs fichiers. De nombreuses applications créeraient simplement un dossier avec son nom d’application et y stockeraient ses fichiers.

Presque toutes les applications disponibles à l'époque nécessitaient le WRITE_EXTERNAL_STORAGE autorisation d'écrire leurs fichiers d'application sur le stockage externe. Cependant, ce qui était plus troublant était le fait que presque toutes les demandes nécessitaient également le READ_EXTERNAL_STORAGE autorisation - juste pour lire leurs propres fichiers de données! Cela signifiait que les applications pouvaient facilement accéder aux données stockées n'importe où sur le stockage externe, et une telle autorisation était souvent accordée par l'utilisateur car elle était nécessaire pour que de nombreuses applications puissent même fonction.

Google a clairement vu cela comme problématique. L’idée derrière la gestion des autorisations est de séparer ce à quoi les applications peuvent et ne peuvent pas avoir accès. Si presque toutes les applications bénéficient d’un accès en lecture aux données utilisateur potentiellement sensibles, alors l’autorisation n’a aucun sens. Ainsi, Google a décidé qu’il lui fallait une nouvelle approche. C'est là qu'intervient FUSE.


Système de fichiers dans l'espace utilisateur (FUSE)

À partir d'Android 4.4, Google a décidé de ne plus monter la partition virtuelle « carte SD » en VFAT. Au lieu de cela, Google a commencé à utiliser FUSE pour émuler FAT32 sur la partition virtuelle « sdcard ». Avec le programme SDCard appelant FUSE pour émuler les autorisations de répertoire de style FAT-on-sdcard, les applications pourraient commencer à accéder à ses données stockées sur un stockage externe sans nécessiter aucune autorisation. En effet, à partir de l'API niveau 19, READ_EXTERNAL_STORAGE n'était plus nécessaire pour accéder aux fichiers situés sur le stockage externe - à condition que le dossier de données créé par le démon FUSE corresponde au nom du package de l'application. FUSE gérerait synthétiser le propriétaire, le groupe et les modes des fichiers sur un stockage externe lorsqu'une application est installée.

FUSE diffère des modules intégrés au noyau car il permet aux utilisateurs non privilégiés d'écrire des systèmes de fichiers virtuels. La raison pour laquelle Google a implémenté FUSE est plutôt simple: il a fait ce qu'ils voulaient et c'était déjà le cas. bien compris et documenté dans le monde de Linux. Pour citer un Développeur Google à ce sujet:

"Étant donné que FUSE est une API stable et agréable, aucun travail de maintenance n'est requis lors du passage d'une version du noyau à l'autre. Si nous migions vers une solution intégrée au noyau, nous nous engagerions à maintenir un ensemble de correctifs pour chaque version stable du noyau. " -Jeff Sharkey, ingénieur logiciel chez Google

Cependant, il devenait clair que les frais généraux de FUSE entraînaient, entre autres problèmes, une baisse des performances. Le développeur avec qui j'ai parlé à ce sujet, Michal Kowalczyk, a écrit un excellent article de blog il y a plus d'un an, détaillant les problèmes actuels avec FUSE. Des détails plus techniques peuvent être lus sur son blog, mais je décrirai ses découvertes (avec sa permission) en termes plus simples.


Le problème avec FUSE

Sous Android, le démon de l'espace utilisateur « sdcard » utilise FUSE pour monter /dev/fuse sur le répertoire de stockage externe émulé au démarrage. Après cela, le démon sdcard interroge le périphérique FUSE pour détecter tous les messages en attente du noyau. Si vous avez écouté le podcast, vous avez peut-être entendu M. Lemarchand faire référence à FUSE introduisant une surcharge lors des opérations d'E/S - voici essentiellement ce qui se passe.

Dans le monde réel, cette baisse de performance affecte n'importe lequel fichier stocké sur un stockage externe.

Problème n°1 – Surcharge d'E/S

Disons que nous créons un simple fichier texte, appelé « test.txt », et le stockons dans /sdcard/test.txt (qui, soit Je vous le rappelle, c'est en fait /data/media/0/test.txt en supposant que l'utilisateur actuel est l'utilisateur principal sur le appareil). Si nous voulions lire (commande cat) ce fichier, nous nous attendrions à ce que le système émette 3 commandes: ouvrir, lire, puis fermer. En effet, comme le démontre M. Kowalczyk en utilisant strace, voici ce qui se passe :

Mais comme le fichier se trouve sur le stockage externe géré par le démon sdcard, de nombreuses opérations supplémentaires doivent être effectuées. Selon M. Kowalczyk, il faut essentiellement 8 étapes supplémentaires pour chacune de ces 3 commandes individuelles:

  1. L'application de l'espace utilisateur émet un appel système qui sera géré par le pilote FUSE dans le noyau (nous le voyons dans la première sortie strace)
  2. Le pilote FUSE dans le noyau informe le démon de l'espace utilisateur (sdcard) de la nouvelle demande
  3. Le démon de l'espace utilisateur lit /dev/fuse
  4. Le démon de l'espace utilisateur analyse la commande et reconnaît le fonctionnement du fichier (ex. ouvrir)
  5. Le démon de l'espace utilisateur émet un appel système vers le système de fichiers réel (EXT4)
  6. Le noyau gère l'accès physique aux données et renvoie les données à l'espace utilisateur
  7. L'espace utilisateur modifie (ou non) les données et les transmet à nouveau via /dev/fuse au noyau
  8. Le noyau termine l'appel système d'origine et déplace les données vers l'application de l'espace utilisateur réelle (dans notre exemple cat)

Cela ressemble à beaucoup de surcharge juste à une seule commande d’E/S à exécuter. Et tu aurais raison. Pour le démontrer, M. Kowalczyk a tenté deux tests d'E/S différents: l'un impliquant la copie d'un gros fichier et l'autre la copie d'un grand nombre de petits fichiers. Il a comparé la vitesse de FUSE (sur la partition virtuelle montée en FAT32) gérant ces opérations par rapport à celle de FUSE. noyau (sur la partition de données formatée en EXT4), et il a constaté que FUSE contribuait effectivement de manière significative aérien.

Lors du premier test, il a copié un fichier de 725 Mo dans les deux conditions de test. Il a constaté que l'implémentation de FUSE transférait des fichiers volumineux 17% plus lentement.

Lors du deuxième test, il a copié 10 000 fichiers, chacun d'une taille de 5 Ko. Dans ce scénario, la mise en œuvre de FUSE était terminée 40 secondes plus lentement pour copier essentiellement 50 Mo de données.

Dans le monde réel, cette baisse de performance affecte n'importe lequel fichier stocké sur un stockage externe. Cela signifie des applications telles que Maps stockant des fichiers volumineux sur /sdcard, des applications musicales stockant des tonnes de fichiers musicaux, des applications d'appareil photo et des photos, etc. Toute opération d’E/S en cours impliquant le stockage externe est affectée par la surcharge de FUSE. Mais la surcharge d’E/S n’est pas le seul problème avec FUSE.

Problème n°2 – Double mise en cache

La mise en cache des données est importante pour améliorer les performances d’accès aux données. En stockant des données essentielles en mémoire, le noyau Linux est capable de rappeler rapidement ces données en cas de besoin. Mais en raison de la manière dont FUSE est implémenté, Android stocke le double de la quantité de cache nécessaire.

Comme le démontre M. Kowalczyk, un fichier de 10 Mo devrait être enregistré dans le cache avec une taille exacte de 10 Mo, mais il doit plutôt atteindre la taille du cache. d'environ 20 Mo. Ceci est problématique sur les appareils dotés de moins de RAM, car les magasins du noyau Linux utilisent le cache de pages pour stocker les données dans mémoire. M. Kowalczyk a testé ce problème de double mise en cache en utilisant cette approche :

  1. Créez un fichier d'une taille connue (pour les tests, 10 Mo)
  2. Copiez-le dans /sdcard
  3. Supprimer le cache des pages
  4. Prendre un instantané de l'utilisation du cache de pages
  5. Lire le fichier de test
  6. Prendre un autre instantané de l'utilisation du cache de pages

Ce qu'il a découvert, c'est qu'avant son test, 241 Mo étaient utilisés par le noyau pour le cache des pages. Une fois qu'il a lu son fichier de test, il s'attendait à voir 251 Mo utilisés pour le cache des pages. Au lieu de cela, il a découvert que ce noyau utilisait 263 Mo pour le cache des pages - à propos deux fois ce qui était attendu. La raison pour laquelle cela se produit est que les données sont d'abord mises en cache par l'application utilisateur qui a initialement émis l'appel d'E/S (FUSE), puis par le démon de la carte SD (EXT4 FS).

Problème n°3 – Implémentation incomplète de FAT32

Il existe deux autres problèmes liés à l'utilisation de FUSE émulant FAT32 qui sont moins connus dans la communauté Android.

La première implique horodatages incorrects. Si vous avez déjà transféré un fichier (comme une photo) et remarqué que l’horodatage est incorrect, c’est à cause de l’implémentation de FUSE par Android. Ce problème a existait pour années. Pour être plus précis, le problème concerne utime() appel système qui permet de modifier l'heure d'accès et de modification d'un fichier. Malheureusement, les appels effectués au démon sdcard en tant qu'utilisateur standard ne disposent pas de l'autorisation appropriée pour exécuter cet appel système. Il existe des solutions de contournement pour cela, mais elles vous obligent à avoir un accès root.

Si vous avez déjà transféré un fichier (comme une photo) et remarqué que l’horodatage est incorrect, c’est à cause de l’implémentation de FUSE par Android.

Le problème suivant est plus préoccupant pour les entreprises utilisant quelque chose comme un carte SD intelligente. Avant FUSE, les créateurs d’applications pouvaient surveiller Indicateur O_DIRECT afin de communiquer avec un microcontrôleur embarqué dans la carte. Avec FUSE, les développeurs ne peuvent accéder qu'à la version mise en cache d'un fichier et ne peuvent voir aucune commande envoyée par un microcontrôleur. Cela pose problème pour certaines applications d'entreprise/gouvernementales/bancaires qui communiquent avec des cartes microSD à valeur ajoutée.


Dumping FUSE pour SDCardFS

Certains OEM ont reconnu ces problèmes très tôt et ont commencé à rechercher une solution interne au noyau pour remplacer FUSE. Samsung, par exemple, a développé Carte SDFS qui est basé sur WrapFS. Cette solution intégrée au noyau émule FAT32 tout comme FUSE, mais renonce à la surcharge d'E/S, à la double mise en cache et aux autres problèmes que j'ai mentionnés ci-dessus. (Oui, permettez-moi de réitérer ce point, cette solution que Google met actuellement en œuvre est basée sur le travail de Samsung).

Google lui-même a finalement reconnu les inconvénients associés à FUSE, c'est pourquoi ils ont commencé à s'orienter vers la couche d'émulation FAT32 intégrée au noyau développée par Samsung. L'entreprise, comme mentionné dans le Les développeurs Android dans les coulisses podcast, a travaillé à rendre SDCardFS disponible pour tous les appareils dans une prochaine version du noyau. Vous pouvez actuellement voir la progression de leur travailler en AOSP.

Comme un Développeur Google expliqué plus tôt, le plus grand défi lors de la mise en œuvre d'une solution intégrée au noyau est de savoir comment mapper le nom du package à ID d'application nécessaire pour qu'un package puisse accéder à ses propres données dans un stockage externe sans nécessiter aucun autorisations. Mais cette déclaration a été faite il y a un an, et nous avons atteint le point où l’équipe appelle SDCardFS leur « prochaine grande nouveauté ». Ils ont déjà confirmé que le erreur d'horodatage redoutée a été corrigé, grâce à l'abandon de FUSE, nous pouvons donc nous attendre à voir tous les changements apportés par l'abandon de FUSE.


Idées fausses sur la vérification des faits

Si vous êtes arrivé jusqu’ici dans l’article, alors félicitations pour avoir tout suivi jusqu’à présent! Je voulais clarifier quelques questions que je me posais moi-même en écrivant cet article :

  • SDCardFS a rien à voir avec les vraies cartes SD. Il est simplement nommé ainsi car il gère l'accès aux E/S pour /sdcard. Et comme vous vous en souvenez peut-être, /sdcard est une étiquette obsolète faisant référence au stockage « externe » de votre appareil (où les applications stockent leurs médias).
  • SDCardFS est pas un système de fichiers traditionnel comme FAT32, EXT4 ou F2FS. Il s'agit d'un système de fichiers wrapper empilable qui transmet les commandes aux systèmes de fichiers émulés inférieurs (dans ce cas, il s'agirait de FAT32 sur la carte /sd).
  • Rien ne changera par rapport au MTP. Vous continuerez à utiliser MTP pour transférer des fichiers vers/depuis votre ordinateur (jusqu'à ce que Google trouve un meilleur protocole). Mais au moins l’erreur d’horodatage sera corrigée!
  • Comme mentionné précédemment, lorsque Google fait référence au « stockage externe », il parle soit du (à toutes fins utiles) à des fins) partition FAT32 virtuelle interne / carte SD OU ils parlent d'une microSD réelle, physique et amovible carte. La terminologie prête à confusion, mais c'est ce qui nous frappe.

Conclusion

En s'éloignant de FUSE et en implémentant une couche d'émulation FAT32 dans le noyau (SDCardFS), Google réduira surcharge d'E/S importante, éliminant la double mise en cache et résolvant certains problèmes obscurs liés à l'émulation de FUSE de FAT32.

Étant donné que ces modifications seront apportées à un noyau, elles peuvent être déployées sans nouvelle version majeure d'Android. Certains utilisateurs s'attendent à voir ces changements officiellement implémentés dans Android 8, mais c'est possible pour que tout futur OTA sur un appareil Pixel apporte la version 4.1 du noyau Linux sur laquelle Google a travaillé sur.

Pour certains d’entre vous, SDCardFS n’est pas un concept nouveau. En fait, les appareils Samsung l’utilisent depuis des années (c’est eux qui l’ont développé après tout). Depuis que SDCardFS a été introduit dans AOSP l'année dernière, certains développeurs de ROM et de noyau personnalisés ont choisi de l'implémenter dans leur travail. CyanogenMOD a envisagé à un moment donné de l'implémenter, mais l'a annulé lorsque les utilisateurs ont rencontré des problèmes avec leurs photos. Mais j'espère qu'avec Google prenant les rênes de ce projet, les utilisateurs d'Android sur tous les futurs appareils pourront profiter des améliorations introduites avec l'abandon de FUSE.