📄 xattr.c
字号:
} b_error = ext3_xattr_block_list(inode, buffer, buffer_size); if (b_error < 0) i_error = 0; } up_read(&EXT3_I(inode)->xattr_sem); return i_error + b_error;}/* * If the EXT3_FEATURE_COMPAT_EXT_ATTR feature of this file system is * not set, set it. */static void ext3_xattr_update_super_block(handle_t *handle, struct super_block *sb){ if (EXT3_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_EXT_ATTR)) return; if (ext3_journal_get_write_access(handle, EXT3_SB(sb)->s_sbh) == 0) { EXT3_SET_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_EXT_ATTR); sb->s_dirt = 1; ext3_journal_dirty_metadata(handle, EXT3_SB(sb)->s_sbh); }}/* * Release the xattr block BH: If the reference count is > 1, decrement * it; otherwise free the block. */static voidext3_xattr_release_block(handle_t *handle, struct inode *inode, struct buffer_head *bh){ struct mb_cache_entry *ce = NULL; int error = 0; ce = mb_cache_entry_get(ext3_xattr_cache, bh->b_bdev, bh->b_blocknr); error = ext3_journal_get_write_access(handle, bh); if (error) goto out; lock_buffer(bh); if (BHDR(bh)->h_refcount == cpu_to_le32(1)) { ea_bdebug(bh, "refcount now=0; freeing"); if (ce) mb_cache_entry_free(ce); ext3_free_blocks(handle, inode, bh->b_blocknr, 1); get_bh(bh); ext3_forget(handle, 1, inode, bh, bh->b_blocknr); } else { BHDR(bh)->h_refcount = cpu_to_le32( le32_to_cpu(BHDR(bh)->h_refcount) - 1); error = ext3_journal_dirty_metadata(handle, bh); if (IS_SYNC(inode)) handle->h_sync = 1; DQUOT_FREE_BLOCK(inode, 1); ea_bdebug(bh, "refcount now=%d; releasing", le32_to_cpu(BHDR(bh)->h_refcount)); if (ce) mb_cache_entry_release(ce); } unlock_buffer(bh);out: ext3_std_error(inode->i_sb, error); return;}struct ext3_xattr_info { int name_index; const char *name; const void *value; size_t value_len;};struct ext3_xattr_search { struct ext3_xattr_entry *first; void *base; void *end; struct ext3_xattr_entry *here; int not_found;};static intext3_xattr_set_entry(struct ext3_xattr_info *i, struct ext3_xattr_search *s){ struct ext3_xattr_entry *last; size_t free, min_offs = s->end - s->base, name_len = strlen(i->name); /* Compute min_offs and last. */ last = s->first; for (; !IS_LAST_ENTRY(last); last = EXT3_XATTR_NEXT(last)) { 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; } } free = min_offs - ((void *)last - s->base) - sizeof(__u32); if (!s->not_found) { if (!s->here->e_value_block && s->here->e_value_size) { size_t size = le32_to_cpu(s->here->e_value_size); free += EXT3_XATTR_SIZE(size); } free += EXT3_XATTR_LEN(name_len); } if (i->value) { if (free < EXT3_XATTR_SIZE(i->value_len) || free < EXT3_XATTR_LEN(name_len) + EXT3_XATTR_SIZE(i->value_len)) return -ENOSPC; } if (i->value && s->not_found) { /* Insert the new name. */ size_t size = EXT3_XATTR_LEN(name_len); size_t rest = (void *)last - (void *)s->here + sizeof(__u32); memmove((void *)s->here + size, s->here, rest); memset(s->here, 0, size); s->here->e_name_index = i->name_index; s->here->e_name_len = name_len; memcpy(s->here->e_name, i->name, name_len); } else { if (!s->here->e_value_block && s->here->e_value_size) { void *first_val = s->base + min_offs; size_t offs = le16_to_cpu(s->here->e_value_offs); void *val = s->base + offs; size_t size = EXT3_XATTR_SIZE( le32_to_cpu(s->here->e_value_size)); if (i->value && size == EXT3_XATTR_SIZE(i->value_len)) { /* The old and the new value have the same size. Just replace. */ s->here->e_value_size = cpu_to_le32(i->value_len); memset(val + size - EXT3_XATTR_PAD, 0, EXT3_XATTR_PAD); /* Clear pad bytes. */ memcpy(val, i->value, i->value_len); return 0; } /* Remove the old value. */ memmove(first_val + size, first_val, val - first_val); memset(first_val, 0, size); s->here->e_value_size = 0; s->here->e_value_offs = 0; min_offs += size; /* Adjust all value offsets. */ last = s->first; while (!IS_LAST_ENTRY(last)) { size_t o = le16_to_cpu(last->e_value_offs); if (!last->e_value_block && last->e_value_size && o < offs) last->e_value_offs = cpu_to_le16(o + size); last = EXT3_XATTR_NEXT(last); } } if (!i->value) { /* Remove the old name. */ size_t size = EXT3_XATTR_LEN(name_len); last = ENTRY((void *)last - size); memmove(s->here, (void *)s->here + size, (void *)last - (void *)s->here + sizeof(__u32)); memset(last, 0, size); } } if (i->value) { /* Insert the new value. */ s->here->e_value_size = cpu_to_le32(i->value_len); if (i->value_len) { size_t size = EXT3_XATTR_SIZE(i->value_len); void *val = s->base + min_offs - size; s->here->e_value_offs = cpu_to_le16(min_offs - size); memset(val + size - EXT3_XATTR_PAD, 0, EXT3_XATTR_PAD); /* Clear the pad bytes. */ memcpy(val, i->value, i->value_len); } } return 0;}struct ext3_xattr_block_find { struct ext3_xattr_search s; struct buffer_head *bh;};static intext3_xattr_block_find(struct inode *inode, struct ext3_xattr_info *i, struct ext3_xattr_block_find *bs){ struct super_block *sb = inode->i_sb; int error; ea_idebug(inode, "name=%d.%s, value=%p, value_len=%ld", i->name_index, i->name, i->value, (long)i->value_len); if (EXT3_I(inode)->i_file_acl) { /* The inode already has an extended attribute block. */ bs->bh = sb_bread(sb, EXT3_I(inode)->i_file_acl); error = -EIO; if (!bs->bh) goto cleanup; ea_bdebug(bs->bh, "b_count=%d, refcount=%d", atomic_read(&(bs->bh->b_count)), le32_to_cpu(BHDR(bs->bh)->h_refcount)); if (ext3_xattr_check_block(bs->bh)) { ext3_error(sb, __FUNCTION__, "inode %lu: bad block "E3FSBLK, inode->i_ino, EXT3_I(inode)->i_file_acl); error = -EIO; goto cleanup; } /* Find the named attribute. */ bs->s.base = BHDR(bs->bh); bs->s.first = BFIRST(bs->bh); bs->s.end = bs->bh->b_data + bs->bh->b_size; bs->s.here = bs->s.first; error = ext3_xattr_find_entry(&bs->s.here, i->name_index, i->name, bs->bh->b_size, 1); if (error && error != -ENODATA) goto cleanup; bs->s.not_found = error; } error = 0;cleanup: return error;}static intext3_xattr_block_set(handle_t *handle, struct inode *inode, struct ext3_xattr_info *i, struct ext3_xattr_block_find *bs){ struct super_block *sb = inode->i_sb; struct buffer_head *new_bh = NULL; struct ext3_xattr_search *s = &bs->s; struct mb_cache_entry *ce = NULL; int error = 0;#define header(x) ((struct ext3_xattr_header *)(x)) if (i->value && i->value_len > sb->s_blocksize) return -ENOSPC; if (s->base) { ce = mb_cache_entry_get(ext3_xattr_cache, bs->bh->b_bdev, bs->bh->b_blocknr); error = ext3_journal_get_write_access(handle, bs->bh); if (error) goto cleanup; lock_buffer(bs->bh); if (header(s->base)->h_refcount == cpu_to_le32(1)) { if (ce) { mb_cache_entry_free(ce); ce = NULL; } ea_bdebug(bs->bh, "modifying in-place"); error = ext3_xattr_set_entry(i, s); if (!error) { if (!IS_LAST_ENTRY(s->first)) ext3_xattr_rehash(header(s->base), s->here); ext3_xattr_cache_insert(bs->bh); } unlock_buffer(bs->bh); if (error == -EIO) goto bad_block; if (!error) error = ext3_journal_dirty_metadata(handle, bs->bh); if (error) goto cleanup; goto inserted; } else { int offset = (char *)s->here - bs->bh->b_data; unlock_buffer(bs->bh); journal_release_buffer(handle, bs->bh); if (ce) { mb_cache_entry_release(ce); ce = NULL; } ea_bdebug(bs->bh, "cloning"); s->base = kmalloc(bs->bh->b_size, GFP_KERNEL); error = -ENOMEM; if (s->base == NULL) goto cleanup; memcpy(s->base, BHDR(bs->bh), bs->bh->b_size); s->first = ENTRY(header(s->base)+1); header(s->base)->h_refcount = cpu_to_le32(1); s->here = ENTRY(s->base + offset); s->end = s->base + bs->bh->b_size; } } else { /* Allocate a buffer where we construct the new block. */ s->base = kzalloc(sb->s_blocksize, GFP_KERNEL); /* assert(header == s->base) */ error = -ENOMEM; if (s->base == NULL) goto cleanup; header(s->base)->h_magic = cpu_to_le32(EXT3_XATTR_MAGIC); header(s->base)->h_blocks = cpu_to_le32(1); header(s->base)->h_refcount = cpu_to_le32(1); s->first = ENTRY(header(s->base)+1); s->here = ENTRY(header(s->base)+1); s->end = s->base + sb->s_blocksize; } error = ext3_xattr_set_entry(i, s); if (error == -EIO) goto bad_block; if (error) goto cleanup; if (!IS_LAST_ENTRY(s->first)) ext3_xattr_rehash(header(s->base), s->here);inserted: if (!IS_LAST_ENTRY(s->first)) { new_bh = ext3_xattr_cache_find(inode, header(s->base), &ce); if (new_bh) { /* We found an identical block in the cache. */ if (new_bh == bs->bh) ea_bdebug(new_bh, "keeping"); else { /* The old block is released after updating the inode. */ error = -EDQUOT; if (DQUOT_ALLOC_BLOCK(inode, 1)) goto cleanup; error = ext3_journal_get_write_access(handle, new_bh); if (error) goto cleanup_dquot; lock_buffer(new_bh); BHDR(new_bh)->h_refcount = cpu_to_le32(1 + le32_to_cpu(BHDR(new_bh)->h_refcount)); ea_bdebug(new_bh, "reusing; refcount now=%d", le32_to_cpu(BHDR(new_bh)->h_refcount)); unlock_buffer(new_bh); error = ext3_journal_dirty_metadata(handle, new_bh); if (error) goto cleanup_dquot; } mb_cache_entry_release(ce); ce = NULL; } else if (bs->bh && s->base == bs->bh->b_data) { /* We were modifying this block in-place. */ ea_bdebug(bs->bh, "keeping this block"); new_bh = bs->bh; get_bh(new_bh); } else { /* We need to allocate a new block */ ext3_fsblk_t goal = le32_to_cpu( EXT3_SB(sb)->s_es->s_first_data_block) + (ext3_fsblk_t)EXT3_I(inode)->i_block_group * EXT3_BLOCKS_PER_GROUP(sb); ext3_fsblk_t block = ext3_new_block(handle, inode, goal, &error); if (error) goto cleanup; ea_idebug(inode, "creating block %d", block); new_bh = sb_getblk(sb, block); if (!new_bh) {getblk_failed: ext3_free_blocks(handle, inode, block, 1); error = -EIO; goto cleanup; } lock_buffer(new_bh); error = ext3_journal_get_create_access(handle, new_bh); if (error) { unlock_buffer(new_bh); goto getblk_failed; } memcpy(new_bh->b_data, s->base, new_bh->b_size); set_buffer_uptodate(new_bh); unlock_buffer(new_bh); ext3_xattr_cache_insert(new_bh); error = ext3_journal_dirty_metadata(handle, new_bh); if (error) goto cleanup; } } /* Update the inode. */ EXT3_I(inode)->i_file_acl = new_bh ? new_bh->b_blocknr : 0; /* Drop the previous xattr block. */ if (bs->bh && bs->bh != new_bh) ext3_xattr_release_block(handle, inode, bs->bh); error = 0;cleanup: if (ce) mb_cache_entry_release(ce); brelse(new_bh); if (!(bs->bh && s->base == bs->bh->b_data)) kfree(s->base); return error;cleanup_dquot: DQUOT_FREE_BLOCK(inode, 1); goto cleanup;bad_block: ext3_error(inode->i_sb, __FUNCTION__, "inode %lu: bad block "E3FSBLK, inode->i_ino, EXT3_I(inode)->i_file_acl); goto cleanup;#undef header}struct ext3_xattr_ibody_find { struct ext3_xattr_search s; struct ext3_iloc iloc;};static intext3_xattr_ibody_find(struct inode *inode, struct ext3_xattr_info *i, struct ext3_xattr_ibody_find *is){ struct ext3_xattr_ibody_header *header; struct ext3_inode *raw_inode; int error; if (EXT3_I(inode)->i_extra_isize == 0) return 0; raw_inode = ext3_raw_inode(&is->iloc); header = IHDR(inode, raw_inode); is->s.base = is->s.first = IFIRST(header); is->s.here = is->s.first; is->s.end = (void *)raw_inode + EXT3_SB(inode->i_sb)->s_inode_size;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -