关于chacl的分析
最近在nfs上面遇到chacl问题,这里记录下分析过程。
ls命令
ls命令根据系统调用getxattr的返回值判断是否要打印”+”
https://github.com/coreutils/coreutils/blob/master/src/ls.c
1 |
|
int file_has_acl (char const *name, struct stat const *sb)
{
#if USE_ACL
if (! S_ISLNK (sb->st_mode))
{
if GETXATTR_WITH_POSIX_ACLS
ssize_t ret;
ret = getxattr (name, XATTR_NAME_POSIX_ACL_ACCESS, NULL, 0); //是否有acl数据
if (ret < 0 && errno == ENODATA)
ret = 0;
else if (ret > 0)
return 1;
if (ret == 0 && S_ISDIR (sb->st_mode))
{
ret = getxattr (name, XATTR_NAME_POSIX_ACL_DEFAULT, NULL, 0);
if (ret < 0 && errno == ENODATA)
ret = 0;
else if (ret > 0)
return 1;
}
if (ret < 0)
return - acl_errno_valid (errno);
return ret;
...1 |
|
getxattr
- vfs_getxattr
- nfs3_getxattr
1 |
|
acl = nfs3_proc_getacl(inode, type);
if (IS_ERR(acl))
return PTR_ERR(acl);
else if (acl) {
if (type == ACL_TYPE_ACCESS && acl->a_count == 0)
error = -ENODATA;
else
error = posix_acl_to_xattr(&init_user_ns, acl, buffer, size);
posix_acl_release(acl);
} else
error = -ENODATA;//如果nfs3_proc_getacl返回null则返回ENODATA
nfs3_proc_getacl@fs/nfs/nfs3acl.c
if (res.acl_access != NULL) {
if (posix_acl_equiv_mode(res.acl_access, NULL) == 0) {//对于标准权限则置空acl
posix_acl_release(res.acl_access);
res.acl_access = NULL;
}
}
1 |
|
getxattr
- vfs_getxattr
- posix_acl_xattr_get
1 | posix_acl_xattr_get@fs/posix_acl.c |
acl = get_acl(inode, handler->flags);
if (IS_ERR(acl))
return PTR_ERR(acl);
if (acl == NULL)
return -ENODATA;
1 | get_acl@fs/posix_acl.c |
acl = get_cached_acl(inode, type);
if (!is_uncached_acl(acl))
return acl;
1 |
|
if (res.acl_access != NULL) {
if ((posix_acl_equiv_mode(res.acl_access, NULL) == 0) ||
res.acl_access->a_count == 0) {
posix_acl_release(res.acl_access);
res.acl_access = NULL;
}
}
```
在chacl之后如果inode->i_acl有效,getxattr返回acl数据。
结论
出现问题的根本原因是4.18内核使用generic acl功能框架,缓存了错误的acl,导致出问题。
最新的内核有patch修正该问题。
即在setacl的时候总是置inode->i_acl无效。