linux 中文件系统的扩展属性

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;
}

你可能感兴趣的:(Linux,源码分析)