📄 xattr.c
字号:
if (EXT3_I(inode)->i_state & EXT3_STATE_XATTR) { error = ext3_xattr_check_names(IFIRST(header), is->s.end); if (error) return error; /* Find the named attribute. */ error = ext3_xattr_find_entry(&is->s.here, i->name_index, i->name, is->s.end - (void *)is->s.base, 0); if (error && error != -ENODATA) return error; is->s.not_found = error; } return 0;}static intext3_xattr_ibody_set(handle_t *handle, struct inode *inode, struct ext3_xattr_info *i, struct ext3_xattr_ibody_find *is){ struct ext3_xattr_ibody_header *header; struct ext3_xattr_search *s = &is->s; int error; if (EXT3_I(inode)->i_extra_isize == 0) return -ENOSPC; error = ext3_xattr_set_entry(i, s); if (error) return error; header = IHDR(inode, ext3_raw_inode(&is->iloc)); if (!IS_LAST_ENTRY(s->first)) { header->h_magic = cpu_to_le32(EXT3_XATTR_MAGIC); EXT3_I(inode)->i_state |= EXT3_STATE_XATTR; } else { header->h_magic = cpu_to_le32(0); EXT3_I(inode)->i_state &= ~EXT3_STATE_XATTR; } return 0;}/* * ext3_xattr_set_handle() * * Create, replace or remove an extended attribute for this inode. Buffer * is NULL to remove an existing extended attribute, and non-NULL to * either replace an existing extended attribute, or create a new extended * attribute. The flags XATTR_REPLACE and XATTR_CREATE * specify that an extended attribute must exist and must not exist * previous to the call, respectively. * * Returns 0, or a negative error number on failure. */intext3_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index, const char *name, const void *value, size_t value_len, int flags){ struct ext3_xattr_info i = { .name_index = name_index, .name = name, .value = value, .value_len = value_len, }; struct ext3_xattr_ibody_find is = { .s = { .not_found = -ENODATA, }, }; struct ext3_xattr_block_find bs = { .s = { .not_found = -ENODATA, }, }; int error; if (!name) return -EINVAL; if (strlen(name) > 255) return -ERANGE; down_write(&EXT3_I(inode)->xattr_sem); error = ext3_get_inode_loc(inode, &is.iloc); if (error) goto cleanup; if (EXT3_I(inode)->i_state & EXT3_STATE_NEW) { struct ext3_inode *raw_inode = ext3_raw_inode(&is.iloc); memset(raw_inode, 0, EXT3_SB(inode->i_sb)->s_inode_size); EXT3_I(inode)->i_state &= ~EXT3_STATE_NEW; } error = ext3_xattr_ibody_find(inode, &i, &is); if (error) goto cleanup; if (is.s.not_found) error = ext3_xattr_block_find(inode, &i, &bs); if (error) goto cleanup; if (is.s.not_found && bs.s.not_found) { error = -ENODATA; if (flags & XATTR_REPLACE) goto cleanup; error = 0; if (!value) goto cleanup; } else { error = -EEXIST; if (flags & XATTR_CREATE) goto cleanup; } error = ext3_journal_get_write_access(handle, is.iloc.bh); if (error) goto cleanup; if (!value) { if (!is.s.not_found) error = ext3_xattr_ibody_set(handle, inode, &i, &is); else if (!bs.s.not_found) error = ext3_xattr_block_set(handle, inode, &i, &bs); } else { error = ext3_xattr_ibody_set(handle, inode, &i, &is); if (!error && !bs.s.not_found) { i.value = NULL; error = ext3_xattr_block_set(handle, inode, &i, &bs); } else if (error == -ENOSPC) { error = ext3_xattr_block_set(handle, inode, &i, &bs); if (error) goto cleanup; if (!is.s.not_found) { i.value = NULL; error = ext3_xattr_ibody_set(handle, inode, &i, &is); } } } if (!error) { ext3_xattr_update_super_block(handle, inode->i_sb); inode->i_ctime = CURRENT_TIME_SEC; error = ext3_mark_iloc_dirty(handle, inode, &is.iloc); /* * The bh is consumed by ext3_mark_iloc_dirty, even with * error != 0. */ is.iloc.bh = NULL; if (IS_SYNC(inode)) handle->h_sync = 1; }cleanup: brelse(is.iloc.bh); brelse(bs.bh); up_write(&EXT3_I(inode)->xattr_sem); return error;}/* * ext3_xattr_set() * * Like ext3_xattr_set_handle, but start from an inode. This extended * attribute modification is a filesystem transaction by itself. * * Returns 0, or a negative error number on failure. */intext3_xattr_set(struct inode *inode, int name_index, const char *name, const void *value, size_t value_len, int flags){ handle_t *handle; int error, retries = 0;retry: handle = ext3_journal_start(inode, EXT3_DATA_TRANS_BLOCKS(inode->i_sb)); if (IS_ERR(handle)) { error = PTR_ERR(handle); } else { int error2; error = ext3_xattr_set_handle(handle, inode, name_index, name, value, value_len, flags); error2 = ext3_journal_stop(handle); if (error == -ENOSPC && ext3_should_retry_alloc(inode->i_sb, &retries)) goto retry; if (error == 0) error = error2; } return error;}/* * ext3_xattr_delete_inode() * * Free extended attribute resources associated with this inode. This * is called immediately before an inode is freed. We have exclusive * access to the inode. */voidext3_xattr_delete_inode(handle_t *handle, struct inode *inode){ struct buffer_head *bh = NULL; if (!EXT3_I(inode)->i_file_acl) goto cleanup; bh = sb_bread(inode->i_sb, EXT3_I(inode)->i_file_acl); if (!bh) { ext3_error(inode->i_sb, __FUNCTION__, "inode %lu: block "E3FSBLK" read error", inode->i_ino, EXT3_I(inode)->i_file_acl); goto cleanup; } if (BHDR(bh)->h_magic != cpu_to_le32(EXT3_XATTR_MAGIC) || BHDR(bh)->h_blocks != cpu_to_le32(1)) { ext3_error(inode->i_sb, __FUNCTION__, "inode %lu: bad block "E3FSBLK, inode->i_ino, EXT3_I(inode)->i_file_acl); goto cleanup; } ext3_xattr_release_block(handle, inode, bh); EXT3_I(inode)->i_file_acl = 0;cleanup: brelse(bh);}/* * ext3_xattr_put_super() * * This is called when a file system is unmounted. */voidext3_xattr_put_super(struct super_block *sb){ mb_cache_shrink(sb->s_bdev);}/* * ext3_xattr_cache_insert() * * Create a new entry in the extended attribute cache, and insert * it unless such an entry is already in the cache. * * Returns 0, or a negative error number on failure. */static voidext3_xattr_cache_insert(struct buffer_head *bh){ __u32 hash = le32_to_cpu(BHDR(bh)->h_hash); struct mb_cache_entry *ce; int error; ce = mb_cache_entry_alloc(ext3_xattr_cache); if (!ce) { ea_bdebug(bh, "out of memory"); return; } 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"); error = 0; } } else { ea_bdebug(bh, "inserting [%x]", (int)hash); mb_cache_entry_release(ce); }}/* * ext3_xattr_cmp() * * Compare two extended attribute blocks for equality. * * Returns 0 if the blocks are equal, 1 if they differ, and * a negative error number on errors. */static intext3_xattr_cmp(struct ext3_xattr_header *header1, struct ext3_xattr_header *header2){ struct ext3_xattr_entry *entry1, *entry2; 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; 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 = EXT3_XATTR_NEXT(entry1); entry2 = EXT3_XATTR_NEXT(entry2); } if (!IS_LAST_ENTRY(entry2)) return 1; return 0;}/* * ext3_xattr_cache_find() * * Find an identical extended attribute block. * * Returns a pointer to the block found, or NULL if such a block was * not found or an error occurred. */static struct buffer_head *ext3_xattr_cache_find(struct inode *inode, struct ext3_xattr_header *header, struct mb_cache_entry **pce){ __u32 hash = le32_to_cpu(header->h_hash); struct mb_cache_entry *ce; if (!header->h_hash) return NULL; /* never share */ ea_idebug(inode, "looking for cached blocks [%x]", (int)hash);again: ce = mb_cache_entry_find_first(ext3_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); if (!bh) { ext3_error(inode->i_sb, __FUNCTION__, "inode %lu: block %lu read error", inode->i_ino, (unsigned long) ce->e_block); } else if (le32_to_cpu(BHDR(bh)->h_refcount) >= EXT3_XATTR_REFCOUNT_MAX) { ea_idebug(inode, "block %lu refcount %d>=%d", (unsigned long) ce->e_block, le32_to_cpu(BHDR(bh)->h_refcount), EXT3_XATTR_REFCOUNT_MAX); } else if (ext3_xattr_cmp(header, BHDR(bh)) == 0) { *pce = ce; return 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/* * ext3_xattr_hash_entry() * * Compute the hash of an extended attribute. */static inline void ext3_xattr_hash_entry(struct ext3_xattr_header *header, struct ext3_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) + EXT3_XATTR_ROUND) >> EXT3_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/* * ext3_xattr_rehash() * * Re-compute the extended attribute hash value after an entry has changed. */static void ext3_xattr_rehash(struct ext3_xattr_header *header, struct ext3_xattr_entry *entry){ struct ext3_xattr_entry *here; __u32 hash = 0; ext3_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 = EXT3_XATTR_NEXT(here); } header->h_hash = cpu_to_le32(hash);}#undef BLOCK_HASH_SHIFTint __initinit_ext3_xattr(void){ ext3_xattr_cache = mb_cache_create("ext3_xattr", NULL, sizeof(struct mb_cache_entry) + sizeof(((struct mb_cache_entry *) 0)->e_indexes[0]), 1, 6); if (!ext3_xattr_cache) return -ENOMEM; return 0;}voidexit_ext3_xattr(void){ if (ext3_xattr_cache) mb_cache_destroy(ext3_xattr_cache); ext3_xattr_cache = NULL;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -