精华内容
下载资源
问答
  • sdcardfs

    2021-01-24 22:29:50
    整理脑图 参考资料 sdcardfs浅析 https://blog.csdn.net/pen_cil/article/details/80427314?utm_medium=distribute.pc_relevant.none-task-blog-baidujs_title-1&spm=1001.2101.3001.4242 sdcardfs权限生成 ...

    整理脑图

    在这里插入图片描述

    代码解读

    权限

    main:
    权限主要检查函数 sdcardfs_permission->get_mode-> generic_permission(内核原生通用权限检查函数)

    其他:
    文件从操作钩子函数,如sdcardfs_open 调用check_caller_access_to_name, 决绝访问autorun.inf,.android_secure,android_secure
    override_fsids 保存任务的cred权限上下文

    packagelist.c:
    通过hash表保存appid, appid用户生成 app的gid,uid

    derived_perm.c:
    提供get_derived_permission接口给sdcardfs_lookup,在建立文件dentry时候会被调用,建立文件权限。

    在这里插入图片描述

    参考资料

    sdcardfs浅析
    https://blog.csdn.net/pen_cil/article/details/80427314?utm_medium=distribute.pc_relevant.none-task-blog-baidujs_title-1&spm=1001.2101.3001.4242

    sdcardfs权限生成
    https://blog.csdn.net/scnutiger/article/details/102511583?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.baidujs&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.baidujs

    展开全文
  • sdcardfs 浅析

    2020-05-22 17:00:00
    sdcardfs是三星基于wrapfs框架开发的虚拟文件系统,并凭借其出色的IO性能,在Android O上替代FUSE(File system in Userspace),成功上位。不...

    sdcardfs是三星基于wrapfs框架开发的虚拟文件系统,并凭借其出色的IO性能,在Android O上替代FUSE(File system in Userspace),成功上位。不提FUSE单讲sdcardfs的文章算不上一次齐全的解析,所以本文在介绍sdcardfs的同时,也会对比sdcardfs和FUSE的框架与原理、分析为何FUSE被sdcardfs替代。希望通过对比解析清楚,那让我们一步步走进sdcardfs。

    sdcardfs的诞生

    sdcardfs是基于wrapfs开发的。wrapfs是什么、又是如何在FUSE,EXT的文件系统大家族中拥有一席之地呢?我们借助wrapfs的开发者Erez对文件系统的分类来分析一下:

    表1.文件系统的分类

    大多数文件系统可以归纳到表1总结的三类中。第一类是底层文件系统,内核空间的优势保障了这类文件系统的优越性能,但驾驭这类文件系统要求开发者对操作系统有深入理解,并不利于开发和调试。第二类用户层文件系统解决了这个痛点,用户层文件系统将晦涩难懂的底层文件系统藏在内核中,提供接口方便开发者调用开发新的文件系统。然而成也用户层,败也用户层,虽然比底层文件系统更容易开发与调试,但在用户态和内核态的来回切换导致性能大大降低。

    鱼与熊掌不可兼得的困境推动了第三种文件系统的诞生---可堆叠文件系统。它的性能表现接近底层文件系统,而开发成本接近用户层文件系统。wrapfs作为一种可堆叠文件系统的框架,为sdcardfs提供必需、或可选择的函数来帮助开发者开发。处于内核空间和用户空间的中间层的sdcardfs,并不真正地管理磁盘而是将操作命令和参数由上层传给底层。

    sdcardfs首先由三星开发,后由Google接手并应用于Android O,然而在AOSP官方承认sdcardfs之前,sdcardfs已经被众多手机厂商商用,比如华为也有自己开发的一套sdcardfs。

    为sdcardfs解除误会

    在梳理sdcardfs是如何运作之前,有几点常年围绕着sdcardfs的困惑点要先说明清楚。如果你也是第一次接触sdcardfs,一定会奇怪,sdcardfs是sd卡的文件系统吗?\sdcard分区又和他们是什么关系呢?

    我们先来说说sd卡和\sdcard分区,早期的安卓手机因为内部存储空间太小,所以会使用sd卡这种外部存储来增大可用空间。与此同时\sdcard分区也出现了,主要存储一些音乐电影等文件。然而这并不代表\sdcard分区就归sd卡所用。在某些同时拥有内部存储空间和sd卡的设备上,\sdcard实际代表内部存储空间,而\storage\sdcardfs1指外部存储。可以说sd卡的流行确实引出了\sdcard分区,但是这两者之间并没有一对一的所属关系。

    另外,sdcardfs文件系统也不是为了管理sd卡而开发的文件系统。而是为了解决其他两类文件系统的痛点而开发的。这就不得不先说说FUSE是怎么来的:当年的文件系统并没有权限管理的能力,当应用A和应用B同时将数据存在外部存储中,并且同时拥有外部存储的读写权限时,也意味着应用A、B有权限读到对方的数据。这是极其不安全的,尤其当应用的敏感信息也存储在外部存储的时候。所以FUSE的一大功能就是赋予权限管理的能力。然而FUSE受自身框架限制,不可避免地拥有IO latency,double caching等痛点得不到解决,以至于一度被sdcardfs所替代。

    sdcardfs也拥有case folding, 权限管理等其他功能。而本文作为入门级浅析,主要集中在sdcardfs的框架梳理和对比中,会更详细分析sdcardfs和FUSE框架有何不同,sdcardfs又是如何避免了FUSE的痛点。

    框架梳理-始于挂载

    和其他文件系统一样,使用sdcardfs也需要先挂载。在init_sdcardfs_fs()中首先为inode,dentry,packagelist申请slab缓存,然后调用resigter_filesystem注册文件系统。和init_sdcardfs_fs()对应自然会有exit_sdcardfs_fs()这个函数来注销sdcardfs,虽然并不常用。

    框架梳理-没有对比就没有伤害

    为了更好地理解sdcardfs何以替代FUSE,这里先梳理一下FUSE框架:

    图1.FUSE框架

    作为中间层的角色,FUSE拥有可加载的内核驱动模块(图中蓝色部分)以及提供API的用户空间的库(图中绿色部分)。其中内核驱动模块注册了/dev/fuse块设备来支持和用户态的通信,而用户空间的守护进程则时刻准备从/dev/fuse中读取并处理操作命令,然后将结果通过/dev/fuse返回给内核空间。用户空间提供的接口方便开发者忽略底层文件系统的存在,基于libfuse实现自定义的操作命令的处理方式。

    当操作挂载FUSE的路径时,用户的命令会随着图中的橘色剪头所示,经过如下一段旅程:1)当用户产生操作命令时,会通过glibc的系统调用将命令传递到内核层的VFS;2)VFS根据所在分区的文件系统将命令传递给对应文件系统的接口,这里挂载的文件系统当然是FUSE;3)FUSE内核模块收到命令后,会将命令分类放在某个队列中等待处理(包括pending,background,processing,interrupts,forgets五个队列,这里不展开讨论队列策略,感兴趣可参考文献1的3.1.1章节[1])/dev/fuse块设备会通过既定的通信协议将操作请求发送给上层FUSE守护进程来“处理”请求,而如何处理操作请求,取决于开发者在守护进程中的具体实现,这就是用户态文件系统开发者需要开发的部分。4)FUSE的守护进程将操作处理完后,将处理结果返回块设备/dev/fuse;5)FUSE内核模块将处理结果返回给VFS,VFS再将结果原路返回给上层。

    分析可发现整个流程中,发生了六次内核态与用户态的切换,这种高负担的操作解释了为何用户层文件系统的性能差。而FUSE确确实实减少了开发成本,如图所示,开发者并不需要了解底层文件系统如何工作,甚至不需要深入理解内核,根据libfuse提供的API接口可以快速开发出简单的定制化的文件系统。

    sdcardfs作为位于内核的中间层,和底层文件系统相比也减少了开发成本,并且处理操作命令的流程非常直观清晰,没有FUSE那么弯弯绕绕的流程:

    图2.带sdcardfs后的框架

    如图所示,sdcardfs仍然处于内核空间。它不同于FUSE,不是内核态和用户态的中间层,而是处于VFS与底层文件系统的中间。在没有sdcardfs的时候,虚拟文件系统层将操作命令直接向下传给指定的文件系统,比如EXT4或F2FS;加上sdcardfs之后,操作命令会经过VFS->sdcardfs->底层文件系统。流程简洁明了无需多言,问题的关键在于,sdcardfs如何将操作命令中的数据快速准确地转发给底层文件系统,并且不会因为sdcardfs自身的存在而影响原来的操作性能。

    在底层文件系统中,我们需要inode、dentry、file多个struct来定位某个文件或数据的所在位置。那么多了一层sdcardfs之后,如何保证IO性能呢?sdcardfs文件系统内也构建对应的inode、dentry、file结构体,并和底层文件系统的inode、dentry、file结构体链接起来,如图所示:

    图3.sdcardfs与底层文件系统的链接[3]

    通过图3的链接,如果知道sdcardfs的file结构体,可以找到底层文件系统的file结构体,继而定位其dentry和inode等信息。

    sdcardfs VS FUSE

    sdcardfs解决了FUSE的很多问题才成功上位的,比如上文提到的IO latency以及double caching。

    IO latency:依据第二节提到的FUSE的框架图,具体分析可得每一个读写命令都将经过六次的用户态和内核态的转换:1)用户空间的应用将系统调用传给FUSE内核驱动;2)FUSE内核驱动通知FUSE用户态守护程序有新的操作命令,用户态守护程序从dev/fuse读取命令;3)守护程序分析命令并下传给底层文件系统;4)底层文件系统执行操作,并将数据返回给FUSE守护程序;5)守护程序将结果通过dev/fuse传给FUSE内核驱动;6)FUSE内核驱动将结果返回给上层应用结束。而在sdcardfs的框架下,内核中仍然只是open, read, close三步操作。

    这种架构的劣势尤其体现在多个小文件的操作上。每一个小文件都将引起六次用户态和内核态的切换,这种框架下的用户态文件系统操作速度远远低于底层文件系统:在复制10000个50kb的小文件的实验中,FUSE比没有FUSE慢了40秒[2],如图4所示,在没有FUSE中间层的EXT4文件系统下,复制10000个50kb小文件需要17.27秒,而FUSE框架下需要1分03秒03毫秒。

    而sdcardfs从架构上避免了不用空间的频繁切换,将切换次数从6次减少到必需的2次切换,即操作命令下发和结果返回,使其性能接近底层文件系统。

    图4.复制大量小文件性能对比

    Double caching:在FUSE框架中的每一次读写调用,数据都会从内核内存复制到用户层缓存,原本的page cache因为FUSE的存在,又大了一倍。而sdcardfs只作为操作和参数的传递者而非处理者,所以从架构中避免了重复缓存的问题。

    总结

    本文基于与FUSE的对比,浅析了sdcardfs的框架和优势。正因为sdcardfs解决了FUSE IO操作延迟和重复缓存的主要痛点,使它在底层文件系统和用户层文件系统的夹缝中生存了下来。sdcardfs已不是当下流行的概念,然而sdcardfs还有很多可提升的空间。

    本文篇幅有限,还有很多内容没有覆盖到,比如sdcardfs的权限管理,case folding,storage tracking等功能的介绍。希望这篇会有后续,或者其他同学也针对sdcardfs的功能来篇分析。

    参考资料

    [1]用户空间文件系统FUSE:架构和实现细节

    [2]Diving into SDCardFS:How Google’s FUSE Replacement Will Reduce I\O Overhead

    [3]A Stackable File System Interface For Linux, Erez Zadok and Ion Badulescu

    扫码关注
    “内核工匠”微信公众号
    Linux 内核黑科技 | 技术文章 | 精选教程
    展开全文
  • Android关闭SdcardFS

    2019-08-26 15:36:37
    Author:Gary Date:2019-8-26 ... 由于项目先在Android6上进行实现的,现需要移植到Android8上。但是Android8上启用了SdcardFS,与原有设计中的Fuse不符,重新适配SdcardFS工作量比较大,找到如下方法可以关闭SdcardFS...

    Author:Gary
    Date:2019-8-26
    参考博客:https://blog.csdn.net/pen_cil/article/details/79842706

    由于项目先在Android6上进行实现的,现需要移植到Android8上。但是Android8上启用了SdcardFS,与原有设计中的Fuse不符,重新适配SdcardFS工作量比较大,找到如下方法可以关闭SdcardFS使用旧的Fuse文件系统:

    打开安卓目录下的文件:system/core/sdcard/sdcard.cpp,第412行:

     static bool supports_sdcardfs(void) {
        std::string filesystems;
        if (!android::base::ReadFileToString("/proc/filesystems", &filesystems)) {
            PLOG(ERROR) << "Could not read /proc/filesystems";
            return false;
        }
        for (const auto& fs : android::base::Split(filesystems, "\n")) {
            if (fs.find("sdcardfs") != std::string::npos) return true;
        }
        return false;
    }
    

    添加一行,直接返回false即可:

    static bool supports_sdcardfs(void) {
    	return false;
        std::string filesystems;
        if (!android::base::ReadFileToString("/proc/filesystems", &filesystems)) {
            PLOG(ERROR) << "Could not read /proc/filesystems";
            return false;
        }
        for (const auto& fs : android::base::Split(filesystems, "\n")) {
            if (fs.find("sdcardfs") != std::string::npos) return true;
        }
        return false;
    }
    

    修改完成后重新编译刷入,在adb shell中输入mount可以看到已经变成了fuse文件系统:
    在这里插入图片描述

    展开全文
  • SDcardFS文件系统浅析(三) - SDcardfs挂载过程 源码kernel/fs/sdcardfs/main.c 挂载过程在init_sdcardfs_fs函数中,下面简要看下源码,分析下挂载过程 init_sdcardfs_fs函数分析 kernel/fs/sdcardfs/main.c ...

    SDcardFS文件系统浅析(三) - SDcardfs挂载过程

    源码kernel/fs/sdcardfs/main.c

    挂载过程在init_sdcardfs_fs函数中,下面简要看下源码,分析下挂载过程

    • init_sdcardfs_fs函数分析

      kernel/fs/sdcardfs/main.c
      static int __init init_sdcardfs_fs(void)
      {
      int err;
      
      pr_info("Registering sdcardfs " SDCARDFS_VERSION "\n");
      
      err = sdcardfs_init_inode_cache();//利用kmem_cache_create申请inode_info和inode_data 缓存
      if (err)
          goto out;
      err = sdcardfs_init_dentry_cache(); //利用kmem_cache_create申请dentry缓存
      if (err)
          goto out;
      err = packagelist_init(); //利用kmem_cache_create申请hashtab缓存
      if (err)
          goto out;
      err = register_filesystem(&sdcardfs_fs_type);
      out:
      if (err) {
          sdcardfs_destroy_inode_cache();
          sdcardfs_destroy_dentry_cache();
          packagelist_exit();
      }
      return err;
      }

      init_sdcardfs_fs函数相对比较简单主要是inode、dentry缓存和packagelist的初始化,初始化完成后注册SDcardfs文件系统

      1. 利用kmem_cache_create来申请inode和dentry缓存
      2. 利用kmem_cache_create来申请hashtable缓存
        • hashtable(散列表),其查找的效率很高,inode和dentry是内存中的数据,而数据的来源是硬盘,如果我们获得了inode和dentry数据,加到hashtable中,方便下一次的快速获取,而不是再次访问硬盘。
      3. 在inode、dentry、hashtable完成初始化后,调用register_filesystem,将sdcardfs_fs_type对象注册到内核。

      在将sdcardfs_fs_type注册到内核后,但还未完成mount过程,除了根文件系统系统是在内核引导阶段就被安装之外,其他文件或者由初始化脚本安装,或者由用户使用mount命令安装在已安装文件系统的某一个目录上。

    • 挂载过程

      在内核的启动过程中通过init_sdcardfs_fs将sdcardfs的sdcardfs_fs_type对象注册到内核中,之后在安卓的启动过程中将其挂载,其配置是否挂载sdcardfs取决于system.prop的一个系统属性

      persist.sys.sdcardfs=force_on //其会使系统在最终挂载data分区为sdcardfs
      注:在安卓8.0上,Google好像取消了该属性,因为8.0原生支持sdcardfs,没有该属性的配置的必要,但是在7.0的代码中看到它的身影

      通过配置该属性后,系统后再启动过程中判断该属性值来决定是否挂载data分区为sdcardfs,可以在sdcardfs_setup中看到其挂载过程,源码路径:

      安卓8.0 /system/core/sdcard/sdcard.cpp 需要翻墙

      /system/core/sdcard/sdcard.cpp
      static bool sdcardfs_setup(const std::string& source_path, const std::string& dest_path,
                               uid_t fsuid, gid_t fsgid, bool multi_user, userid_t userid, gid_t gid,
                               mode_t mask, bool derive_gid, bool default_normal) {
        // Try several attempts, each time with one less option, to gracefully
        // handle older kernels that aren't updated yet.
        for (int i = 0; i < 4; i++) {
            .............
            if (mount(source_path.c_str(), dest_path.c_str(), "sdcardfs", //其通过该函数挂载sdcardfs
                      MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_NOATIME, opts.c_str()) == -1) {
                PLOG(WARNING) << "Failed to mount sdcardfs with options " << opts;
            } else {
                return true;
            }
        }
        return false;
      }
    • exit_sdcardfs_fs函数

      static void __exit exit_sdcardfs_fs(void)
      {
      sdcardfs_destroy_inode_cache();
      sdcardfs_destroy_dentry_cache();
      packagelist_exit(); //前三行利用kmem_cache_destroy来释放申请的inode、dentry、hashtable缓存
      unregister_filesystem(&sdcardfs_fs_type);
      pr_info("Completed sdcardfs module unload\n");
      }

      exit_sdcardfs_fs与init_sdcardfs_fs函数相反,比较简单,但一般不会用到

      1. 利用kmem_cache_destroy来释放申请的inode、dentry、hashtable缓存
      2. 在inode、dentry、hashtable释放后,调用unregister_filesystem,将sdcardfs_fs_type从内核中注销
    展开全文
  • SDcardFS文件系统浅析(五)- sdcardfs在文件系统调用中 上一节从ftrace中可以看到在cat过程中sdcardfs调用顺序,我们知道了sdcardfs的调用流程,但是这些函数在整个文件系统的调用中是怎么配合的,怎么被串起来的...
  • sdcardfs之一简介

    千次阅读 2019-10-11 22:17:53
    1. sdcardfs是什么? sdcardfs最初由三星开发,从Android8.0开始google开始接管sdcardfs用来替换原本的FUSE文件系统。(以下代码基于android 9.0的sdcardfs) 它跟sdcard(TF卡)没有关系,并不是一个磁盘文件系统。...
  • sdcardfs之二权限控制

    千次阅读 2019-10-11 22:33:33
    sdcardfs如果没有独特的权限控制,只是转发用户态的参数和操作给底层文件系统就没有其存在的意义了。所以接下来关注sdcardfs是如何做到权限控制的。 1. linux的UGO文件权限生成 sdcardfs需要给vfs呈现linux标准的...
  • SDcardFS文件系统浅析(四)- cat 过程

    千次阅读 2018-05-24 22:01:48
    SDcardFS文件系统浅析(四)- cat 过程 我们暂时先跳过源码,通过在sdcardfs文件系统中cat一个文件的过程,来了解sdcardfs的调用过程,在对其调用流程有个清晰理解后再去看代码,会事半工倍。 通过ftrace设置graph...
  • SDcardFS文件系统浅析(一) - sdcarfs历史 由于安卓O的已经官方支持SDcardFS文件系统,在开发过程中也遇到一些问题,特此浅要分析下SDcardFS 1、Fuse(Filesystem in Userspace) 早期的android系统没有使用fuse...
  • 1. 打开sdcardfs config arch/arm|arm64/configs/sprd_xxx_defconfig: -# CONFIG_SDCARD_FS is not set +CONFIG_SDCARD_FS=y 2. 使用sdcardfs build/target/product/emulated_storage.mk: -PRODUCT_PROPERTY_...
  • Android文件访问权限的管理机制以及SDCardFS 1. 原生Linux文件访问权限控制 原生的Linux操作系统是通过拥有者 ID(uid) 和群组 ID(gid)对文件的访问权限进行管理,如: user0@user0:testLinuxPermission$ ls -l 访问...
  • 對比fuse和sdcardfs,對同一個文件訪問,fuse需要經過6次用戶態與內核態的切換,但是sdcardfs只需要經過2次切換。另外fuse在內核中有多個隊列,隊列中元素的出列要等帶前面的元素先出列。因此單次文件訪問,fuse比...
  • SDcardFS文件系统浅析(二) - inode、dentry、super_block 在开始之前,首先得理解文件系统中inode、dentry、super_block的含义,下面简单介绍下这三个结构的作用,但不做代码层面分析,有个大概认知即可,如果详细...
  • [RK3288][Android6.0] Fuse将被SDCardFS替换

    千次阅读 2017-08-16 16:42:05
    External实际上是Internal ...很久以前,每台Android设备都使用外插microSD卡用于存储,这是因为内部的storage容量太小了。...Android O will be bringing the new SDCardFS to replace FUSE
  • 基于fuse的sdcard存储方案缺点 android默认的方案,是基于用户空间文件系统,其最大的优点是移植性好。 分析android 默认fuse方案操作流程,如上图。可看出其最大缺点是: fuse文件系统和sdcard daemon 必须频繁...

空空如也

空空如也

1 2 3 4 5 ... 13
收藏数 251
精华内容 100
关键字:

sdcardfs