ext2文件系统源代码之xattr.c

来源:互联网 发布:数据库市场占有率 2016 编辑:程序博客网 时间:2024/06/02 01:04
今天我们来看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,#endifNULL};/*由扩展属性在数组里的下表,获得对应的处理函数结构体,参数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大小,当失败的时候返回负的错误编号,成功时候返回消耗的字节数目*/intext2_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(inode, "cache insert failed");error = -ENODATA;goto cleanup;found:/* 检查保存value的块号,否则说明这个块是坏的 */if (entry->e_value_block != 0)goto bad_block;size = le32_to_cpu(entry->e_value_size);/*检查块的大小是否合法*/if (size > inode->i_sb->s_blocksize ||    le16_to_cpu(entry->e_value_offs) + size > inode->i_sb->s_blocksize)goto bad_block;/*创建一个新的扩展属性项,并且插入到缓冲区*/if (ext2_xattr_cache_insert(bh))ea_idebug(inode, "cache insert failed");if (buffer) {error = -ERANGE;if (size > buffer_size)goto cleanup;/* 返回属性 */memcpy(buffer, bh->b_data + le16_to_cpu(entry->e_value_offs),size);}error = size;cleanup:/*释放资源的引用*/brelse(bh);up_read(&EXT2_I(inode)->xattr_sem);return error;}/*ext2_xattr_list()函数,复制一系列的属性到buffer里,当buffer是NULL的时候就只计算需要的字节数,成功返回需要的字节数,失败返回错误码 */static intext2_xattr_list(struct inode *inode, char *buffer, size_t buffer_size){struct buffer_head *bh = NULL;struct ext2_xattr_entry *entry;char *end;size_t rest = buffer_size;int error;ea_idebug(inode, "buffer=%p, buffer_size=%ld",  buffer, (long)buffer_size);/*在读取i_file_acl之前必须上xattr_sem锁*/down_read(&EXT2_I(inode)->xattr_sem);error = 0;/*检查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指向缓冲区的末尾*/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_list","inode %ld: bad block %d", inode->i_ino,EXT2_I(inode)->i_file_acl);error = -EIO;goto cleanup;}/* 检查得到的buffer里的数据结构是不是对的 *//*第一个项*/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;entry = next;}/*创建一个新的项并插入*/if (ext2_xattr_cache_insert(bh))ea_idebug(inode, "cache insert failed");/* 列出所有的属性名称 */for (entry = FIRST_ENTRY(bh); !IS_LAST_ENTRY(entry);     entry = EXT2_XATTR_NEXT(entry)) {     /*得到属性处理结构体*/struct xattr_handler *handler =ext2_xattr_handler(entry->e_name_index);if (handler) {/*调用这个结构体的函数list来列出所有的属性*/size_t size = handler->list(inode, buffer, rest,    entry->e_name,    entry->e_name_len);/*检查函数是否成功*/if (buffer) {if (size > rest) {error = -ERANGE;goto cleanup;}buffer += size;}rest -= size;}}/*返回所占用的全部空间大小*/error = buffer_size - rest;  /* total size */cleanup:/*释放占用的全部空间*/brelse(bh);up_read(&EXT2_I(inode)->xattr_sem);return error;}/* 这个函数是从inode调用的listxattr()函数 */ssize_text2_listxattr(struct dentry *dentry, char *buffer, size_t size){/*直接调用前边的函数*/return ext2_xattr_list(dentry->d_inode, buffer, size);}/* 如果EXT2_FEATURE_COMPAT_EXT_ATTR位没有设置,就设置了 */static void ext2_xattr_update_super_block(struct super_block *sb){if (EXT2_HAS_COMPAT_FEATURE(sb, EXT2_FEATURE_COMPAT_EXT_ATTR))return;EXT2_SET_COMPAT_FEATURE(sb, EXT2_FEATURE_COMPAT_EXT_ATTR);sb->s_dirt = 1;mark_buffer_dirty(EXT2_SB(sb)->s_sbh);}/*ext2_xattr_set()函数可以创建,替换,删除一个inode的扩展属性buffer是NULL就删除,不为NUll就是替换或者是创建一个属性,flags参数的值XATTR_REPLACE和XATTR_CREATE标记处扩展属性必须存在和必须不能存在,失败的时候返回负的错误号 */intext2_xattr_set(struct inode *inode, int name_index, const char *name,       const void *value, size_t value_len, int flags){struct super_block *sb = inode->i_sb;struct buffer_head *bh = NULL;struct ext2_xattr_header *header = NULL;struct ext2_xattr_entry *here, *last;size_t name_len, free, min_offs = sb->s_blocksize;int not_found = 1, error;char *end;ea_idebug(inode, "name=%d.%s, value=%p, value_len=%ld",  name_index, name, value, (long)value_len);/*参数检查*/if (value == NULL)value_len = 0;if (name == NULL)return -EINVAL;/*名字长度检查*/name_len = strlen(name);if (name_len > 255 || value_len > sb->s_blocksize)return -ERANGE;/*在对文件的i_file_acl字段读写之前,必须上锁*/down_write(&EXT2_I(inode)->xattr_sem);/*如果i_file_acl字段不为0*/if (EXT2_I(inode)->i_file_acl) {/* inode已经有一个扩展属性块了,读取这个块的内容 */bh = sb_bread(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));/*header指向头部*/header = HDR(bh);/*end指向尾部*/end = bh->b_data + bh->b_size;/*检查头部的数据,看这个缓冲区是不是对的*/if (header->h_magic != cpu_to_le32(EXT2_XATTR_MAGIC) ||    header->h_blocks != cpu_to_le32(1)) {bad_block:ext2_error(sb, "ext2_xattr_set","inode %ld: bad block %d", inode->i_ino,    EXT2_I(inode)->i_file_acl);error = -EIO;goto cleanup;}/* 寻找我们想要的属性 *//* 先把here指向第一个项 */here = FIRST_ENTRY(bh);/*遍历所有的项*/while (!IS_LAST_ENTRY(here)) {/*next指向下一个*/struct ext2_xattr_entry *next = EXT2_XATTR_NEXT(here);/*检查这个块是不是坏块,好的应该是正好不会超出缓冲区的*/if ((char *)next >= end)goto bad_block;/*得到属性值在文件里的偏移量*/if (!here->e_value_block && here->e_value_size) {size_t offs = le16_to_cpu(here->e_value_offs);/*min_offs指向最小的偏移量*/if (offs < min_offs)min_offs = offs;}/*判定有没有找到我们想要的项,首先要name_index一致,另外名称长度和名字也要一致*/not_found = name_index - here->e_name_index;if (!not_found)not_found = name_len - here->e_name_len;if (!not_found)not_found = memcmp(name, here->e_name,name_len);if (not_found <= 0)break;/*指向下一个项*/here = next;}last = here;/* 计算还没有遍历的,是不是有不合法的数据,还要计算min_offs */while (!IS_LAST_ENTRY(last)) {struct ext2_xattr_entry *next = EXT2_XATTR_NEXT(last);if ((char *)next >= end)goto bad_block;if (!last->e_value_block && last->e_value_size) {size_t offs = le16_to_cpu(last->e_value_offs);if (offs < min_offs)min_offs = offs;}last = next;}/* 看看是不是有多余的空间了. */free = min_offs - ((char*)last - (char*)header) - sizeof(__u32);} else {/* 这个块是坏的,我们需要一个新的块 */free = sb->s_blocksize -sizeof(struct ext2_xattr_header) - sizeof(__u32);here = last = NULL;  }if (not_found) {/* 请求删除的项没找到,返回错误 */error = -ENODATA;if (flags & XATTR_REPLACE)goto cleanup;error = 0;if (value == NULL)goto cleanup;} else {/* 创建一个已经存在的项吗 */error = -EEXIST;if (flags & XATTR_CREATE)goto cleanup;if (!here->e_value_block && here->e_value_size) {size_t size = le32_to_cpu(here->e_value_size);if (le16_to_cpu(here->e_value_offs) + size >     sb->s_blocksize || size > sb->s_blocksize)goto bad_block;free += EXT2_XATTR_SIZE(size);}free += EXT2_XATTR_LEN(name_len);}error = -ENOSPC;/*空间不够创建*/if (free < EXT2_XATTR_LEN(name_len) + EXT2_XATTR_SIZE(value_len))goto cleanup;/* 设置新属性. */if (header) {struct mb_cache_entry *ce;/*从ext2_xattr_cache获得一个缓冲区*/ce = mb_cache_entry_get(ext2_xattr_cache, bh->b_bdev,bh->b_blocknr);/*访问前上锁*/lock_buffer(bh);if (header->h_refcount == cpu_to_le32(1)) {ea_bdebug(bh, "modifying in-place");if (ce)mb_cache_entry_free(ce);} else {int offset;if (ce)mb_cache_entry_release(ce);unlock_buffer(bh);ea_bdebug(bh, "cloning");header = kmalloc(bh->b_size, GFP_KERNEL);error = -ENOMEM;if (header == NULL)goto cleanup;/*把原来缓冲区的内容放到新分配的header里*/memcpy(header, HDR(bh), bh->b_size);header->h_refcount = cpu_to_le32(1);/*offset是偏移,here指向项,last指向最后一个entry*/offset = (char *)here - bh->b_data;here = ENTRY((char *)header + offset);offset = (char *)last - bh->b_data;last = ENTRY((char *)header + offset);}} else {/* 创建缓冲区,建立新的block结构体 */header = kzalloc(sb->s_blocksize, GFP_KERNEL);error = -ENOMEM;if (header == NULL)goto cleanup;end = (char *)header + sb->s_blocksize;header->h_magic = cpu_to_le32(EXT2_XATTR_MAGIC);header->h_blocks = header->h_refcount = cpu_to_le32(1);last = here = ENTRY(header+1);}/* 修改属性. */if (not_found) {/* 插入新的属性名称 *//* 得到对应名称的项的字节大小size,rest是余下的大小 */size_t size = EXT2_XATTR_LEN(name_len);size_t rest = (char *)last - (char *)here;/*为新的属性腾出位置*/memmove((char *)here + size, here, rest);/*新的地方先初始化为0*/memset(here, 0, size);/*赋值*/here->e_name_index = name_index;here->e_name_len = name_len;memcpy(here->e_name, name, name_len);} else {/* 如果属性的值就存在本块内 */if (!here->e_value_block && here->e_value_size) {/*指向第一个值*/char *first_val = (char *)header + min_offs;size_t offs = le16_to_cpu(here->e_value_offs);char *val = (char *)header + offs;size_t size = EXT2_XATTR_SIZE(le32_to_cpu(here->e_value_size));/*如果新旧属性值长度一样*/if (size == EXT2_XATTR_SIZE(value_len)) {/* 直接替换*/here->e_value_size = cpu_to_le32(value_len);memset(val + size - EXT2_XATTR_PAD, 0,       EXT2_XATTR_PAD); /* Clear pad bytes. */memcpy(val, value, value_len);goto skip_replace;}/* 新旧属性长度不一样,移除旧的 */memmove(first_val + size, first_val, val - first_val);memset(first_val, 0, size);here->e_value_offs = 0;min_offs += size;/* 还要调整所有的偏移 */last = ENTRY(header+1);while (!IS_LAST_ENTRY(last)) {size_t o = le16_to_cpu(last->e_value_offs);if (!last->e_value_block && o < offs)last->e_value_offs =cpu_to_le16(o + size);last = EXT2_XATTR_NEXT(last);}}if (value == NULL) {/* 移除原有的属性名 */size_t size = EXT2_XATTR_LEN(name_len);last = ENTRY((char *)last - size);memmove(here, (char*)here + size,(char*)last - (char*)here);memset(last, 0, size);}}if (value != NULL) {/* 插入新的值 */here->e_value_size = cpu_to_le32(value_len);/*值不是空值的话*/if (value_len) {/*修改*/size_t size = EXT2_XATTR_SIZE(value_len);char *val = (char *)header + min_offs - size;here->e_value_offs =cpu_to_le16((char *)val - (char *)header);memset(val + size - EXT2_XATTR_PAD, 0,       EXT2_XATTR_PAD); /* Clear the pad bytes. */memcpy(val, value, value_len);}}skip_replace:if (IS_LAST_ENTRY(ENTRY(header+1))) {/* 这个块不是空的. */if (bh && header == HDR(bh))unlock_buffer(bh);  /* we were modifying in-place. */error = ext2_xattr_set2(inode, bh, NULL);} else {ext2_xattr_rehash(header, here);if (bh && header == HDR(bh))unlock_buffer(bh);  /* we were modifying in-place. */error = ext2_xattr_set2(inode, bh, header);}cleanup:/*释放对buffer_head的引用*/brelse(bh);if (!(bh && header == HDR(bh)))kfree(header);/*释放锁*/up_write(&EXT2_I(inode)->xattr_sem);return error;}/*ext2_xattr_set()函数的下一半,更新文件系统*/static intext2_xattr_set2(struct inode *inode, struct buffer_head *old_bh,struct ext2_xattr_header *header){struct super_block *sb = inode->i_sb;struct buffer_head *new_bh = NULL;int error;if (header) {/*在缓存里寻找header的项*/new_bh = ext2_xattr_cache_find(inode, header);/*如果找到了*/if (new_bh) {/*同一个*/if (new_bh == old_bh) {ea_bdebug(new_bh, "keeping this block");} else {/* The old block is released after updating   the inode.  */ea_bdebug(new_bh, "reusing block");error = -EDQUOT;if (DQUOT_ALLOC_BLOCK(inode, 1)) {unlock_buffer(new_bh);goto cleanup;}HDR(new_bh)->h_refcount = cpu_to_le32(1 +le32_to_cpu(HDR(new_bh)->h_refcount));ea_bdebug(new_bh, "refcount now=%d",le32_to_cpu(HDR(new_bh)->h_refcount));}unlock_buffer(new_bh);} else if (old_bh && header == HDR(old_bh)) {/* Keep this block. No need to lock the block as we   don't need to change the reference count. */new_bh = old_bh;get_bh(new_bh);ext2_xattr_cache_insert(new_bh);} else {/* We need to allocate a new block */int goal = le32_to_cpu(EXT2_SB(sb)->s_es->           s_first_data_block) +   EXT2_I(inode)->i_block_group *   EXT2_BLOCKS_PER_GROUP(sb);int block = ext2_new_block(inode, goal,   NULL, NULL, &error);if (error)goto cleanup;ea_idebug(inode, "creating block %d", block);new_bh = sb_getblk(sb, block);if (!new_bh) {ext2_free_blocks(inode, block, 1);error = -EIO;goto cleanup;}lock_buffer(new_bh);memcpy(new_bh->b_data, header, new_bh->b_size);set_buffer_uptodate(new_bh);unlock_buffer(new_bh);ext2_xattr_cache_insert(new_bh);ext2_xattr_update_super_block(sb);}/*new_bh脏了*/mark_buffer_dirty(new_bh);if (IS_SYNC(inode)) {sync_dirty_buffer(new_bh);error = -EIO;if (buffer_req(new_bh) && !buffer_uptodate(new_bh))goto cleanup;}}/*更新inode的i_file_acl字段,修改时间等*/EXT2_I(inode)->i_file_acl = new_bh ? new_bh->b_blocknr : 0;inode->i_ctime = CURRENT_TIME_SEC;/*是否需要同步*/if (IS_SYNC(inode)) {error = ext2_sync_inode (inode);if (error && error != -ENOSPC) {if (new_bh && new_bh != old_bh)DQUOT_FREE_BLOCK(inode, 1);goto cleanup;}} elsemark_inode_dirty(inode);error = 0;/*如果存在原有的块,并且我们已经不用了就释放*/if (old_bh && old_bh != new_bh) {struct mb_cache_entry *ce;/*找到他在缓存里的位置*/ce = mb_cache_entry_get(ext2_xattr_cache, old_bh->b_bdev,old_bh->b_blocknr);lock_buffer(old_bh);if (HDR(old_bh)->h_refcount == cpu_to_le32(1)) {/* 如果引用仅仅有一个,释放 */if (ce)mb_cache_entry_free(ce);ea_bdebug(old_bh, "freeing");ext2_free_blocks(inode, old_bh->b_blocknr, 1);/* We let our caller release old_bh, so we * need to duplicate the buffer before. */get_bh(old_bh);bforget(old_bh);} else {/* 减少引用计数 */HDR(old_bh)->h_refcount = cpu_to_le32(le32_to_cpu(HDR(old_bh)->h_refcount) - 1);if (ce)mb_cache_entry_release(ce);DQUOT_FREE_BLOCK(inode, 1);mark_buffer_dirty(old_bh);ea_bdebug(old_bh, "refcount now=%d",le32_to_cpu(HDR(old_bh)->h_refcount));}unlock_buffer(old_bh);}cleanup:brelse(new_bh);return error;}/* ext2_xattr_delete_inode()函数释放与inode相关的属性资源 */voidext2_xattr_delete_inode(struct inode *inode){struct buffer_head *bh = NULL;struct mb_cache_entry *ce;/*读i_file_acl之前都要上这个锁*/down_write(&EXT2_I(inode)->xattr_sem);if (!EXT2_I(inode)->i_file_acl)goto cleanup;/*读这个属性所在的块*/bh = sb_bread(inode->i_sb, EXT2_I(inode)->i_file_acl);/*如果读取出现错误*/if (!bh) {ext2_error(inode->i_sb, "ext2_xattr_delete_inode","inode %ld: block %d read error", inode->i_ino,EXT2_I(inode)->i_file_acl);goto cleanup;}ea_bdebug(bh, "b_count=%d", atomic_read(&(bh->b_count)));/*检验读取出来的buffer_head是不是有问题,是不是ext2文件系统的属性*/if (HDR(bh)->h_magic != cpu_to_le32(EXT2_XATTR_MAGIC) ||    HDR(bh)->h_blocks != cpu_to_le32(1)) {ext2_error(inode->i_sb, "ext2_xattr_delete_inode","inode %ld: bad block %d", inode->i_ino,EXT2_I(inode)->i_file_acl);goto cleanup;}/*在ext2_xattr_cache缓存里寻找并删除*/ce = mb_cache_entry_get(ext2_xattr_cache, bh->b_bdev, bh->b_blocknr);lock_buffer(bh);/*引用计数为1就删除*/if (HDR(bh)->h_refcount == cpu_to_le32(1)) {if (ce)mb_cache_entry_free(ce);ext2_free_blocks(inode, EXT2_I(inode)->i_file_acl, 1);get_bh(bh);bforget(bh);unlock_buffer(bh);} else {/*递减引用计数*/HDR(bh)->h_refcount = cpu_to_le32(le32_to_cpu(HDR(bh)->h_refcount) - 1);if (ce)mb_cache_entry_release(ce);ea_bdebug(bh, "refcount now=%d",le32_to_cpu(HDR(bh)->h_refcount));unlock_buffer(bh);mark_buffer_dirty(bh);if (IS_SYNC(inode))sync_dirty_buffer(bh);DQUOT_FREE_BLOCK(inode, 1);}EXT2_I(inode)->i_file_acl = 0;cleanup:brelse(bh);up_write(&EXT2_I(inode)->xattr_sem);}/* ext2_xattr_put_super()当文件系统被卸载的时候调用 */voidext2_xattr_put_super(struct super_block *sb){mb_cache_shrink(sb->s_bdev);}/* ext2_xattr_cache_insert()函数在属性缓存里创建一个新的扩展属性项,不管它是不是已经在ext2_xattr_cache缓存里,成返回0 */static intext2_xattr_cache_insert(struct buffer_head *bh){/*插入缓存是需要hash来便于查找*/__u32 hash = le32_to_cpu(HDR(bh)->h_hash);struct mb_cache_entry *ce;int error;/*在ext2_xattr_cache分配缓存*/ce = mb_cache_entry_alloc(ext2_xattr_cache);if (!ce)return -ENOMEM;/*把这个ce插入*/error = mb_cache_entry_insert(ce, bh->b_bdev, bh->b_blocknr, &hash);/*插入失败,释放缓存*/if (error) {mb_cache_entry_free(ce);if (error == -EBUSY) {ea_bdebug(bh, "already in cache (%d cache entries)",atomic_read(&ext2_xattr_cache->c_entry_count));error = 0;}} else {ea_bdebug(bh, "inserting [%x] (%d cache entries)", (int)hash,  atomic_read(&ext2_xattr_cache->c_entry_count));mb_cache_entry_release(ce);}return error;}/* ext2_xattr_cmp()函数比较两个扩展属性块,当这两个一样时返回0,不一样返回1,有错误返回负数 */static intext2_xattr_cmp(struct ext2_xattr_header *header1,       struct ext2_xattr_header *header2){struct ext2_xattr_entry *entry1, *entry2;/*得到这两个缓冲区的head*/entry1 = ENTRY(header1+1);entry2 = ENTRY(header2+1);/*遍历开始*/while (!IS_LAST_ENTRY(entry1)) {/*第一个没有到结尾第二个到结尾了,说明不一样*/if (IS_LAST_ENTRY(entry2))return 1;/*比较*/if (entry1->e_hash != entry2->e_hash ||    entry1->e_name_index != entry2->e_name_index ||    entry1->e_name_len != entry2->e_name_len ||    entry1->e_value_size != entry2->e_value_size ||    memcmp(entry1->e_name, entry2->e_name, entry1->e_name_len))return 1;if (entry1->e_value_block != 0 || entry2->e_value_block != 0)return -EIO;/*比较value*/if (memcmp((char *)header1 + le16_to_cpu(entry1->e_value_offs),   (char *)header2 + le16_to_cpu(entry2->e_value_offs),   le32_to_cpu(entry1->e_value_size)))return 1;/*指向下一个*/entry1 = EXT2_XATTR_NEXT(entry1);entry2 = EXT2_XATTR_NEXT(entry2);}/*不一样*/if (!IS_LAST_ENTRY(entry2))return 1;return 0;}/*ext2_xattr_cache_find()函数,寻找一个标记的扩展属性块。成功的话返回找到的块的buffer_head,失败返回NULL*/static struct buffer_head *ext2_xattr_cache_find(struct inode *inode, struct ext2_xattr_header *header){__u32 hash = le32_to_cpu(header->h_hash);struct mb_cache_entry *ce;/*没有共享在hash里*/if (!header->h_hash)return NULL;  ea_idebug(inode, "looking for cached blocks [%x]", (int)hash);again:/*在ext2_xattr_cache缓存里一个一个的找*/ce = mb_cache_entry_find_first(ext2_xattr_cache, 0,       inode->i_sb->s_bdev, hash);/*寻找的循环*/while (ce) {struct buffer_head *bh;/*检验得到的是不是合法的*/if (IS_ERR(ce)) {if (PTR_ERR(ce) == -EAGAIN)goto again;break;}/*读取这一块进入内存*/bh = sb_bread(inode->i_sb, ce->e_block);/*如果IO读取出错*/if (!bh) {ext2_error(inode->i_sb, "ext2_xattr_cache_find","inode %ld: block %ld read error",inode->i_ino, (unsigned long) ce->e_block);} else {/*开始读取buffer_head*/lock_buffer(bh);/*一个缓冲区被引用太多次*/if (le32_to_cpu(HDR(bh)->h_refcount) >   EXT2_XATTR_REFCOUNT_MAX) {ea_idebug(inode, "block %ld refcount %d>%d",  (unsigned long) ce->e_block,  le32_to_cpu(HDR(bh)->h_refcount),  EXT2_XATTR_REFCOUNT_MAX);/*匹配*/} else if (!ext2_xattr_cmp(header, HDR(bh))) {ea_bdebug(bh, "b_count=%d",  atomic_read(&(bh->b_count)));mb_cache_entry_release(ce);return bh;}unlock_buffer(bh);brelse(bh);}/*继续找*/ce = mb_cache_entry_find_next(ce, 0, inode->i_sb->s_bdev, hash);}return NULL;}#define NAME_HASH_SHIFT 5#define VALUE_HASH_SHIFT 16/*ext2_xattr_hash_entry()计算这个扩展属性的hash值 */static inline void ext2_xattr_hash_entry(struct ext2_xattr_header *header, struct ext2_xattr_entry *entry){__u32 hash = 0;char *name = entry->e_name;int n;for (n=0; n < entry->e_name_len; n++) {hash = (hash << NAME_HASH_SHIFT) ^       (hash >> (8*sizeof(hash) - NAME_HASH_SHIFT)) ^       *name++;}if (entry->e_value_block == 0 && entry->e_value_size != 0) {__le32 *value = (__le32 *)((char *)header +le16_to_cpu(entry->e_value_offs));for (n = (le32_to_cpu(entry->e_value_size) +     EXT2_XATTR_ROUND) >> EXT2_XATTR_PAD_BITS; n; n--) {hash = (hash << VALUE_HASH_SHIFT) ^       (hash >> (8*sizeof(hash) - VALUE_HASH_SHIFT)) ^       le32_to_cpu(*value++);}}entry->e_hash = cpu_to_le32(hash);}#undef NAME_HASH_SHIFT#undef VALUE_HASH_SHIFT#define BLOCK_HASH_SHIFT 16/* * ext2_xattr_rehash()重新计算hash值 */static void ext2_xattr_rehash(struct ext2_xattr_header *header,      struct ext2_xattr_entry *entry){struct ext2_xattr_entry *here;__u32 hash = 0;ext2_xattr_hash_entry(header, entry);here = ENTRY(header+1);while (!IS_LAST_ENTRY(here)) {if (!here->e_hash) {/* Block is not shared if an entry's hash value == 0 */hash = 0;break;}hash = (hash << BLOCK_HASH_SHIFT) ^       (hash >> (8*sizeof(hash) - BLOCK_HASH_SHIFT)) ^       le32_to_cpu(here->e_hash);here = EXT2_XATTR_NEXT(here);}header->h_hash = cpu_to_le32(hash);}#undef BLOCK_HASH_SHIFT/*ext2属性初始化*/int __initinit_ext2_xattr(void){/*创建缓冲区*/ext2_xattr_cache = mb_cache_create("ext2_xattr", NULL,sizeof(struct mb_cache_entry) +sizeof(((struct mb_cache_entry *) 0)->e_indexes[0]), 1, 6);if (!ext2_xattr_cache)return -ENOMEM;return 0;}/*ext2属性退出销毁*/voidexit_ext2_xattr(void){mb_cache_destroy(ext2_xattr_cache);}

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 报税ukey丢了怎么办 苏州学生e卡通怎么办 教师继续教育学时不够怎么办 在看守所37天后怎么办 cad证书丢了怎么办 学信网注册身份证重复怎么办 学历和学位认证怎么办 假学历无法认证怎么办 学历认证没照片怎么办? 毕业证封皮丢了怎么办 留服认证不了怎么办 无公害认证书怎么办 假学历认证报告怎么办 留学要求寄原件怎么办 干部小三怀孕怎么办? 小三的孩子怎么办 把小三打住院了怎么办 小月子没人伺候怎么办 寝室室友有狐臭怎么办 室友在寝室养猫怎么办 和直接领导不合怎么办 房产共有人去世怎么办 发现邪教宣传内容怎么办 说课时两个课时怎么办 投稿文章被拒绝怎么办 中立性细胞偏低怎么办? 孩子爱告状老师怎么办 高中学不好数学怎么办 想做老师应该怎么办 教师职称换学校怎么办 大四差选修学分怎么办 尔雅通识课学分没修满怎么办 大学全英文授课怎么办 小孩脑部有囊肿怎么办 防震期间门应该怎么办 在家待着没意思怎么办 人户分离上学怎么办 小孩上学没人接送怎么办 宝宝上学没人接送怎么办 上海浦东新区酒类许可证怎么办 金税盘里报税处理打不开怎么办