Plonger dans SDCardFS: comment le remplacement de FUSE par Google réduira-t-il le temps système d'I / O

Il y a plusieurs mois, Google a ajouté un élément appelé « SDCardFS » aux branches AOSP officielles du noyau Linux. À l’époque, le déménagement n’a été remarqué que par certains développeurs du noyau, mais il est par ailleurs passé sous le radar de la plupart des utilisateurs. Pas de surprise, compte tenu du fait que la plupart des utilisateurs, y compris moi-même, ne savent pas vraiment ce qui se passe sous le capot de l'OS Android et de son noyau.

Cependant, l'épisode le plus récent du podcast Android Developers Backstage a renouvelé l'intérêt pour ce sujet. Le podcast, hébergé par Chet Haase (un ingénieur logiciel senior chez Google), a exploré les modifications récentes et à venir apportées au noyau. Rom Lemarchand, développeur du noyau Linux travaillant sur l’équipe Android, était à l’émission. Le duo a principalement discuté des modifications apportées pour prendre en compte les mises à jour A / B, mais au cours des 5 dernières minutes de l'épisode, M. Lemarchand a parlé de «la prochaine étape importante» sur laquelle son équipe travaillait: SDCardFS .

Je dois avouer que j'ai appris l'existence de SDCardFS après avoir écouté ce podcast. Bien sûr, je n'ai pas été le seul à s'intéresser à ce sujet, comme l'a montré un fil de discussion Reddit récent. Cependant, je n’étais pas satisfait de l’explication de base fournie dans le podcast et, dans le but de dissiper une partie de la désinformation qui circule, j’ai moi-même effectué des recherches et interrogé quelques experts possédant des connaissances pertinentes sur le sujet. matière.

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


"Externe" est vraiment interne

Dès le départ, nous devons éliminer certaines idées fausses - sinon le reste de l'article sera très déroutant. Il est utile de discuter de l’histoire des cartes SD et des téléphones Android.

Au début des téléphones Android, presque tous les appareils utilisaient leur carte microSD pour le stockage. Cela était dû au fait que les téléphones livrés avec des capacités de stockage internes minuscules à l'époque. Cependant, les cartes SD utilisées pour stocker des applications ne fournissent souvent pas une expérience utilisateur stellaire, du moins par rapport à la vitesse à laquelle la mémoire flash interne peut lire / écrire des données. Par conséquent, l'utilisation croissante des cartes SD pour le stockage de données externe était devenue une préoccupation de l'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 de stockage d'Android étaient basées sur le fait que chaque périphérique disposait d'un emplacement de carte microSD physique réel. Mais même sur les périphériques ne contenant pas de fente pour carte SD, l’étiquette / sdcard était toujours utilisée pour désigner la puce de stockage interne. Le fait que les périphériques utilisant à la fois une carte SD physique et une puce de stockage à grande capacité de stockage nomment souvent leurs partitions basées sur la carte SD est encore plus déroutant. Par exemple, dans ces périphériques, 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 physique externe.

Ainsi, même si la carte microSD est pratiquement considérée comme un stockage externe, la convention de dénomination a pour conséquence que la «carte SD» reste longtemps dépassée par toute utilisation réelle d’une carte physique. Cette confusion avec le stockage a également posé quelques problèmes 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.

En raison du faible espace de stockage des puces de stockage internes antérieures, les utilisateurs ont appris avec frustration qu'ils ne pouvaient plus installer d'applications (car la partition / data était pleine). Pendant ce temps, leurs cartes microSD de plus grande capacité ont été reléguées au maintien de supports (tels que des photos, de la musique et des films). Les utilisateurs qui ont consulté nos forums au cours de la journée se souviendront peut-être de ces noms: Link2SD et Apps2SD. C'étaient des solutions (root) permettant 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.

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

Afin de maintenir la compatibilité et de réduire les risques de confusion, Google utilisait toujours cette partition désormais «virtuelle» pour stocker le contenu multimédia. Mais maintenant que cette partition virtuelle «sdcard» est réellement située dans / data, tout ce qui y est stocké serait comptabilisé dans l’espace de stockage de la puce de stockage interne. Il incombait donc aux équipementiers de déterminer l’espace alloué aux applications (/ données) par rapport aux supports (/ données / supports).

Deux «cartes SD» très différentes

Google espérait que les fabricants suivraient leur exemple et se débarrasseraient des cartes SD. Heureusement, avec le temps, les fabricants de téléphones ont été en mesure de se procurer ces composants à des capacités plus élevées tout en restant rentables, de sorte que le besoin de cartes SD commençait à devenir insuffisant. Mais les conventions de dénomination ont persisté pour réduire les efforts que les développeurs et les équipementiers devraient déployer pour s’ajuster. Actuellement, lorsque nous parlons de «stockage externe», nous faisons référence à l'une des deux choses suivantes: la carte microSD amovible réelle ou la partition virtuelle «SDCard» située dans / data / media. Le dernier d'entre eux, en pratique, est en réalité un stockage interne, mais la convention de nommage de Google le différencie en raison du fait que ces données sont accessibles à l'utilisateur (par exemple, lorsqu'elles sont connectées à l'ordinateur).

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


L'histoire des systèmes de fichiers virtuels Android

Maintenant que «sdcard» est traité 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 de l’Android 2.3, Google a choisi de formater «sdcard» au format VFAT (FAT virtuel). Ce changement était logique à l’époque, car le montage de VFAT permettrait à presque tous les ordinateurs d’accéder aux données stockées sur votre téléphone. Cependant, cette mise en œuvre initiale posait deux problèmes majeurs.

Le premier concerne principalement l'utilisateur final (vous). Pour connecter votre appareil à votre ordinateur, vous utiliseriez le mode de stockage de masse USB pour transférer des données. Cependant, cela nécessitait que le périphérique Android démonte la partition virtuelle avant que l'ordinateur puisse accéder aux données. Si un utilisateur souhaite utiliser son appareil alors qu’il est branché, de nombreux éléments s’affichent comme indisponibles.

L'introduction du protocole de transfert de média (MTP) a résolu ce premier problème. Lorsqu'il est branché, votre ordinateur voit votre appareil comme un «dispositif 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 à partir du périphérique. Lorsqu'un fichier doit être supprimé, MTP envoie une commande pour supprimer le fichier demandé de son stockage. Contrairement au mode de stockage de masse USB qui monte réellement la «carte sd», MTP permet à l'utilisateur de continuer à utiliser son appareil alors qu'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 les fichiers stockés sur l'appareil soient reconnus.

Deuxièmement, VFAT ne fournissait pas le type de gestion des autorisations robuste dont Google avait besoin. Dès le début, de nombreux développeurs d’applications considéraient la «carte SD» comme un dépotoir pour les données de leurs applications, sans aucun sens unifié du lieu de stockage de leurs fichiers. De nombreuses applications créeraient simplement un dossier avec son nom d'application et y stockeraient leurs fichiers.

Presque toutes les applications disponibles à ce moment-là nécessitaient l'autorisation WRITE_EXTERNAL_STORAGE pour écrire leurs fichiers d'application sur le stockage externe. Cependant, ce qui était plus troublant, c’était que presque toutes les applications avaient également besoin de l’autorisation READ_EXTERNAL_STORAGE - il leur suffisait de 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. Une telle autorisation était souvent accordée par l'utilisateur car elle était indispensable au bon fonctionnement de nombreuses applications.

Google a clairement vu cela comme problématique. L'idée derrière la gestion des autorisations est de séparer les applications auxquelles les applications peuvent et ne peuvent pas avoir accès. Si presque toutes les applications se voient accorder un accès en lecture à des données utilisateur potentiellement sensibles, l'autorisation n'a alors plus de sens. Ainsi, Google a décidé qu'ils avaient besoin d'une nouvelle approche. C’est là que FUSE entre en scène.


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 «sdcard» en tant que 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-sur-sdcard, les applications pouvaient commencer à accéder à ses données stockées sur un stockage externe sans nécessiter d'autorisations . En effet, à compter de l'API de niveau 19, READ_EXTERNAL_STORAGE n'était plus nécessaire pour accéder aux fichiers situés sur un stockage externe - à condition que le dossier de données créé par le démon FUSE corresponde au nom du package de l'application. FUSE se chargerait de la synthèse du propriétaire, du groupe et des modes de fichiers sur le stockage externe lorsqu’une application est installée.

FUSE diffère des modules dans le 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 était déjà bien compris et documenté dans le monde de Linux. Pour citer un développeur de Google à ce sujet:

«FUSE étant une API stable et agréable, aucun travail de maintenance n’est requis pour passer d’une version du noyau à l’autre. Si nous migrions vers une solution intégrée au noyau, nous nous abonnerions à la maintenance d'un ensemble de correctifs pour chaque version de noyau stable. »-Jeff Sharkey, ingénieur logiciel chez Google

