xattr 是文件扩展属性全称是一种以key-value 保存数据到文件系统中的技术、xattr从功能上分为四类user/trusted/system/security. 这四类中system用于保存acl,security 用于支持selinux,user/trusted 提供给用户保存进程的设置。
从include/uapi/linux/limits.h 中可以知道
#define XATTR_NAME_MAX 255/* # chars in an extended attribute name */
#define XATTR_SIZE_MAX 65536/* size of an extended attribute value (64k) */
#define XATTR_LIST_MAX 65536/* size of extended attribute namelist (64k) */
在保存xattr时候 key的长度不能超过255 ,value 不能超过64k。总的配对数不能超过64k
在os中没有文件系统都对应一组setxattr和getxattr命令用于读写xattr
例如ext4 为例
extern ssize_t ext4_listxattr(struct dentry *, char *, size_t);
extern int ext4_xattr_get(struct inode *, int, const char *, void *, size_t);
extern int ext4_xattr_set(struct inode *, int, const char *, const void *, size_t, int);
同时fs提供setxattr和getxattr 等系统调用来查新和更新xattr
我们以setxttr这个系统调用为例
SYSCALL_DEFINE5(setxattr, const char __user *, pathname,
const char __user *, name, const void __user *, value,
size_t, size, int, flags)
{
#调用这个函数来设置xattr
return path_setxattr(pathname, name, value, size, flags, LOOKUP_FOLLOW);
}
static int path_setxattr(const char __user *pathname,
const char __user *name, const void __user *value,
size_t size, int flags, unsigned int lookup_flags)
{
struct path path;
int error;
retry:
error = user_path_at(AT_FDCWD, pathname, lookup_flags, &path);
if (error)
return error;
#检查这个mount point是否可以写,因为这里是set xattr如果不能写,则直接退出
error = mnt_want_write(path.mnt);
if (!error) {
#可以写的话,则调用setxattr 来设置扩展属性
error = setxattr(path.dentry, name, value, size, flags);
mnt_drop_write(path.mnt);
}
path_put(&path);
if (retry_estale(error, lookup_flags)) {
lookup_flags |= LOOKUP_REVAL;
goto retry;
}
return error;
}
static long
setxattr(struct dentry *d, const char __user *name, const void __user *value,
size_t size, int flags)
{
int error;
void *kvalue = NULL;
char kname[XATTR_NAME_MAX + 1];
#如果包含create和replace这两个属性,则退出
if (flags & ~(XATTR_CREATE|XATTR_REPLACE))
return -EINVAL;
#从user pace copy 要写的数据
error = strncpy_from_user(kname, name, sizeof(kname));
if (error == 0 || error == sizeof(kname))
error = -ERANGE;
if (error < 0)
return error;
if (size) {
#检查value的值不能超过46K
if (size > XATTR_SIZE_MAX)
return -E2BIG;
kvalue = kvmalloc(size, GFP_KERNEL);
if (!kvalue)
return -ENOMEM;
#从user space copy要写的value
if (copy_from_user(kvalue, value, size)) {
error = -EFAULT;
goto out;
}
#设置system ,主要用于acl
if ((strcmp(kname, XATTR_NAME_POSIX_ACL_ACCESS) == 0) ||
(strcmp(kname, XATTR_NAME_POSIX_ACL_DEFAULT) == 0))
posix_acl_fix_xattr_from_user(kvalue, size);
#检查name是否有权限
else if (strcmp(kname, XATTR_NAME_CAPS) == 0) {
error = cap_convert_nscap(d, &kvalue, size);
if (error < 0)
goto out;
size = error;
}
}
#开始通过vfs调用各个文件系统实现的setxattr,以ext4 为例的话,就是最终会调用ext4_xattr_set
error = vfs_setxattr(d, kname, kvalue, size, flags);
out:
kvfree(kvalue);
return error;
}