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;

}

Logo

更多推荐