Cependant, il devenait tout à fait clair que les frais généraux de FUSE introduisaient un succès dans la performance parmi d’autres problèmes. Le développeur avec qui j'ai parlé à ce sujet, Michal Kowalczyk, a rédigé un excellent blog, il y a plus d'un an, détaillant les problèmes actuels liés à FUSE. Des détails plus techniques peuvent être lus sur son blog, mais je décrirai ses découvertes (avec son autorisation) 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 dans le répertoire de stockage externe émulé au démarrage. Après cela, le démon sdcard interroge le périphérique FUSE à la recherche de messages en attente du noyau. Si vous avez écouté le podcast, vous avez peut-être entendu M. Lemarchand faire référence à FUSE introduisant des frais généraux pendant les opérations d'E / S - voici essentiellement ce qui se passe.

Dans la réalité, cet impact sur les performances affecte tout fichier stocké sur un stockage externe.

Problème n ° 1 - frais généraux d'E / S

Disons que nous créons un fichier texte simple, appelé "test.txt", et le stockons dans /sdcard/test.txt (ce qui, rappelons-le, est en réalité /data/media/0/test.txt en supposant que l’utilisateur actuel est l’utilisateur principal du périphérique). Si nous voulions lire (commande cat) ce fichier, nous nous attendrions à ce que le système émette 3 commandes: open, read, puis close. En effet, comme M. Kowalczyk le démontre en utilisant strace, c’est 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 système émet un appel système qui sera géré par le pilote FUSE dans le noyau (nous le verrons 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 requête
  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 (par exemple, open)
  5. Le démon de l'espace utilisateur envoie un appel système au système de fichiers actuel (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 au noyau par / dev / fuse
  8. Le noyau termine l'appel système d'origine et déplace les données vers l'application utilisateur réelle (dans notre exemple de chat)

Cela semble être une surcharge pour une seule commande d'E / S à exécuter. Et tu aurais raison. Pour le démontrer, M. Kowalczyk a tenté deux tests d’entrée / sortie différents: l’un impliquant la copie d’un fichier volumineux et l’autre, la copie de nombreux fichiers de petite taille. Il a comparé la vitesse de FUSE (sur la partition virtuelle montée en tant que FAT32) gérant ces opérations par rapport au noyau (sur la partition de données au format EXT4) et a constaté que FUSE contribuait effectivement à une surcharge importante.

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 FUSE transférait les 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 plus lente de 40 secondes pour copier essentiellement des données d'une valeur de 50 Mo.

Dans la réalité, cet impact sur les performances affecte tout fichier stocké sur un stockage externe. Cela signifie que des applications telles que Cartes stockant des fichiers volumineux sur / sdcard, des applications Musique stockant des tonnes de fichiers musicaux, des applications photo et des photos, etc. Toute opération d'E / S effectuée impliquant le stockage externe est affectée par la surcharge de FUSE. Mais les frais généraux d'E / S ne sont pas le seul problème avec FUSE.

Problème n ° 2 - Double Caching

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 M. Kowalczyk l'a démontré, un fichier de 10 Mo devrait être enregistré dans le cache avec exactement 10 Mo, mais la taille du cache passera à environ 20 Mo. Cela pose problème sur les périphériques dotés de moins de mémoire RAM, car les magasins du noyau Linux utilisent le cache de pages pour stocker les données en mémoire. M. Kowalczyk a testé ce problème de double cache en utilisant cette approche:

  1. Créez un fichier de taille connue (pour les tests, 10 Mo)
  2. Copiez-le dans / sdcard
  3. Déposer le cache de la page
  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 de pages. Une fois qu'il a lu son fichier de test, il s’attend à voir 251 Mo utilisés pour le cache de pages. Au lieu de cela, il a découvert que ce noyau utilisait 263 Mo pour le cache de pages, soit environ deux fois plus que prévu . Cela s'explique par le fait que les données sont d'abord mises en cache par l'application utilisateur à l'origine de l'appel d'E / S (FUSE) et ensuite par le démon sdcard (EXT4 FS).

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

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

Le premier implique des horodatages incorrects . Si vous avez déjà transféré un fichier (une photo, par exemple) et que l'horodatage est incorrect, c'est en raison de la mise en œuvre de FUSE par Android. Ce problème existe depuis des années . Pour être plus précis, le problème concerne l'appel système utime (), qui vous permet de modifier le délai d'accès et de modification d'un fichier. Malheureusement, les appels passés au démon sdcard en tant qu'utilisateur standard ne disposent pas des autorisations nécessaires pour exécuter cet appel système. Il existe des solutions de contournement pour cela, mais elles requièrent un accès root.

Si vous avez déjà transféré un fichier (une photo, par exemple) et que l'horodatage est incorrect, c'est en raison de la mise en œuvre de FUSE par Android.

Le problème suivant concerne davantage les entreprises utilisant quelque chose comme une carte SmartSD. Avant FUSE, les fabricants d’applications pouvaient surveiller l’indicateur O_DIRECT afin de communiquer avec un microcontrôleur intégré dans la carte. Avec FUSE, les développeurs ne peuvent accéder qu'à la version en cache d'un fichier et ne peuvent voir aucune commande envoyée par un microcontrôleur. Ceci est problématique pour certaines applications d'entreprise / gouvernementales / bancaires qui communiquent avec des cartes microSD à valeur ajoutée.


Dumping FUSE pour SDCardFS

Certains équipementiers ont rapidement reconnu ces problèmes et ont commencé à chercher une solution dans le noyau pour remplacer FUSE. Samsung, par exemple, a développé SDCardFS basé sur WrapFS. Cette solution intégrée au noyau émule FAT32 comme le fait FUSE, mais élimine la surcharge d’entrée / sortie, la double mise en cache et les autres problèmes que j’ai mentionnés ci-dessus. (Oui, je le répète, cette solution mise en œuvre par Google est basée sur le travail de Samsung ).

Google eux-mêmes ont finalement reconnu les inconvénients associés à FUSE, raison pour laquelle ils ont commencé à se diriger vers la couche d'émulation FAT32 dans le noyau développée par Samsung. Comme indiqué dans le podcast Backstage des développeurs Android, la société s’emploie à rendre SDCardFS disponible pour tous les périphériques dans une prochaine version du noyau. Vous pouvez actuellement voir l'état d'avancement de leurs travaux au sein du BSPA.

Comme l'a expliqué plus tôt un développeur de Google, le plus gros défi de la mise en œuvre d'une solution dans le noyau consiste à mapper le nom du package sur l'ID d'application nécessaire pour qu'un package puisse accéder à ses propres données dans un stockage externe sans nécessiter d'autorisations. Mais cette déclaration a été faite il y a un an et nous avons atteint le point où l'équipe appelle SDCardFS comme étant leur "prochain gros succès". Ils ont déjà confirmé que l'erreur d'horodatage redoutable avait été corrigée, grâce à l'abandon de FUSE, nous pouvons donc nous attendre à voir tous les changements apportés avec l’abandon de FUSE.


Vérification des faits

Si vous en êtes à ce point dans l'article, félicitations pour avoir suivi tout ce que vous avez fait jusqu'à présent! Je voulais clarifier quelques questions que j'avais moi-même en écrivant cet article:

  • SDCardFS n'a rien à voir avec les cartes SD réelles . Il est simplement nommé en tant que tel car il gère les accès d'E / S pour / sdcard. Et comme vous vous en souviendrez 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 n'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 des commandes aux systèmes de fichiers émulés inférieurs (dans ce cas, il s’agirait du format FAT32 sur la / sdcard).
  • Rien ne changera en ce qui concerne MTP . Vous continuerez à utiliser MTP pour transférer des fichiers de / vers votre ordinateur (jusqu'à ce que Google définisse un meilleur protocole). Mais au moins l'erreur d'horodatage sera corrigée!
  • Comme mentionné précédemment, lorsque Google fait référence à «Stockage externe», il s’agit de la partition FAT32 virtuelle interne / carte virtuelle (à toutes fins utiles) ou d’une carte microSD amovible, physique et réelle. La terminologie est déroutante, 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 considérablement le surcoût d'E / S, éliminera la double mise en cache et résoudra certains problèmes obscurs liés à l'émulation de FAT32 par FUSE.

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

Pour certains d'entre vous, SDCardFS n'est pas un nouveau concept. En fait, les appareils Samsung l'utilisent depuis des années (ce sont eux qui l'ont développé). 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’intégrer à leurs travaux. CyanogenMOD a, à un moment donné, envisagé de la mettre en œuvre, mais l'a annulée lorsque les utilisateurs rencontraient des problèmes avec leurs photos. Mais, espérons-le, avec Google prenant les rênes de ce projet, les utilisateurs d'Android sur tous les futurs appareils pourront tirer parti des améliorations apportées avec l'abandon de FUSE.