今天我们来看ext2的扩展属性的主要文件xattr.c,内部有扩展属性的最重要的代码实现,但是文件也真的很长,我们来开始吧。
/* 作者版权信息
* linux/fs/ext2/xattr.c
*
* Copyright (C) 2001-2003 Andreas Gruenbacher <agruen@suse.de>
* 被Harrison Xing修改过
* Fix by Harrison Xing <harrison@mountainviewdata.com>.
* Extended attributes for symlinks and special files added per
* suggestion of Luka Renko <luka.renko@hermes.si>.
* xattr consolidation Copyright (c) 2004 James Morris <jmorris@redhat.com>,
* Red Hat Inc.
*
*/
#include <linux/buffer_head.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/mbcache.h>
#include <linux/quotaops.h>
#include <linux/rwsem.h>
#include "ext2.h"
#include "xattr.h"
#include "acl.h"
/*宏定义,参数是buffer_head就诶勾踢指针,得到ext2_xattr_header类型的指针,指向buffer的头部*/
#define HDR(bh) ((struct ext2_xattr_header *)((bh)->b_data))
/*将指针转化为ext2_xattr_entry类型的*/
#define ENTRY(ptr) ((struct ext2_xattr_entry *)(ptr))
/*获得buffer的第一个项指针*/
#define FIRST_ENTRY(bh) ENTRY(HDR(bh)+1)
/*判断当前的项是不是最后一个*/
#define IS_LAST_ENTRY(entry) (*(__u32 *)(entry) == 0)
/*调试信息*/
#ifdef EXT2_XATTR_DEBUG
# define ea_idebug(inode, f...) do { \
printk(KERN_DEBUG "inode %s:%ld: ", \
inode->i_sb->s_id, inode->i_ino); \
printk(f); \
printk("\n"); \
} while (0)
# define ea_bdebug(bh, f...) do { \
char b[BDEVNAME_SIZE]; \
printk(KERN_DEBUG "block %s:%lu: ", \
bdevname(bh->b_bdev, b), \
(unsigned long) bh->b_blocknr); \
printk(f); \
printk("\n"); \
} while (0)
#else
# define ea_idebug(f...)
# define ea_bdebug(f...)
#endif
/*一些用到的函数声明*/
static int ext2_xattr_set2(struct inode *, struct buffer_head *,
struct ext2_xattr_header *);
static int ext2_xattr_cache_insert(struct buffer_head *);
static struct buffer_head *ext2_xattr_cache_find(struct inode *,
struct ext2_xattr_header *);
static void ext2_xattr_rehash(struct ext2_xattr_header *,
struct ext2_xattr_entry *);
/*系统存储的属性缓存*/
static struct mb_cache *ext2_xattr_cache;
/*属性的名称和处理函数的映射*/
static struct xattr_handler *ext2_xattr_handler_map[] = {
[EXT2_XATTR_INDEX_USER] = &ext2_xattr_user_handler,
#ifdef CONFIG_EXT2_FS_POSIX_ACL
[EXT2_XATTR_INDEX_POSIX_ACL_ACCESS] = &ext2_xattr_acl_access_handler,
[EXT2_XATTR_INDEX_POSIX_ACL_DEFAULT] = &ext2_xattr_acl_default_handler,
#endif
[EXT2_XATTR_INDEX_TRUSTED] = &ext2_xattr_trusted_handler,
#ifdef CONFIG_EXT2_FS_SECURITY
[EXT2_XATTR_INDEX_SECURITY] = &ext2_xattr_security_handler,
#endif
};
/*扩展属性的集合*/
struct xattr_handler *ext2_xattr_handlers[] = {
&ext2_xattr_user_handler,
&ext2_xattr_trusted_handler,
#ifdef CONFIG_EXT2_FS_POSIX_ACL
&ext2_xattr_acl_access_handler,
&ext2_xattr_acl_default_handler,
#endif
#ifdef CONFIG_EXT2_FS_SECURITY
&ext2_xattr_security_handler,
#endif
NULL
};
/*由扩展属性在数组里的下表,获得对应的处理函数结构体,参数name_index就是下表*/
static inline struct xattr_handler *
ext2_xattr_handler(int name_index)
{
struct xattr_handler *handler = NULL;
/*如果参数合法,返回对应的结构体*/
if (name_index > 0 && name_index < ARRAY_SIZE(ext2_xattr_handler_map))
/*上边刚说过的结构体*/
handler = ext2_xattr_handler_map[name_index];
return handler;
}
/*ext2_xattr_get()函数,复制一个扩展属性结构体到一个给定的buffer里,或者是计算需要的buffer大小,参数buffer如果是NULL的话,就计算需要的buffer大小,当失败的时候返回负的错误编号,成功时候返回消耗的字节数目*/
int
ext2_xattr_get(struct inode *inode, int name_index, const char *name,
void *buffer, size_t buffer_size)
{
struct buffer_head *bh = NULL;
struct ext2_xattr_entry *entry;
size_t name_len, size;
char *end;
int error;
/*调试信息,不管了*/
ea_idebug(inode, "name=%d.%s, buffer=%p, buffer_size=%ld",
name_index, name, buffer, (long)buffer_size);
/*如果要求的属性名称为NULL,说明传入参数有问题*/
if (name == NULL)
return -EINVAL;
/*读i_file_acl之前必须上锁*/
down_read(&EXT2_I(inode)->xattr_sem);
error = -ENODATA;
/*i_file_acl指向属性的文件块号,如果为空,直接返回*/
if (!EXT2_I(inode)->i_file_acl)
goto cleanup;
ea_idebug(inode, "reading block %d", EXT2_I(inode)->i_file_acl);
/*读取这个块进入内存*/
bh = sb_bread(inode->i_sb, EXT2_I(inode)->i_file_acl);
error = -EIO;
if (!bh)
goto cleanup;
ea_bdebug(bh, "b_count=%d, refcount=%d",
atomic_read(&(bh->b_count)), le32_to_cpu(HDR(bh)->h_refcount));
/*end指向buffer的末尾*/
end = bh->b_data + bh->b_size;
/*检查读取的缓冲区,看看这个块是不是坏块*/
if (HDR(bh)->h_magic != cpu_to_le32(EXT2_XATTR_MAGIC) ||
HDR(bh)->h_blocks != cpu_to_le32(1)) {
/*如果是坏块,报错并返回IO错误*/
bad_block: ext2_error(inode->i_sb, "ext2_xattr_get",
"inode %ld: bad block %d", inode->i_ino,
EXT2_I(inode)->i_file_acl);
error = -EIO;
goto cleanup;
}
/* 根据属性的名字寻找这个属性 */
/*先获得属性名字长度*/
name_len = strlen(name);
error = -ERANGE;
/*最大名字长度是255*/
if (name_len > 255)
goto cleanup;
/*获得属性的第一项*/
entry = FIRST_ENTRY(bh);
/*遍历属性的每一项*/
while (!IS_LAST_ENTRY(entry)) {
struct ext2_xattr_entry *next =
EXT2_XATTR_NEXT(entry);
/*检验当前项是不是合法*/
if ((char *)next >= end)
goto bad_block;
/*匹配,是不是我们想要的*/
if (name_index == entry->e_name_index &&
name_len == entry->e_name_len &&
memcmp(name, entry->e_name, name_len) == 0)
goto found;
entry = next;
}
/* 检查余下的项,看看有没有坏的 */
while (!IS_LAST_ENTRY(entry)) {
struct ext2_xattr_entry *next =
EXT2_XATTR_NEXT(entry);
if ((char *)next >= end)
goto bad_block;
entry = next;
}
/*创建一个新的扩展属性项,并且插入它*/
if (ext2_xattr_cache_insert(bh))
ea_idebug(