如何在嵌入式Linux中高效地在VFAT分区上创建大文件

2024-04-21

我正在尝试在嵌入式 Linux 盒子中使用“dd”命令在 VFAT 分区上创建一个大的空文件:

dd if=/dev/zero of=/mnt/flash/file bs=1M count=1 seek=1023

目的是跳过前 1023 个块并在文件末尾仅写入 1 个块,这在本机 EXT3 分区上应该非常快,而且确实如此。然而,这个操作在 VFAT 分区上变得非常慢,并出现以下消息:

lowmem_shrink:: nr_to_scan=128, gfp_mask=d0, other_free=6971, min_adj=16
// ... more `lowmem_shrink' messages

另一种尝试是 fopen() VFAT 分区上的一个文件,然后 fseek() 到最后写入数据,这也被证明很慢,并且还显示来自内核的相同消息。

那么基本上,有没有一种快速方法可以在 VFAT 分区上创建文件(无需遍历前 1023 个块)?

Thanks.


为什么 VFAT“跳过”写入速度如此之慢?

除非 VFAT 文件系统驱动程序在这方面进行了“欺骗”,否则在 FAT 类型文件系统上创建大文件总是需要很长时间。为了遵守 FAT 规范,驱动程序必须分配所有数据块并对它们进行零初始化,即使您“跳过”写入也是如此。这是因为 FAT 具有“簇链接”功能。

造成这种情况的原因是 FAT 无法支持以下任一功能:

  • 文件中的 UN*X 式“漏洞”(又名“稀疏文件”)
    这就是您在 ext3 上使用测试用例创建的内容 - 一个没有数据块分配给其前 1GB-1MB 的文件,最后是一个实际提交的 1MB 零初始化块。
  • NTFS 样式的“有效数据长度”信息。
    在 NTFS 上,文件可以分配未初始化的块,但文件的元数据将保留two大小字段 - 一个表示文件的总大小,另一个表示实际写入文件的字节数(从文件的开头开始)。

如果没有支持这两种技术的规范,如果跳过一个范围,文件系统将始终必须分配和清零所有“中间”数据块。

还要记住,在 ext3 上,您使用的技术实际上并不allocate文件的块(最后 1MB 除外)。如果您需要预先分配的块(不仅仅是设置大文件的大小),您还必须在那里执行完整写入。

如何修改 VFAT 驱动程序来处理这个问题?

目前,驱动程序使用Linux内核功能cont_write_begin()甚至启动对文件的异步写入;这个函数看起来像:

/*
 * For moronic filesystems that do not allow holes in file.
 * We may have to extend the file.
 */
int cont_write_begin(struct file *file, struct address_space *mapping,
                    loff_t pos, unsigned len, unsigned flags,
                    struct page **pagep, void **fsdata,
                    get_block_t *get_block, loff_t *bytes)
{
    struct inode *inode = mapping->host;
    unsigned blocksize = 1 << inode->i_blkbits;
    unsigned zerofrom;
    int err;

    err = cont_expand_zero(file, mapping, pos, bytes);
    if (err)
            return err;

    zerofrom = *bytes & ~PAGE_CACHE_MASK;
    if (pos+len > *bytes && zerofrom & (blocksize-1)) {
            *bytes |= (blocksize-1);
            (*bytes)++;
    }

    return block_write_begin(mapping, pos, len, flags, pagep, get_block);
}

这是一个简单的策略,但也是一个页面缓存回收器(您的日志消息是调用的结果)cont_expand_zero()它完成所有工作,并且不是异步的)。如果文件系统将这两项操作分开——一项任务进行“真正的”写入,另一项任务进行零填充,那么它会显得更快。

在仍然使用默认的 Linux 文件系统实用程序接口的情况下实现这一点的方法是在内部创建两个“虚拟”文件 - 一个用于要填零的区域,另一个用于实际要写入的数据。真实文件的目录条目和 FAT 簇链仅在后台任务实际完成后才会更新,方法是将其最后一个簇与“zerofill 文件”的第一个簇链接,并将该文件的最后一个簇与“zerofill 文件”的第一个簇链接。实际写入文件”。人们还希望进行直接写入来进行零填充,以避免破坏页面缓存。

