RK3588 kernel-6.1 fs/ext4/acl.c POSIX ACL 支持分析
1. 分析范围
rk3588/kernel-6.1/fs/ext4/acl.crk3588/kernel-6.1/fs/ext4/acl.h- 与
xattr.c中扩展属性接口、VFSposix_acl通用层的衔接
编译依赖:CONFIG_EXT4_FS_POSIX_ACL(在 fs/ext4/Makefile 中把 acl.o 链入 ext4 模块)。
2. 代码作用(一句话)
acl.c 在 ext4 里把 POSIX ACL 落到磁盘:以“固定二进制布局”存放在扩展属性(xattr)中,并在读/写时与内核内存结构 struct posix_acl 互转;设置 ACL 时走 JBD2 事务 + ext4_xattr_set,新建文件时从父目录继承 default ACL。
3. 解决了什么问题
3.1 UNIX 经典权限的局限
传统 rwx 只对 owner / group / other 三组生效。需要下面能力时不够用:
- 给 多个用户 或 多个组 单独授权;
- 目录上设 默认 ACL,使新建文件/子目录 自动继承 权限语义;
- 与
mask一起限制 ACL 条目的有效权限(POSIX.1e 模型)。
POSIX ACL 在 Linux 上通过 setfacl/getfacl 等接口暴露;文件系统必须能 持久化 ACL 并在 permission 检查时参与决策。ext4 选择把它存在 xattr 里(与 ext3 时期思路一致),acl.c 负责 格式转换与 I/O 路径,实际权限检查由 VFS 通用 posix_acl_* + inode i_acl / i_default_acl 缓存完成。
3.2 ext4 侧具体承担的工作
| 问题 | acl.c 的做法 |
|---|---|
| 盘上长什么样 | ext4_acl_header + ext4_acl_entry / ext4_acl_entry_short,版本号 EXT4_ACL_VERSION |
| 与用户态/通用 ACL 如何对应 | ext4_acl_from_disk / ext4_acl_to_disk |
| 从哪里读写 | 通过 ext4_xattr_get / ext4_xattr_set_handle,索引 EXT4_XATTR_INDEX_POSIX_ACL_ACCESS 与 ..._DEFAULT |
| 一致性 | ext4_set_acl 内 ext4_journal_start/stop,与元数据日志一致 |
access ACL 与 mode 位一致性 |
posix_acl_update_mode:访问 ACL 可能要求同步更新 i_mode 中 owner 类权限 |
| 新 inode | ext4_init_acl:从父目录 posix_acl_create 得到 default + access,再写入子 inode |
4. 磁盘格式(acl.h)
ext4_acl_header:仅a_version(当前0x0001),小端。ext4_acl_entry:e_tag、e_perm、可选e_id(用于ACL_USER/ACL_GROUP条目)。ext4_acl_entry_short:无e_id,用于ACL_USER_OBJ、ACL_GROUP_OBJ、ACL_MASK、ACL_OTHER。
条目数量与总长用 ext4_acl_count() / ext4_acl_size() 推算(前 4 条按 short 布局,多出的为带 id 的 full entry),与 acl.c 中遍历逻辑一致,防止畸形 xattr 越界解析。
5. 核心函数说明
5.1 ext4_acl_from_disk / ext4_acl_to_disk
- 从盘读出:校验长度、
a_version、ext4_acl_count,逐条解析e_tag/e_perm,对ACL_USER/ACL_GROUP用make_kuid/make_kgid(init_user_ns)填入内存 ACL。 - 写回盘:分配连续 buffer,
e_tag/e_perm/e_id转小端;from_kuid/from_kgid写 id(同样在 init_user_ns 下序列化,与磁盘历史格式一致)。
解析结束指针必须 严格等于 end,否则 EINVAL,避免尾部垃圾或截断。
5.2 ext4_get_acl
VFS get_posix_acl 的 ext4 实现入口(由 ext4.h 里 inode 操作表挂接)。
- 类型:
ACL_TYPE_ACCESS→ access xattr;ACL_TYPE_DEFAULT→ default xattr(仅目录语义在设置层限制)。 rcu == true:直接返回ERR_PTR(-ECHILD),不支持在 RCU 下读 ACL(需一致快照则走非 RCU 路径)。- 通过
ext4_xattr_get取 blob,再ext4_acl_from_disk;-ENODATA/-ENOSYS视为 无 ACL(NULL)。
5.3 __ext4_set_acl
内部函数:在已有 handle_t 下 ext4_xattr_set_handle 写入或删除 xattr;成功后 set_cached_acl 更新 inode 上 ACL 缓存。
- default ACL:若 inode 不是目录 且要设置非空 default ACL,返回
-EACCES(符合 POSIX:default ACL 只属于目录)。 acl == NULL:删除对应 xattr(size == 0)。
5.4 ext4_set_acl
对外设置入口:配额初始化 → 计算 xattr 所需 journal credits → ext4_journal_start。
- 对
ACL_TYPE_ACCESS且acl非空:调用posix_acl_update_mode,必要时更新inode->i_mode与i_ctime,并ext4_mark_inode_dirty。 -ENOSPC时按 ext4 惯例ext4_should_retry_alloc重试。
5.5 ext4_init_acl
在 ext4_new_inode 路径调用(父目录 dir 已持锁;新 inode 仍独占)。
posix_acl_create(dir, &inode->i_mode, &default_acl, &acl):由通用层根据父目录 default ACL 和 umask 算出子节点的 default + access。- 分别
__ext4_set_acl(..., XATTR_CREATE)写入;释放临时 ACL 引用;错误时仍要 release,避免泄漏。
6. 配置关闭时(acl.h)
若未定义 CONFIG_EXT4_FS_POSIX_ACL:
ext4_get_acl/ext4_set_acl被定义为NULL(不需 POSIX ACL 钩子)。ext4_init_acl内联为仅inode->i_mode &= ~current_umask(),并注释说明:否则不会因未调用posix_acl_create而漏掉 umask。
7. 与其它模块的关系
1 | VFS / generic_acl / permission() |
8. RK3588 / 嵌入式注意点
- 开启
CONFIG_EXT4_FS_POSIX_ACL会增加代码体积与少量元数据路径开销;Android/服务器镜像若使用 ACL,需要打开;纯嵌入式只读 rootfs 可酌情关闭。 - ACL 存 xattr:小文件 + 多 ACL 可能增加元数据与
fsck负担;权限模型简单时继续用传统chmod即可。 - user namespace 与挂载 idmap 场景下,盘上 uid/gid 与
init_user_ns序列化方式需与上层策略一致;本文件 ACL 序列化固定走init_user_ns,与多数 xattr ACL 实现一致。
9. 小结
| 维度 | 结论 |
|---|---|
| 作用 | ext4 的 POSIX ACL:盘上 xattr 比特流 ↔ struct posix_acl,带日志的 set,新建 inode 继承 |
| 解决问题 | 在 ext4 上实现超出 user/group/other 的细粒度权限与目录默认 ACL,并与 VFS ACL 框架对接 |
| 关键依赖 | xattr、JBD2、posix_acl_* 通用层、CONFIG_EXT4_FS_POSIX_ACL |
文档对应路径:rk3588/kernel-6.1/fs/ext4/acl.c。保存位置:linuxDoc/fs/ext4/。
正在加载留言…