
存储【免费下载链接】mergerfsa featureful union filesystem项目地址https://gitcode.com/gh_mirrors/me/mergerfs点击查看免费下载本文围绕 mergerfs 的branches选项展开它是 mergerfs 定义“哪些存储路径组成资源池”的核心配置决定了挂载池的边界。你将学会branches的完整语法含逐分支mode与minfreespace、分支路径在解析阶段的 glob 展开与realpath规范化流程、通过运行时 API 动态增删分支的操作方式以及作者推荐的大规模分支目录布局、挂载点权限锁定与格式化实践。读完之后你可以把多台不同介质HDD/SSD/NVMe/远程文件系统组织成一个稳定、可运维的 mergerfs 挂载点。1. branches 是什么用冒号分隔的路径池branches参数是一个以冒号:分隔的路径列表这些路径会被“池化”pooled在一起形成 mergerfs 的挂载内容。路径是否位于同一文件系统、底层文件系统类型是什么在合理范围内都不重要。两条重要的行为约束来自 branches 文档容量指标不会重复计算位于同一文件系统上的多个路径其已用/可用空间指标不会被重复统计避免statfs报告的总容量被虚高特性透传底层文件系统不支持的特性如某些文件系统上的文件属性、扩展属性会返回相应的错误mergerfs 不会伪造支持。branches是 mergerfs 主配置项之一在 src/config.cpp 中与branches配置结构绑定其解析与池管理实现集中在 src/branch.hpp、src/branches.cpp 与 src/branches.hpp。2. 逐分支选项mode 与 minfreespace每个分支路径可以携带两个逐分支选项mode模式和minfreespace该分支的最小剩余空间阈值。写法是在路径尾部追加选项之间用逗号分隔例如/mnt/hdd/disk0RW,1234完整写法即路径MODE,minfreespace。其中minfreespace的作用与语法和 全局 minfreespace 选项 完全一致全局默认4G只是作用于单个分支不指定时默认继承全局值。2.1 三种分支模式RWread/write默认行为。该分支参与所有策略policy类别的计算ROread-only该分支被排除在create与action策略之外。效果等同于把底层文件系统只读挂载但处理更快NCno-create该分支仅被排除在create策略之外——不能在其上创建新文件但允许修改和删除已有文件。从源码看模式定义在 src/branch.hpp 的Branch::Mode枚举中RO/RW/NC并提供ro()、nc()、ro_or_nc()三个判定方法。策略在挑选 create 目标分支时会调用这些方法例如ff策略first free挑第一个有空间的分支的 create 流程在 src/policy_ff.cpp 中for(auto branch : *ibranches_) { if(branch.ro_or_nc()) error_and_continue(error,EROFS); // RO/NC 分支直接跳过 rv fs::info(branch.path,info); ... if(info.readonly) error_and_continue(error,EROFS); if(info.spaceavail branch.minfreespace()) error_and_continue(error,ENOSPC); // 剩余空间低于阈值则跳过 obranches_.emplace_back(branch); return 0; }可以看到逐分支minfreespace在这里生效可用空间低于阈值时该分支按ENOSPC被跳过。此外还有一个自动保护逻辑src/branches.cpp 的find_and_set_mode_ro()会检查 RW 分支对应的底层文件系统是否实际处于只读状态如介质变只读若是则把该分支模式自动改为RO并记录 warning 日志避免持续向只读介质发起写操作。2.2 解析实现与语法边界分支字符串的解析逻辑位于 src/branches.cppparse_mode、parse_minfreespace、parse_branch三个函数有几个值得注意的细节按最后一个切分parse_branch使用str::rsplit1(str_, )即从右侧第一个处分割。这意味着路径名本身可以包含字符如/tmp/withequalsRW会被正确解析为路径/tmp/withequals 模式RWtests/tests.cpp 中有对应测试test_branches_path_with_equals_in_name选项顺序固定之后先按逗号拆成至多两段第一段是 mode只接受RW/RO/NC否则返回EINVAL第二段是 minfreespace空选项非法/tmp/a等号后什么都没有返回EINVALtests/tests.cpp。Branch内部用std::variantu64, const u64*存储 minfreespace未单独指定时保存的是指向全局默认值的指针。从 src/branch.cpp 的minfreespace()实现看取全局指针时是实时读取当前全局值——也就是说后续通过运行时 API 修改全局minfreespace所有未单独设置的分支会同步生效tests/tests.cpp 的test_branches_global_minfreespace_live_tracking验证了该行为。branches选项在挂载点上的stat/目录列表显示时由 src/branch.cpp 的to_string()生成路径模式[,人类可读容量]形式如/mnt/hdd/disk0RW,4G冒号拼接各分支输出。3. 分支路径的解析resolution流程每个冒号分隔的分支记号在branches选项被解析时各自独立解析——既发生在启动时也发生在通过运行时 API 更新时。文档给出的五步流程是路径部分先按 glob 展开若 glob 匹配到一个或多个目录每个匹配项各自成为一个分支若 glob 无匹配mergerfs 记录一条 notice 日志并把配置中的原路径原样保留为单个字面分支对每个结果路径执行realpath解析成功则存储规范化路径失败典型原因是路径尚不存在则存储原样路径存在但不是目录的路径会被记录日志并跳过不存在的路径被记录日志但保留。对照源码可以逐条印证glob 展开在 src/fs_glob.cpp封装了 POSIXglob(3)标志为GLOB_BRACE|GLOB_ONLYDIR——即支持花括号展开如disk{1,2,3}且只匹配目录“无匹配则保留字面路径”在 src/branches.cppSysLog::notice(branch glob ... found no matches, adding the literal to branches)后把 glob 原文 push 进列表realpath规范化在 src/fs_realpathize.cpp对每个路径调用fs::realpath失败NULL则跳过替换即保留原样路径“存在但非目录则跳过、不存在则保留”在 src/branches.cppis_directory为假打 warning 并continueexists为假打 notice 但照常emplace_back。由此得到文档强调的两个实践结论可以先配置尚未存在的字面分支。例如/mnt/hdd/disk0/foobar可以在/mnt/hdd/disk0还没挂载时就写入配置等盘挂上后它自然可用但分支解析不会在后台重复执行。如果/mnt/hdd/disk0/*在解析时没有匹配到任何目录mergerfs 存下的是字面路径/mnt/hdd/disk0/*之后新出现的匹配目录不会被自动发现。要让 glob 重新展开需通过运行时 API 更新branches或重启 mergerfs。4. Glob 匹配简化多分支配置为便于一次性纳入多个分支mergerfs 支持 glob 通配。注意文档中的加粗警告经由 shell 使用时glob 记号必须转义否则 shell 会自己先做通配展开。# mergerfs /mnt/hdd/\*:/mnt/ssd/\* /media上面的命令行会使用/mnt/hdd与/mnt/ssd下的所有目录作为分支。若要开机自动挂载或让相关工具能读到配置写入/etc/fstab# file system mount point type options dump pass /mnt/hdd/*:/mnt/ssd/* /media mergerfs minfreespace16G 0 0注意glob 展开只发生在挂载时或经运行时 API 更新branches时。之后新出现的、符合 glob 的目录不会被自动纳入——这也是第 3 节“字面路径保留”规则的直接后果。另一种便捷的分支组织方式是用符号链接管理分支见 quickstart 文档 的 “/etc/fstab w/ config file” 一节在配置目录如/etc/mergerfs/branches/media/下为每个分支创建 symlink/etc/fstab里用branches目录的 glob 指向它们mergerfs 会解析符号链接并使用真实路径。好处是分支增减只需增删 symlinkfstab本身不必改动# /etc/fstab /etc/mergerfs/branches/media/* /media mergerfs config/etc/mergerfs/config/media.ini$ ls -lh /etc/mergerfs/branches/media/* lrwxrwxrwx 1 root root 14 Aug 4 2023 disk0 - /mnt/hdd/disk0 lrwxrwxrwx 1 root root 14 Aug 4 2023 disk1 - /mnt/hdd/disk1 lrwxrwxrwx 1 root root 14 Aug 4 2023 disk2 - /mnt/hdd/disk25. 运行时 API挂载后动态增删分支挂载完成后branches还可以通过挂载点上的 xattr 接口修改读取用getfattr -n user.mergerfs.branches mountpoint/.mergerfs修改用setfattr -n user.mergerfs.branches -v VALUE mountpoint/.mergerfs。运行时值除分支列表本身外还支持几个列表操作指令详见 runtime_interface 文档值说明[list]整体替换分支列表set[list]在现有列表头部插入[list]在现有列表尾部追加- [list]按 fnmatch 模式移除匹配的分支-移除列表第一个分支-移除列表最后一个分支示例$ getfattr -n user.mergerfs.branches .mergerfs user.mergerfs.branches/mnt/hdd/disk0RW:/mnt/hdd/disk1RW $ setfattr -n user.mergerfs.branches -v /mnt/hdd/disk2RO .mergerfs $ getfattr -n user.mergerfs.branches .mergerfs user.mergerfs.branches/mnt/hdd/disk2RO:/mnt/hdd/disk0RW:/mnt/hdd/disk1RW这些指令在 src/branches.cpp 的Branches::Impl::from_string中分发到add_begin、add_end/、erase_begin-、erase_end-、erase_fnmatch-用fnmatch按模式批量删除和set或无指令前缀等函数。更新采用“先在新副本上解析、成功后原子替换”的方式解析失败不会影响正在运行的分支列表。tests/tests.cpp 对这组操作符含多路径追加/前插、fnmatch 多模式删除、/-等非法前缀返回EINVAL有完整的单元测试覆盖。注意运行时更新的错误约定来自 runtime_interface 文档非法值返回EINVAL若把branches设为无效/不存在的值mergerfs 不会崩溃而是在挂载点stat时返回一个假条目、列目录时显示一个提示文件 “error: no valid mergerfs branch found, check config”以确保用户能发现问题且 xattr 接口仍可访问。6. 分支目录布局面向可运维的命名规范文档给出的布局建议对分支路径本身没有硬性要求但大规模场景下很有价值在/mnt/下为每类存储介质和/或互连方式建一个子目录——hdd传统硬盘、ssdSATA SSD、nvmeM.2/U.2 NVMe、remoteNFS、SMB、sshfs 等。挂载点以“容量-序列号”本地盘或“主机名-远端文件系统”远程命名$ ls -lh /mnt/ total 16K drwxr-xr-x 8 root root 4.0K Aug 18 2024 hdd drwxr-xr-x 6 root root 4.0K Oct 8 2024 nvme drwxr-xr-x 3 root root 4.0K Aug 24 2024 remote drwxr-xr-x 3 root root 4.0K Jul 14 2024 ssd $ ls -lh /mnt/hdd/ total 8K d--------- 2 root root 4.0K Apr 14 15:58 10T-01234567 d--------- 2 root root 4.0K Apr 12 20:51 20T-12345678 $ ls -lh /mnt/nvme/ total 8K d--------- 2 root root 4.0K Apr 14 16:00 1T-ABCDEFGH d--------- 2 root root 4.0K Apr 14 23:24 1T-BCDEFGHI $ ls -lh /mnt/remote/ total 8K d--------- 2 root root 4.0K Apr 12 20:23 foo-sshfs d--------- 2 root root 4.0K Apr 12 20:24 bar-nfs # You can find the serial number of a drive using lsblk $ lsblk -d -o NAME,PATH,SIZE,SERIAL NAME PATH SIZE SERIAL sda /dev/sda 9.1T 01234567 sdb /dev/sdb 18.2T 12345678 nvme0n1 /dev/nvme0n1 953.9G ABCDEFGH nvme1n1 /dev/nvme1n1 953.9G BCDEFGHIlsblk -d -o NAME,PATH,SIZE,SERIAL是获取磁盘序列号、用于命名挂载点与fstab标签的关键工具。7. 权限与模式锁定挂载点、规范化已挂载文件系统7.1 锁定挂载点目录为确保某目录仅作为挂载点使用最好在挂载文件系统到它之前把权限收紧到最严格$ sudo chown root:root /mnt/hdd/10T-XYZ $ sudo chmod 0000 /mnt/hdd/10T-XYZ $ sudo setfattr -n user.mergerfs.branch_mounts_here $ sudo chattr i /mnt/hdd/10T-XYZ其中扩展属性user.mergerfs.branch_mounts_here有专门用途branches-mount-timeout 选项用它在轮询分支是否“已挂载”时识别该分支路径指向的是预期的文件系统还是一个尚未被覆盖的挂载点目录。从源码看判定逻辑在 src/fs_wait_for_mount.cpp 的_branch_is_mounted()分支目录带 xattruser.mergerfs.branch→ 视为已挂载分支目录内存在.mergerfs.branch文件 → 视为已挂载分支目录带 xattruser.mergerfs.branch_mounts_here→ 明确视为未挂载分支目录内存在.mergerfs.branch_mounts_here文件 → 明确视为未挂载以上都不满足时比较 mergerfs 挂载点与分支路径的st_dev设备号不同才视为已挂载。这正是第 7.1/7.2 节两组setfattr命令的底层依据。chattr i大概率只在 EXT{2,3,4} 上有效但它能让目录及其内容对root也保持不可修改同时仍可作为挂载点。7.2 规范化已挂载文件系统对 Linux 新手、希望把 mergerfs 挂载点作为主要使用入口、或单纯想简化权限管理的用户文档建议把挂载的文件系统根目录设置得像/tmp/一样属主root权限ugorwx并加上 sticky bit效果等价chmod 1777。这一步必须在挂载之后执行$ sudo chown root:root /mnt/hdd/10T-SERIALNUM $ sudo chmod 1777 /mnt/hdd/10T-SERIALNUM $ sudo setfattr -n user.mergerfs.branch /mnt/hdd/10T-SERIALNUM这里的user.mergerfs.branchxattr 让 mergerfs 明确知道“这个目录本身就是分支已挂载的文件系统”与user.mergerfs.branch_mounts_here标记“挂载点盘还没挂上”配合构成 mergerfs 识别分支状态的完整标记体系。8. 分区与格式化建议整盘格式化文档还顺带回答了用户高频问题mergerfs 用户的典型用法是吃满整块盘容量因此建议单分区甚至无分区。很多人没意识到分区不仅不必要还可能带来麻烦——与其建分区不如直接格式化块设备。以/dev/sda为例$ lsblk -d -o NAME,PATH,SERIAL /dev/sda NAME PATH SERIAL sda /dev/sda 01234567 $ sudo mkfs.ext4 -m0 -L 01234567 /dev/sda mke2fs 1.47.0 (5-Feb-2023) Discarding device blocks: done Creating filesystem with 262144 4k blocks and 65536 inodes Filesystem UUID: ede8bf96-9aff-464e-a4fb-a4ab8a197cd7 Superblock backups stored on blocks: 32768, 98304, 163840, 229376 Allocating group tables: done Writing inode tables: done Creating journal (8192 blocks): done Writing superblocks and filesystem accounting information: done-m0关闭保留块-L写入以序列号命名的文件系统标签然后在fstab中用序列号作为标识# file system mount point type options dump pass LABEL01234567 /mnt/hdd/10TB-01234567 auto nofail 0 2这样做的收益少一个需要配置和操心的对象分区表块对齐得到保证磁盘在不同外壳/控制器间挪用时更容易——某些 SATA 转 USB 适配器按 4K 扇区寻址而盘本身是 512B若之前按另一种扇区大小建了分区换控制器后文件系统起始偏移会被错误解读手工修复可行但缺乏良好文档整盘格式化可直接规避。9. 小结一条 branches 配置的生命周期把上述内容串起来一条branches配置在 mergerfs 中的完整生命周期是字符串解析按:切分每项按最后一个分出路径与选项选项按,解析 mode 与 minfreespacesrc/branches.cpp路径展开glob含花括号、仅限目录展开无匹配则保留字面路径并记 noticesrc/fs_glob.cpp、src/branches.cpp规范化与校验realpath成功则替换为规范路径不存在则保留、存在但非目录则丢弃src/fs_realpathize.cpp、src/branches.cpp策略使用create 类策略跳过ro_or_nc()分支并按逐分支 minfreespace 过滤src/policy_ff.cpp底层变只读时自动降级为 ROsrc/branches.cpp运行中调整通过.mergerfsxattr 上的user.mergerfs.branches支持整体替换与增删操作符解析成功才原子替换src/branches.cpp。配套的仓库参考路径便于继续深入分支核心实现src/branch.hpp、src/branch.cpp、src/branches.cpp、src/branches.hppglob 与路径解析src/fs_glob.cpp、src/fs_realpathize.cpp挂载等待判定src/fs_wait_for_mount.cpp单元测试tests/tests.cpp相关文档branches-mount-timeout、minfreespace、运行时接口、quickstart赞分享存储【免费下载链接】mergerfsa featureful union filesystem项目地址https://gitcode.com/gh_mirrors/me/mergerfs点击查看免费下载相关推荐mergerfs branches-mount-timeout 选项详解让 Union Filesystem 正确等待异步挂载的分支mergerfs branches mount timeout 选项详解让 Union Filesystem 正确等待异步挂载的分支 在 systemd 时代存储Wand-Enhancer 快速指南三分钟解除两小时限制顺带装好手机远程面板Wand Enhancer 快速指南三分钟解除两小时限制顺带装好手机远程面板 做完之后你手里有一个不再有 2 小时免费时间用完倒计时的 Wand原桌面应用前端Gulp 5 Glob 匹配完全指南从 *、** 到 ! 的路径模式语法与工程实践Gulp 5 Glob 匹配完全指南从 、 到 ! 的路径模式语法与工程实践 本文是 gulp 官方 Getting Started 系列中 Explaini构建工具CLI上一篇Consolonia字体系统揭秘ASCII艺术字体如何实现终端中的视觉盛宴下一篇提升BTCRecover恢复效率GPU加速与OpenCL配置终极指南 创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考