注意:虽然这一切在技术上都是可行的,但问题是进行这样的改变有多值得?谁一直需要这个手术?会有什么副作用?
现有的(简单)代码对于较小的跳过写入来说是完全可以接受的,如果您创建一个 1MB 文件并在末尾写入一个字节,您将不会真正注意到它的存在。只有当您选择的文件大小符合 FAT 文件系统允许您执行的操作的限制时,它才会对您产生影响。

其他选项...

在某些情况下,手头的任务涉及两个(或更多)步骤:

  1. 使用 FAT 重新格式化(例如)SD 卡
  2. 将一个或多个大文件放入其中以“预填充”该卡
  3. (取决于应用程序,可选)
    预填充文件,或者
    将环回文件系统映像放入其中

我处理过的一个案例我们折叠了前两个 - 即修改mkdosfs在创建 (FAT32) 文件系统时预分配/预创建文件。这非常简单,在写入 FAT 表时,只需创建分配的簇链,而不是填充“空闲”标记的簇。它还具有保证数据块是连续的优点,以防您的应用程序从中受益。你可以决定让mkdosfs not清除数据块之前的内容。例如,如果您知道准备步骤之一涉及写入整个数据或执行 FAT 上的 ext3-in-file-on-FAT(非常常见的事情 - Linux 设备、用于与 Windows 应用程序/GUI 进行数据交换的 SD 卡),那么就不需要将任何东西清零/双重写入(一次用零,一次用其他任何东西)。如果您的用例符合此要求(即格式化卡是“初始化使用”过程的有用/正常步骤),请尝试一下;经过适当修改的mkdosfs是其一部分TomTom 的 dosfsutils 源代码,请参阅mkdosfs.c搜索-N命令行选项处理 http://www.tomtom.com/gpl/arm11/dosfstools-2.11-tt695638.tar.gz.

正如前面提到的,在谈论预分配时,还有posix_fallocate() http://pubs.opengroup.org/onlinepubs/009696799/functions/posix_fallocate.html。目前在 Linux 上使用 FAT 时,这基本上与手动操作相同dd ...,即等待填零。但函数的规范并不要求它是同步的。块分配(FAT 簇链生成)必须同步完成,但 VFAT 磁盘上的不同大小更新和数据块填零可以后台/延迟(即,要么在后台以低优先级完成,要么仅在明确指定的情况下完成)请求通过fdsync() / sync()以便该应用程序可以例如分配块,写入非零内容本身...)。但这就是技术/设计;我不知道有人做过内核修改,即使只是为了实验。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在嵌入式Linux中高效地在VFAT分区上创建大文件 的相关文章

  • 如何在Linux上用C/C++编写Web服务器[关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我正在考虑在 Linux 平台上开发一个小型 阅读 初级 Web 服务器 但我不知道从哪里开始 我希望它能够做的是 监听特定端口 接受
  • Linux 内核使用的设备树文件 (dtb) 可视化工具? [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我正在寻找一个可以图形化表示Linux内核中使用的硬件设备树的工具 我正在尝试了解特定 Arm 芯片组
  • 如何获取与 shell 中的文件名模式匹配的所有文件的总文件大小?

    我正在尝试仅使用 shell 来计算与文件名模式匹配的所有文件 在目录树中 的总大小 以字节为单位 这是我到目前为止所拥有的 find name undo exec stat c s awk 总计 1 END 打印总计 有没有更简单的方法来
  • 如何在C(Linux utf8终端)中打印“盒子抽屉”Unicode字符?

    我正在尝试显示 方框图范围 2500 257F 中的 Unicode 字符 它应该是标准 utf8 Unicode 标准 版本 6 2 我根本做不到 我首先尝试使用旧的 ASCII 字符 但 Linux 终端以 utf8 显示 并且没有显示
  • 在 Linux 中重新启动时,新创建的文件变为 0 kb(数据被覆盖为空)

    我遇到了一个奇怪的问题 这让我发疯 当前的任务是在 root 用户第一次登录时启动一组文件 并在同一用户第二次登录时启动另一组文件 我决定使用 profile 和 bashrc 文件 并在第一次登录期间发生的任务结束时重新加载 bashrc
  • 在 Windows 中从文件名获取驱动器号

    是否有 Windows API 函数可以从 Windows 路径中提取驱动器号 例如 U path to file txt U path to file txt 在正确整理的同时 relative path to file txt alte
  • bash 将输出重定向到文件,但结果不完整

    重定向命令输出的问题已经被问过很多次了 但是我有一个奇怪的行为 我使用的是 bash shell debian 版本 4 3 30 1 release 并尝试将输出重定向到文件 但并非所有内容都记录在文件中 我尝试运行的 bin 文件是 l
  • 为什么此 NASM 代码会打印我的环境变量?

    本学期我刚刚完成计算机体系结构课程 除其他外 我们一直在涉足 MIPS 汇编并在 MARS 模拟器中运行它 今天 出于好奇 我开始在我的 Ubuntu 机器上摆弄 NASM 基本上只是将教程中的内容拼凑起来 并感受一下 NASM 与 MIP
  • 嵌入清单文件以要求具有 mingw32 的管理员执行级别

    我正在 ubuntu 下使用 i586 mingw32msvc 交叉编译应用程序 我很难理解如何嵌入清单文件以要求 mingw32 具有管理员执行级别 对于我的例子 我使用了这个hello c int main return 0 这个资源文
  • Linux无法删除文件

    当我找到文件时 我在删除它们时遇到问题 任务 必须找到带有空格的文件并将其删除 我的尝试 rm find L root grep i 但我有错误 rm cannot remove root test No such file or dire
  • Ubuntu Python shebang 线不工作

    无法让 shebang 线在 Ubuntu 中为 python 脚本工作 我每次只收到命令未找到错误 test py usr bin env python print Ran which python usr bin python 在 sh
  • Python 3.4.3 subprocess.Popen 在没有管道的情况下获取命令的输出?

    我试图将命令的输出分配给变量 而不让命令认为它正在通过管道传输 原因是 如果正在通过管道传输 则相关命令会给出未格式化的文本作为输出 但如果从终端运行 则会给出颜色格式化的文本 我需要获取这种颜色格式的文本 到目前为止我已经尝试了一些事情
  • 如何在 Linux 上通过 FTP 递归下载文件夹 [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 Locked 这个问题及其答案是locked help locked posts因为这个问题是题外话 但却具有历史意义 目前不接受新的答案
  • grep 排除文件的数组参数

    我想从我的文件中排除一些文件grep命令 为此我使用参数 exclude excluded file ext 为了更容易阅读 我想使用包含排除文件的 bash 数组 EXCLUDED FILES excluded file ext 然后将
  • 找不到包“gdk-pixbuf-2.0”

    我正在尝试在 Amazon Linux 发行版实例上构建 librsvg 我已经通过 yum 安装了大部分依赖项 其中一些在实例上启用的默认 yum 存储库中不可用 因此必须从头开始构建它们 我已经走了很远 但还停留在最后一点 跑步时sud
  • SSH,运行进程然后忽略输出

    我有一个命令可以使用 SSH 并在 SSH 后运行脚本 该脚本运行一个二进制文件 脚本完成后 我可以输入任意键 本地终端将恢复到正常状态 但是 由于该进程仍在我通过 SSH 连接的计算机中运行 因此任何时候它都会登录到stdout我在本地终
  • 适用于 Linux 的轻量级 IDE [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • docker 非 root 绑定安装权限,WITH --userns-remap

    all 尝试让绑定安装权限正常工作 我的目标是在容器中绑定安装卷 以便 a 容器不以 root 用户身份运行入口点 二 docker daemon 配置了 userns remap 这样容器 主机上没有 root c 我可以绑定挂载和读 写
  • Google BQ:运行参数化查询,其中参数变量是 BQ 表目标

    我正在尝试从 Linux 命令行为 BQ 表目标运行 SQL 此 SQL 脚本将用于多个日期 客户端和 BQ 表目标 因此这需要在我的 BQ API 命令行调用中使用参数 标志 parameter 现在 我已经点击此链接来了解参数化查询 h
  • 如何为 Linux 桌面条目文件指定带有相对路径的图标?

    对于我的一个 Linux 应用程序 我有应用程序二进制文件 一个 launcher sh 脚本 针对 LD LIBRARY PATH 和一个 desktop 文件 所有这些都位于同一文件夹中 我想使用图标的相对路径而不是绝对路径 我试过了

随机推荐