162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * linux/fs/ext4/xattr.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2001-2003 Andreas Gruenbacher, <agruen@suse.de> 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Fix by Harrison Xing <harrison@mountainviewdata.com>. 862306a36Sopenharmony_ci * Ext4 code with a lot of help from Eric Jarman <ejarman@acm.org>. 962306a36Sopenharmony_ci * Extended attributes for symlinks and special files added per 1062306a36Sopenharmony_ci * suggestion of Luka Renko <luka.renko@hermes.si>. 1162306a36Sopenharmony_ci * xattr consolidation Copyright (c) 2004 James Morris <jmorris@redhat.com>, 1262306a36Sopenharmony_ci * Red Hat Inc. 1362306a36Sopenharmony_ci * ea-in-inode support by Alex Tomas <alex@clusterfs.com> aka bzzz 1462306a36Sopenharmony_ci * and Andreas Gruenbacher <agruen@suse.de>. 1562306a36Sopenharmony_ci */ 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci/* 1862306a36Sopenharmony_ci * Extended attributes are stored directly in inodes (on file systems with 1962306a36Sopenharmony_ci * inodes bigger than 128 bytes) and on additional disk blocks. The i_file_acl 2062306a36Sopenharmony_ci * field contains the block number if an inode uses an additional block. All 2162306a36Sopenharmony_ci * attributes must fit in the inode and one additional block. Blocks that 2262306a36Sopenharmony_ci * contain the identical set of attributes may be shared among several inodes. 2362306a36Sopenharmony_ci * Identical blocks are detected by keeping a cache of blocks that have 2462306a36Sopenharmony_ci * recently been accessed. 2562306a36Sopenharmony_ci * 2662306a36Sopenharmony_ci * The attributes in inodes and on blocks have a different header; the entries 2762306a36Sopenharmony_ci * are stored in the same format: 2862306a36Sopenharmony_ci * 2962306a36Sopenharmony_ci * +------------------+ 3062306a36Sopenharmony_ci * | header | 3162306a36Sopenharmony_ci * | entry 1 | | 3262306a36Sopenharmony_ci * | entry 2 | | growing downwards 3362306a36Sopenharmony_ci * | entry 3 | v 3462306a36Sopenharmony_ci * | four null bytes | 3562306a36Sopenharmony_ci * | . . . | 3662306a36Sopenharmony_ci * | value 1 | ^ 3762306a36Sopenharmony_ci * | value 3 | | growing upwards 3862306a36Sopenharmony_ci * | value 2 | | 3962306a36Sopenharmony_ci * +------------------+ 4062306a36Sopenharmony_ci * 4162306a36Sopenharmony_ci * The header is followed by multiple entry descriptors. In disk blocks, the 4262306a36Sopenharmony_ci * entry descriptors are kept sorted. In inodes, they are unsorted. The 4362306a36Sopenharmony_ci * attribute values are aligned to the end of the block in no specific order. 4462306a36Sopenharmony_ci * 4562306a36Sopenharmony_ci * Locking strategy 4662306a36Sopenharmony_ci * ---------------- 4762306a36Sopenharmony_ci * EXT4_I(inode)->i_file_acl is protected by EXT4_I(inode)->xattr_sem. 4862306a36Sopenharmony_ci * EA blocks are only changed if they are exclusive to an inode, so 4962306a36Sopenharmony_ci * holding xattr_sem also means that nothing but the EA block's reference 5062306a36Sopenharmony_ci * count can change. Multiple writers to the same block are synchronized 5162306a36Sopenharmony_ci * by the buffer lock. 5262306a36Sopenharmony_ci */ 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci#include <linux/init.h> 5562306a36Sopenharmony_ci#include <linux/fs.h> 5662306a36Sopenharmony_ci#include <linux/slab.h> 5762306a36Sopenharmony_ci#include <linux/mbcache.h> 5862306a36Sopenharmony_ci#include <linux/quotaops.h> 5962306a36Sopenharmony_ci#include <linux/iversion.h> 6062306a36Sopenharmony_ci#include "ext4_jbd2.h" 6162306a36Sopenharmony_ci#include "ext4.h" 6262306a36Sopenharmony_ci#include "xattr.h" 6362306a36Sopenharmony_ci#include "acl.h" 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci#ifdef EXT4_XATTR_DEBUG 6662306a36Sopenharmony_ci# define ea_idebug(inode, fmt, ...) \ 6762306a36Sopenharmony_ci printk(KERN_DEBUG "inode %s:%lu: " fmt "\n", \ 6862306a36Sopenharmony_ci inode->i_sb->s_id, inode->i_ino, ##__VA_ARGS__) 6962306a36Sopenharmony_ci# define ea_bdebug(bh, fmt, ...) \ 7062306a36Sopenharmony_ci printk(KERN_DEBUG "block %pg:%lu: " fmt "\n", \ 7162306a36Sopenharmony_ci bh->b_bdev, (unsigned long)bh->b_blocknr, ##__VA_ARGS__) 7262306a36Sopenharmony_ci#else 7362306a36Sopenharmony_ci# define ea_idebug(inode, fmt, ...) no_printk(fmt, ##__VA_ARGS__) 7462306a36Sopenharmony_ci# define ea_bdebug(bh, fmt, ...) no_printk(fmt, ##__VA_ARGS__) 7562306a36Sopenharmony_ci#endif 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_cistatic void ext4_xattr_block_cache_insert(struct mb_cache *, 7862306a36Sopenharmony_ci struct buffer_head *); 7962306a36Sopenharmony_cistatic struct buffer_head * 8062306a36Sopenharmony_ciext4_xattr_block_cache_find(struct inode *, struct ext4_xattr_header *, 8162306a36Sopenharmony_ci struct mb_cache_entry **); 8262306a36Sopenharmony_cistatic __le32 ext4_xattr_hash_entry(char *name, size_t name_len, __le32 *value, 8362306a36Sopenharmony_ci size_t value_count); 8462306a36Sopenharmony_cistatic __le32 ext4_xattr_hash_entry_signed(char *name, size_t name_len, __le32 *value, 8562306a36Sopenharmony_ci size_t value_count); 8662306a36Sopenharmony_cistatic void ext4_xattr_rehash(struct ext4_xattr_header *); 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_cistatic const struct xattr_handler * const ext4_xattr_handler_map[] = { 8962306a36Sopenharmony_ci [EXT4_XATTR_INDEX_USER] = &ext4_xattr_user_handler, 9062306a36Sopenharmony_ci#ifdef CONFIG_EXT4_FS_POSIX_ACL 9162306a36Sopenharmony_ci [EXT4_XATTR_INDEX_POSIX_ACL_ACCESS] = &nop_posix_acl_access, 9262306a36Sopenharmony_ci [EXT4_XATTR_INDEX_POSIX_ACL_DEFAULT] = &nop_posix_acl_default, 9362306a36Sopenharmony_ci#endif 9462306a36Sopenharmony_ci [EXT4_XATTR_INDEX_TRUSTED] = &ext4_xattr_trusted_handler, 9562306a36Sopenharmony_ci#ifdef CONFIG_EXT4_FS_SECURITY 9662306a36Sopenharmony_ci [EXT4_XATTR_INDEX_SECURITY] = &ext4_xattr_security_handler, 9762306a36Sopenharmony_ci#endif 9862306a36Sopenharmony_ci [EXT4_XATTR_INDEX_HURD] = &ext4_xattr_hurd_handler, 9962306a36Sopenharmony_ci}; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ciconst struct xattr_handler *ext4_xattr_handlers[] = { 10262306a36Sopenharmony_ci &ext4_xattr_user_handler, 10362306a36Sopenharmony_ci &ext4_xattr_trusted_handler, 10462306a36Sopenharmony_ci#ifdef CONFIG_EXT4_FS_SECURITY 10562306a36Sopenharmony_ci &ext4_xattr_security_handler, 10662306a36Sopenharmony_ci#endif 10762306a36Sopenharmony_ci &ext4_xattr_hurd_handler, 10862306a36Sopenharmony_ci NULL 10962306a36Sopenharmony_ci}; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci#define EA_BLOCK_CACHE(inode) (((struct ext4_sb_info *) \ 11262306a36Sopenharmony_ci inode->i_sb->s_fs_info)->s_ea_block_cache) 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci#define EA_INODE_CACHE(inode) (((struct ext4_sb_info *) \ 11562306a36Sopenharmony_ci inode->i_sb->s_fs_info)->s_ea_inode_cache) 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_cistatic int 11862306a36Sopenharmony_ciext4_expand_inode_array(struct ext4_xattr_inode_array **ea_inode_array, 11962306a36Sopenharmony_ci struct inode *inode); 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci#ifdef CONFIG_LOCKDEP 12262306a36Sopenharmony_civoid ext4_xattr_inode_set_class(struct inode *ea_inode) 12362306a36Sopenharmony_ci{ 12462306a36Sopenharmony_ci struct ext4_inode_info *ei = EXT4_I(ea_inode); 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci lockdep_set_subclass(&ea_inode->i_rwsem, 1); 12762306a36Sopenharmony_ci (void) ei; /* shut up clang warning if !CONFIG_LOCKDEP */ 12862306a36Sopenharmony_ci lockdep_set_subclass(&ei->i_data_sem, I_DATA_SEM_EA); 12962306a36Sopenharmony_ci} 13062306a36Sopenharmony_ci#endif 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_cistatic __le32 ext4_xattr_block_csum(struct inode *inode, 13362306a36Sopenharmony_ci sector_t block_nr, 13462306a36Sopenharmony_ci struct ext4_xattr_header *hdr) 13562306a36Sopenharmony_ci{ 13662306a36Sopenharmony_ci struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); 13762306a36Sopenharmony_ci __u32 csum; 13862306a36Sopenharmony_ci __le64 dsk_block_nr = cpu_to_le64(block_nr); 13962306a36Sopenharmony_ci __u32 dummy_csum = 0; 14062306a36Sopenharmony_ci int offset = offsetof(struct ext4_xattr_header, h_checksum); 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci csum = ext4_chksum(sbi, sbi->s_csum_seed, (__u8 *)&dsk_block_nr, 14362306a36Sopenharmony_ci sizeof(dsk_block_nr)); 14462306a36Sopenharmony_ci csum = ext4_chksum(sbi, csum, (__u8 *)hdr, offset); 14562306a36Sopenharmony_ci csum = ext4_chksum(sbi, csum, (__u8 *)&dummy_csum, sizeof(dummy_csum)); 14662306a36Sopenharmony_ci offset += sizeof(dummy_csum); 14762306a36Sopenharmony_ci csum = ext4_chksum(sbi, csum, (__u8 *)hdr + offset, 14862306a36Sopenharmony_ci EXT4_BLOCK_SIZE(inode->i_sb) - offset); 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci return cpu_to_le32(csum); 15162306a36Sopenharmony_ci} 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_cistatic int ext4_xattr_block_csum_verify(struct inode *inode, 15462306a36Sopenharmony_ci struct buffer_head *bh) 15562306a36Sopenharmony_ci{ 15662306a36Sopenharmony_ci struct ext4_xattr_header *hdr = BHDR(bh); 15762306a36Sopenharmony_ci int ret = 1; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci if (ext4_has_metadata_csum(inode->i_sb)) { 16062306a36Sopenharmony_ci lock_buffer(bh); 16162306a36Sopenharmony_ci ret = (hdr->h_checksum == ext4_xattr_block_csum(inode, 16262306a36Sopenharmony_ci bh->b_blocknr, hdr)); 16362306a36Sopenharmony_ci unlock_buffer(bh); 16462306a36Sopenharmony_ci } 16562306a36Sopenharmony_ci return ret; 16662306a36Sopenharmony_ci} 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_cistatic void ext4_xattr_block_csum_set(struct inode *inode, 16962306a36Sopenharmony_ci struct buffer_head *bh) 17062306a36Sopenharmony_ci{ 17162306a36Sopenharmony_ci if (ext4_has_metadata_csum(inode->i_sb)) 17262306a36Sopenharmony_ci BHDR(bh)->h_checksum = ext4_xattr_block_csum(inode, 17362306a36Sopenharmony_ci bh->b_blocknr, BHDR(bh)); 17462306a36Sopenharmony_ci} 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_cistatic inline const char *ext4_xattr_prefix(int name_index, 17762306a36Sopenharmony_ci struct dentry *dentry) 17862306a36Sopenharmony_ci{ 17962306a36Sopenharmony_ci const struct xattr_handler *handler = NULL; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci if (name_index > 0 && name_index < ARRAY_SIZE(ext4_xattr_handler_map)) 18262306a36Sopenharmony_ci handler = ext4_xattr_handler_map[name_index]; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci if (!xattr_handler_can_list(handler, dentry)) 18562306a36Sopenharmony_ci return NULL; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci return xattr_prefix(handler); 18862306a36Sopenharmony_ci} 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_cistatic int 19162306a36Sopenharmony_cicheck_xattrs(struct inode *inode, struct buffer_head *bh, 19262306a36Sopenharmony_ci struct ext4_xattr_entry *entry, void *end, void *value_start, 19362306a36Sopenharmony_ci const char *function, unsigned int line) 19462306a36Sopenharmony_ci{ 19562306a36Sopenharmony_ci struct ext4_xattr_entry *e = entry; 19662306a36Sopenharmony_ci int err = -EFSCORRUPTED; 19762306a36Sopenharmony_ci char *err_str; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci if (bh) { 20062306a36Sopenharmony_ci if (BHDR(bh)->h_magic != cpu_to_le32(EXT4_XATTR_MAGIC) || 20162306a36Sopenharmony_ci BHDR(bh)->h_blocks != cpu_to_le32(1)) { 20262306a36Sopenharmony_ci err_str = "invalid header"; 20362306a36Sopenharmony_ci goto errout; 20462306a36Sopenharmony_ci } 20562306a36Sopenharmony_ci if (buffer_verified(bh)) 20662306a36Sopenharmony_ci return 0; 20762306a36Sopenharmony_ci if (!ext4_xattr_block_csum_verify(inode, bh)) { 20862306a36Sopenharmony_ci err = -EFSBADCRC; 20962306a36Sopenharmony_ci err_str = "invalid checksum"; 21062306a36Sopenharmony_ci goto errout; 21162306a36Sopenharmony_ci } 21262306a36Sopenharmony_ci } else { 21362306a36Sopenharmony_ci struct ext4_xattr_ibody_header *header = value_start; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci header -= 1; 21662306a36Sopenharmony_ci if (end - (void *)header < sizeof(*header) + sizeof(u32)) { 21762306a36Sopenharmony_ci err_str = "in-inode xattr block too small"; 21862306a36Sopenharmony_ci goto errout; 21962306a36Sopenharmony_ci } 22062306a36Sopenharmony_ci if (header->h_magic != cpu_to_le32(EXT4_XATTR_MAGIC)) { 22162306a36Sopenharmony_ci err_str = "bad magic number in in-inode xattr"; 22262306a36Sopenharmony_ci goto errout; 22362306a36Sopenharmony_ci } 22462306a36Sopenharmony_ci } 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci /* Find the end of the names list */ 22762306a36Sopenharmony_ci while (!IS_LAST_ENTRY(e)) { 22862306a36Sopenharmony_ci struct ext4_xattr_entry *next = EXT4_XATTR_NEXT(e); 22962306a36Sopenharmony_ci if ((void *)next >= end) { 23062306a36Sopenharmony_ci err_str = "e_name out of bounds"; 23162306a36Sopenharmony_ci goto errout; 23262306a36Sopenharmony_ci } 23362306a36Sopenharmony_ci if (strnlen(e->e_name, e->e_name_len) != e->e_name_len) { 23462306a36Sopenharmony_ci err_str = "bad e_name length"; 23562306a36Sopenharmony_ci goto errout; 23662306a36Sopenharmony_ci } 23762306a36Sopenharmony_ci e = next; 23862306a36Sopenharmony_ci } 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci /* Check the values */ 24162306a36Sopenharmony_ci while (!IS_LAST_ENTRY(entry)) { 24262306a36Sopenharmony_ci u32 size = le32_to_cpu(entry->e_value_size); 24362306a36Sopenharmony_ci unsigned long ea_ino = le32_to_cpu(entry->e_value_inum); 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci if (!ext4_has_feature_ea_inode(inode->i_sb) && ea_ino) { 24662306a36Sopenharmony_ci err_str = "ea_inode specified without ea_inode feature enabled"; 24762306a36Sopenharmony_ci goto errout; 24862306a36Sopenharmony_ci } 24962306a36Sopenharmony_ci if (ea_ino && ((ea_ino == EXT4_ROOT_INO) || 25062306a36Sopenharmony_ci !ext4_valid_inum(inode->i_sb, ea_ino))) { 25162306a36Sopenharmony_ci err_str = "invalid ea_ino"; 25262306a36Sopenharmony_ci goto errout; 25362306a36Sopenharmony_ci } 25462306a36Sopenharmony_ci if (size > EXT4_XATTR_SIZE_MAX) { 25562306a36Sopenharmony_ci err_str = "e_value size too large"; 25662306a36Sopenharmony_ci goto errout; 25762306a36Sopenharmony_ci } 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci if (size != 0 && entry->e_value_inum == 0) { 26062306a36Sopenharmony_ci u16 offs = le16_to_cpu(entry->e_value_offs); 26162306a36Sopenharmony_ci void *value; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci /* 26462306a36Sopenharmony_ci * The value cannot overlap the names, and the value 26562306a36Sopenharmony_ci * with padding cannot extend beyond 'end'. Check both 26662306a36Sopenharmony_ci * the padded and unpadded sizes, since the size may 26762306a36Sopenharmony_ci * overflow to 0 when adding padding. 26862306a36Sopenharmony_ci */ 26962306a36Sopenharmony_ci if (offs > end - value_start) { 27062306a36Sopenharmony_ci err_str = "e_value out of bounds"; 27162306a36Sopenharmony_ci goto errout; 27262306a36Sopenharmony_ci } 27362306a36Sopenharmony_ci value = value_start + offs; 27462306a36Sopenharmony_ci if (value < (void *)e + sizeof(u32) || 27562306a36Sopenharmony_ci size > end - value || 27662306a36Sopenharmony_ci EXT4_XATTR_SIZE(size) > end - value) { 27762306a36Sopenharmony_ci err_str = "overlapping e_value "; 27862306a36Sopenharmony_ci goto errout; 27962306a36Sopenharmony_ci } 28062306a36Sopenharmony_ci } 28162306a36Sopenharmony_ci entry = EXT4_XATTR_NEXT(entry); 28262306a36Sopenharmony_ci } 28362306a36Sopenharmony_ci if (bh) 28462306a36Sopenharmony_ci set_buffer_verified(bh); 28562306a36Sopenharmony_ci return 0; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_cierrout: 28862306a36Sopenharmony_ci if (bh) 28962306a36Sopenharmony_ci __ext4_error_inode(inode, function, line, 0, -err, 29062306a36Sopenharmony_ci "corrupted xattr block %llu: %s", 29162306a36Sopenharmony_ci (unsigned long long) bh->b_blocknr, 29262306a36Sopenharmony_ci err_str); 29362306a36Sopenharmony_ci else 29462306a36Sopenharmony_ci __ext4_error_inode(inode, function, line, 0, -err, 29562306a36Sopenharmony_ci "corrupted in-inode xattr: %s", err_str); 29662306a36Sopenharmony_ci return err; 29762306a36Sopenharmony_ci} 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_cistatic inline int 30062306a36Sopenharmony_ci__ext4_xattr_check_block(struct inode *inode, struct buffer_head *bh, 30162306a36Sopenharmony_ci const char *function, unsigned int line) 30262306a36Sopenharmony_ci{ 30362306a36Sopenharmony_ci return check_xattrs(inode, bh, BFIRST(bh), bh->b_data + bh->b_size, 30462306a36Sopenharmony_ci bh->b_data, function, line); 30562306a36Sopenharmony_ci} 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci#define ext4_xattr_check_block(inode, bh) \ 30862306a36Sopenharmony_ci __ext4_xattr_check_block((inode), (bh), __func__, __LINE__) 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_cistatic inline int 31262306a36Sopenharmony_ci__xattr_check_inode(struct inode *inode, struct ext4_xattr_ibody_header *header, 31362306a36Sopenharmony_ci void *end, const char *function, unsigned int line) 31462306a36Sopenharmony_ci{ 31562306a36Sopenharmony_ci return check_xattrs(inode, NULL, IFIRST(header), end, IFIRST(header), 31662306a36Sopenharmony_ci function, line); 31762306a36Sopenharmony_ci} 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci#define xattr_check_inode(inode, header, end) \ 32062306a36Sopenharmony_ci __xattr_check_inode((inode), (header), (end), __func__, __LINE__) 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_cistatic int 32362306a36Sopenharmony_cixattr_find_entry(struct inode *inode, struct ext4_xattr_entry **pentry, 32462306a36Sopenharmony_ci void *end, int name_index, const char *name, int sorted) 32562306a36Sopenharmony_ci{ 32662306a36Sopenharmony_ci struct ext4_xattr_entry *entry, *next; 32762306a36Sopenharmony_ci size_t name_len; 32862306a36Sopenharmony_ci int cmp = 1; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci if (name == NULL) 33162306a36Sopenharmony_ci return -EINVAL; 33262306a36Sopenharmony_ci name_len = strlen(name); 33362306a36Sopenharmony_ci for (entry = *pentry; !IS_LAST_ENTRY(entry); entry = next) { 33462306a36Sopenharmony_ci next = EXT4_XATTR_NEXT(entry); 33562306a36Sopenharmony_ci if ((void *) next >= end) { 33662306a36Sopenharmony_ci EXT4_ERROR_INODE(inode, "corrupted xattr entries"); 33762306a36Sopenharmony_ci return -EFSCORRUPTED; 33862306a36Sopenharmony_ci } 33962306a36Sopenharmony_ci cmp = name_index - entry->e_name_index; 34062306a36Sopenharmony_ci if (!cmp) 34162306a36Sopenharmony_ci cmp = name_len - entry->e_name_len; 34262306a36Sopenharmony_ci if (!cmp) 34362306a36Sopenharmony_ci cmp = memcmp(name, entry->e_name, name_len); 34462306a36Sopenharmony_ci if (cmp <= 0 && (sorted || cmp == 0)) 34562306a36Sopenharmony_ci break; 34662306a36Sopenharmony_ci } 34762306a36Sopenharmony_ci *pentry = entry; 34862306a36Sopenharmony_ci return cmp ? -ENODATA : 0; 34962306a36Sopenharmony_ci} 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_cistatic u32 35262306a36Sopenharmony_ciext4_xattr_inode_hash(struct ext4_sb_info *sbi, const void *buffer, size_t size) 35362306a36Sopenharmony_ci{ 35462306a36Sopenharmony_ci return ext4_chksum(sbi, sbi->s_csum_seed, buffer, size); 35562306a36Sopenharmony_ci} 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_cistatic u64 ext4_xattr_inode_get_ref(struct inode *ea_inode) 35862306a36Sopenharmony_ci{ 35962306a36Sopenharmony_ci return ((u64) inode_get_ctime(ea_inode).tv_sec << 32) | 36062306a36Sopenharmony_ci (u32) inode_peek_iversion_raw(ea_inode); 36162306a36Sopenharmony_ci} 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_cistatic void ext4_xattr_inode_set_ref(struct inode *ea_inode, u64 ref_count) 36462306a36Sopenharmony_ci{ 36562306a36Sopenharmony_ci inode_set_ctime(ea_inode, (u32)(ref_count >> 32), 0); 36662306a36Sopenharmony_ci inode_set_iversion_raw(ea_inode, ref_count & 0xffffffff); 36762306a36Sopenharmony_ci} 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_cistatic u32 ext4_xattr_inode_get_hash(struct inode *ea_inode) 37062306a36Sopenharmony_ci{ 37162306a36Sopenharmony_ci return (u32)ea_inode->i_atime.tv_sec; 37262306a36Sopenharmony_ci} 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_cistatic void ext4_xattr_inode_set_hash(struct inode *ea_inode, u32 hash) 37562306a36Sopenharmony_ci{ 37662306a36Sopenharmony_ci ea_inode->i_atime.tv_sec = hash; 37762306a36Sopenharmony_ci} 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci/* 38062306a36Sopenharmony_ci * Read the EA value from an inode. 38162306a36Sopenharmony_ci */ 38262306a36Sopenharmony_cistatic int ext4_xattr_inode_read(struct inode *ea_inode, void *buf, size_t size) 38362306a36Sopenharmony_ci{ 38462306a36Sopenharmony_ci int blocksize = 1 << ea_inode->i_blkbits; 38562306a36Sopenharmony_ci int bh_count = (size + blocksize - 1) >> ea_inode->i_blkbits; 38662306a36Sopenharmony_ci int tail_size = (size % blocksize) ?: blocksize; 38762306a36Sopenharmony_ci struct buffer_head *bhs_inline[8]; 38862306a36Sopenharmony_ci struct buffer_head **bhs = bhs_inline; 38962306a36Sopenharmony_ci int i, ret; 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci if (bh_count > ARRAY_SIZE(bhs_inline)) { 39262306a36Sopenharmony_ci bhs = kmalloc_array(bh_count, sizeof(*bhs), GFP_NOFS); 39362306a36Sopenharmony_ci if (!bhs) 39462306a36Sopenharmony_ci return -ENOMEM; 39562306a36Sopenharmony_ci } 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci ret = ext4_bread_batch(ea_inode, 0 /* block */, bh_count, 39862306a36Sopenharmony_ci true /* wait */, bhs); 39962306a36Sopenharmony_ci if (ret) 40062306a36Sopenharmony_ci goto free_bhs; 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci for (i = 0; i < bh_count; i++) { 40362306a36Sopenharmony_ci /* There shouldn't be any holes in ea_inode. */ 40462306a36Sopenharmony_ci if (!bhs[i]) { 40562306a36Sopenharmony_ci ret = -EFSCORRUPTED; 40662306a36Sopenharmony_ci goto put_bhs; 40762306a36Sopenharmony_ci } 40862306a36Sopenharmony_ci memcpy((char *)buf + blocksize * i, bhs[i]->b_data, 40962306a36Sopenharmony_ci i < bh_count - 1 ? blocksize : tail_size); 41062306a36Sopenharmony_ci } 41162306a36Sopenharmony_ci ret = 0; 41262306a36Sopenharmony_ciput_bhs: 41362306a36Sopenharmony_ci for (i = 0; i < bh_count; i++) 41462306a36Sopenharmony_ci brelse(bhs[i]); 41562306a36Sopenharmony_cifree_bhs: 41662306a36Sopenharmony_ci if (bhs != bhs_inline) 41762306a36Sopenharmony_ci kfree(bhs); 41862306a36Sopenharmony_ci return ret; 41962306a36Sopenharmony_ci} 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci#define EXT4_XATTR_INODE_GET_PARENT(inode) ((__u32)(inode)->i_mtime.tv_sec) 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_cistatic int ext4_xattr_inode_iget(struct inode *parent, unsigned long ea_ino, 42462306a36Sopenharmony_ci u32 ea_inode_hash, struct inode **ea_inode) 42562306a36Sopenharmony_ci{ 42662306a36Sopenharmony_ci struct inode *inode; 42762306a36Sopenharmony_ci int err; 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci /* 43062306a36Sopenharmony_ci * We have to check for this corruption early as otherwise 43162306a36Sopenharmony_ci * iget_locked() could wait indefinitely for the state of our 43262306a36Sopenharmony_ci * parent inode. 43362306a36Sopenharmony_ci */ 43462306a36Sopenharmony_ci if (parent->i_ino == ea_ino) { 43562306a36Sopenharmony_ci ext4_error(parent->i_sb, 43662306a36Sopenharmony_ci "Parent and EA inode have the same ino %lu", ea_ino); 43762306a36Sopenharmony_ci return -EFSCORRUPTED; 43862306a36Sopenharmony_ci } 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci inode = ext4_iget(parent->i_sb, ea_ino, EXT4_IGET_EA_INODE); 44162306a36Sopenharmony_ci if (IS_ERR(inode)) { 44262306a36Sopenharmony_ci err = PTR_ERR(inode); 44362306a36Sopenharmony_ci ext4_error(parent->i_sb, 44462306a36Sopenharmony_ci "error while reading EA inode %lu err=%d", ea_ino, 44562306a36Sopenharmony_ci err); 44662306a36Sopenharmony_ci return err; 44762306a36Sopenharmony_ci } 44862306a36Sopenharmony_ci ext4_xattr_inode_set_class(inode); 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci /* 45162306a36Sopenharmony_ci * Check whether this is an old Lustre-style xattr inode. Lustre 45262306a36Sopenharmony_ci * implementation does not have hash validation, rather it has a 45362306a36Sopenharmony_ci * backpointer from ea_inode to the parent inode. 45462306a36Sopenharmony_ci */ 45562306a36Sopenharmony_ci if (ea_inode_hash != ext4_xattr_inode_get_hash(inode) && 45662306a36Sopenharmony_ci EXT4_XATTR_INODE_GET_PARENT(inode) == parent->i_ino && 45762306a36Sopenharmony_ci inode->i_generation == parent->i_generation) { 45862306a36Sopenharmony_ci ext4_set_inode_state(inode, EXT4_STATE_LUSTRE_EA_INODE); 45962306a36Sopenharmony_ci ext4_xattr_inode_set_ref(inode, 1); 46062306a36Sopenharmony_ci } else { 46162306a36Sopenharmony_ci inode_lock(inode); 46262306a36Sopenharmony_ci inode->i_flags |= S_NOQUOTA; 46362306a36Sopenharmony_ci inode_unlock(inode); 46462306a36Sopenharmony_ci } 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci *ea_inode = inode; 46762306a36Sopenharmony_ci return 0; 46862306a36Sopenharmony_ci} 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci/* Remove entry from mbcache when EA inode is getting evicted */ 47162306a36Sopenharmony_civoid ext4_evict_ea_inode(struct inode *inode) 47262306a36Sopenharmony_ci{ 47362306a36Sopenharmony_ci struct mb_cache_entry *oe; 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci if (!EA_INODE_CACHE(inode)) 47662306a36Sopenharmony_ci return; 47762306a36Sopenharmony_ci /* Wait for entry to get unused so that we can remove it */ 47862306a36Sopenharmony_ci while ((oe = mb_cache_entry_delete_or_get(EA_INODE_CACHE(inode), 47962306a36Sopenharmony_ci ext4_xattr_inode_get_hash(inode), inode->i_ino))) { 48062306a36Sopenharmony_ci mb_cache_entry_wait_unused(oe); 48162306a36Sopenharmony_ci mb_cache_entry_put(EA_INODE_CACHE(inode), oe); 48262306a36Sopenharmony_ci } 48362306a36Sopenharmony_ci} 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_cistatic int 48662306a36Sopenharmony_ciext4_xattr_inode_verify_hashes(struct inode *ea_inode, 48762306a36Sopenharmony_ci struct ext4_xattr_entry *entry, void *buffer, 48862306a36Sopenharmony_ci size_t size) 48962306a36Sopenharmony_ci{ 49062306a36Sopenharmony_ci u32 hash; 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci /* Verify stored hash matches calculated hash. */ 49362306a36Sopenharmony_ci hash = ext4_xattr_inode_hash(EXT4_SB(ea_inode->i_sb), buffer, size); 49462306a36Sopenharmony_ci if (hash != ext4_xattr_inode_get_hash(ea_inode)) 49562306a36Sopenharmony_ci return -EFSCORRUPTED; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci if (entry) { 49862306a36Sopenharmony_ci __le32 e_hash, tmp_data; 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci /* Verify entry hash. */ 50162306a36Sopenharmony_ci tmp_data = cpu_to_le32(hash); 50262306a36Sopenharmony_ci e_hash = ext4_xattr_hash_entry(entry->e_name, entry->e_name_len, 50362306a36Sopenharmony_ci &tmp_data, 1); 50462306a36Sopenharmony_ci /* All good? */ 50562306a36Sopenharmony_ci if (e_hash == entry->e_hash) 50662306a36Sopenharmony_ci return 0; 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci /* 50962306a36Sopenharmony_ci * Not good. Maybe the entry hash was calculated 51062306a36Sopenharmony_ci * using the buggy signed char version? 51162306a36Sopenharmony_ci */ 51262306a36Sopenharmony_ci e_hash = ext4_xattr_hash_entry_signed(entry->e_name, entry->e_name_len, 51362306a36Sopenharmony_ci &tmp_data, 1); 51462306a36Sopenharmony_ci /* Still no match - bad */ 51562306a36Sopenharmony_ci if (e_hash != entry->e_hash) 51662306a36Sopenharmony_ci return -EFSCORRUPTED; 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci /* Let people know about old hash */ 51962306a36Sopenharmony_ci pr_warn_once("ext4: filesystem with signed xattr name hash"); 52062306a36Sopenharmony_ci } 52162306a36Sopenharmony_ci return 0; 52262306a36Sopenharmony_ci} 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci/* 52562306a36Sopenharmony_ci * Read xattr value from the EA inode. 52662306a36Sopenharmony_ci */ 52762306a36Sopenharmony_cistatic int 52862306a36Sopenharmony_ciext4_xattr_inode_get(struct inode *inode, struct ext4_xattr_entry *entry, 52962306a36Sopenharmony_ci void *buffer, size_t size) 53062306a36Sopenharmony_ci{ 53162306a36Sopenharmony_ci struct mb_cache *ea_inode_cache = EA_INODE_CACHE(inode); 53262306a36Sopenharmony_ci struct inode *ea_inode; 53362306a36Sopenharmony_ci int err; 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci err = ext4_xattr_inode_iget(inode, le32_to_cpu(entry->e_value_inum), 53662306a36Sopenharmony_ci le32_to_cpu(entry->e_hash), &ea_inode); 53762306a36Sopenharmony_ci if (err) { 53862306a36Sopenharmony_ci ea_inode = NULL; 53962306a36Sopenharmony_ci goto out; 54062306a36Sopenharmony_ci } 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci if (i_size_read(ea_inode) != size) { 54362306a36Sopenharmony_ci ext4_warning_inode(ea_inode, 54462306a36Sopenharmony_ci "ea_inode file size=%llu entry size=%zu", 54562306a36Sopenharmony_ci i_size_read(ea_inode), size); 54662306a36Sopenharmony_ci err = -EFSCORRUPTED; 54762306a36Sopenharmony_ci goto out; 54862306a36Sopenharmony_ci } 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci err = ext4_xattr_inode_read(ea_inode, buffer, size); 55162306a36Sopenharmony_ci if (err) 55262306a36Sopenharmony_ci goto out; 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci if (!ext4_test_inode_state(ea_inode, EXT4_STATE_LUSTRE_EA_INODE)) { 55562306a36Sopenharmony_ci err = ext4_xattr_inode_verify_hashes(ea_inode, entry, buffer, 55662306a36Sopenharmony_ci size); 55762306a36Sopenharmony_ci if (err) { 55862306a36Sopenharmony_ci ext4_warning_inode(ea_inode, 55962306a36Sopenharmony_ci "EA inode hash validation failed"); 56062306a36Sopenharmony_ci goto out; 56162306a36Sopenharmony_ci } 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci if (ea_inode_cache) 56462306a36Sopenharmony_ci mb_cache_entry_create(ea_inode_cache, GFP_NOFS, 56562306a36Sopenharmony_ci ext4_xattr_inode_get_hash(ea_inode), 56662306a36Sopenharmony_ci ea_inode->i_ino, true /* reusable */); 56762306a36Sopenharmony_ci } 56862306a36Sopenharmony_ciout: 56962306a36Sopenharmony_ci iput(ea_inode); 57062306a36Sopenharmony_ci return err; 57162306a36Sopenharmony_ci} 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_cistatic int 57462306a36Sopenharmony_ciext4_xattr_block_get(struct inode *inode, int name_index, const char *name, 57562306a36Sopenharmony_ci void *buffer, size_t buffer_size) 57662306a36Sopenharmony_ci{ 57762306a36Sopenharmony_ci struct buffer_head *bh = NULL; 57862306a36Sopenharmony_ci struct ext4_xattr_entry *entry; 57962306a36Sopenharmony_ci size_t size; 58062306a36Sopenharmony_ci void *end; 58162306a36Sopenharmony_ci int error; 58262306a36Sopenharmony_ci struct mb_cache *ea_block_cache = EA_BLOCK_CACHE(inode); 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci ea_idebug(inode, "name=%d.%s, buffer=%p, buffer_size=%ld", 58562306a36Sopenharmony_ci name_index, name, buffer, (long)buffer_size); 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci if (!EXT4_I(inode)->i_file_acl) 58862306a36Sopenharmony_ci return -ENODATA; 58962306a36Sopenharmony_ci ea_idebug(inode, "reading block %llu", 59062306a36Sopenharmony_ci (unsigned long long)EXT4_I(inode)->i_file_acl); 59162306a36Sopenharmony_ci bh = ext4_sb_bread(inode->i_sb, EXT4_I(inode)->i_file_acl, REQ_PRIO); 59262306a36Sopenharmony_ci if (IS_ERR(bh)) 59362306a36Sopenharmony_ci return PTR_ERR(bh); 59462306a36Sopenharmony_ci ea_bdebug(bh, "b_count=%d, refcount=%d", 59562306a36Sopenharmony_ci atomic_read(&(bh->b_count)), le32_to_cpu(BHDR(bh)->h_refcount)); 59662306a36Sopenharmony_ci error = ext4_xattr_check_block(inode, bh); 59762306a36Sopenharmony_ci if (error) 59862306a36Sopenharmony_ci goto cleanup; 59962306a36Sopenharmony_ci ext4_xattr_block_cache_insert(ea_block_cache, bh); 60062306a36Sopenharmony_ci entry = BFIRST(bh); 60162306a36Sopenharmony_ci end = bh->b_data + bh->b_size; 60262306a36Sopenharmony_ci error = xattr_find_entry(inode, &entry, end, name_index, name, 1); 60362306a36Sopenharmony_ci if (error) 60462306a36Sopenharmony_ci goto cleanup; 60562306a36Sopenharmony_ci size = le32_to_cpu(entry->e_value_size); 60662306a36Sopenharmony_ci error = -ERANGE; 60762306a36Sopenharmony_ci if (unlikely(size > EXT4_XATTR_SIZE_MAX)) 60862306a36Sopenharmony_ci goto cleanup; 60962306a36Sopenharmony_ci if (buffer) { 61062306a36Sopenharmony_ci if (size > buffer_size) 61162306a36Sopenharmony_ci goto cleanup; 61262306a36Sopenharmony_ci if (entry->e_value_inum) { 61362306a36Sopenharmony_ci error = ext4_xattr_inode_get(inode, entry, buffer, 61462306a36Sopenharmony_ci size); 61562306a36Sopenharmony_ci if (error) 61662306a36Sopenharmony_ci goto cleanup; 61762306a36Sopenharmony_ci } else { 61862306a36Sopenharmony_ci u16 offset = le16_to_cpu(entry->e_value_offs); 61962306a36Sopenharmony_ci void *p = bh->b_data + offset; 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci if (unlikely(p + size > end)) 62262306a36Sopenharmony_ci goto cleanup; 62362306a36Sopenharmony_ci memcpy(buffer, p, size); 62462306a36Sopenharmony_ci } 62562306a36Sopenharmony_ci } 62662306a36Sopenharmony_ci error = size; 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_cicleanup: 62962306a36Sopenharmony_ci brelse(bh); 63062306a36Sopenharmony_ci return error; 63162306a36Sopenharmony_ci} 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ciint 63462306a36Sopenharmony_ciext4_xattr_ibody_get(struct inode *inode, int name_index, const char *name, 63562306a36Sopenharmony_ci void *buffer, size_t buffer_size) 63662306a36Sopenharmony_ci{ 63762306a36Sopenharmony_ci struct ext4_xattr_ibody_header *header; 63862306a36Sopenharmony_ci struct ext4_xattr_entry *entry; 63962306a36Sopenharmony_ci struct ext4_inode *raw_inode; 64062306a36Sopenharmony_ci struct ext4_iloc iloc; 64162306a36Sopenharmony_ci size_t size; 64262306a36Sopenharmony_ci void *end; 64362306a36Sopenharmony_ci int error; 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci if (!ext4_test_inode_state(inode, EXT4_STATE_XATTR)) 64662306a36Sopenharmony_ci return -ENODATA; 64762306a36Sopenharmony_ci error = ext4_get_inode_loc(inode, &iloc); 64862306a36Sopenharmony_ci if (error) 64962306a36Sopenharmony_ci return error; 65062306a36Sopenharmony_ci raw_inode = ext4_raw_inode(&iloc); 65162306a36Sopenharmony_ci header = IHDR(inode, raw_inode); 65262306a36Sopenharmony_ci end = (void *)raw_inode + EXT4_SB(inode->i_sb)->s_inode_size; 65362306a36Sopenharmony_ci error = xattr_check_inode(inode, header, end); 65462306a36Sopenharmony_ci if (error) 65562306a36Sopenharmony_ci goto cleanup; 65662306a36Sopenharmony_ci entry = IFIRST(header); 65762306a36Sopenharmony_ci error = xattr_find_entry(inode, &entry, end, name_index, name, 0); 65862306a36Sopenharmony_ci if (error) 65962306a36Sopenharmony_ci goto cleanup; 66062306a36Sopenharmony_ci size = le32_to_cpu(entry->e_value_size); 66162306a36Sopenharmony_ci error = -ERANGE; 66262306a36Sopenharmony_ci if (unlikely(size > EXT4_XATTR_SIZE_MAX)) 66362306a36Sopenharmony_ci goto cleanup; 66462306a36Sopenharmony_ci if (buffer) { 66562306a36Sopenharmony_ci if (size > buffer_size) 66662306a36Sopenharmony_ci goto cleanup; 66762306a36Sopenharmony_ci if (entry->e_value_inum) { 66862306a36Sopenharmony_ci error = ext4_xattr_inode_get(inode, entry, buffer, 66962306a36Sopenharmony_ci size); 67062306a36Sopenharmony_ci if (error) 67162306a36Sopenharmony_ci goto cleanup; 67262306a36Sopenharmony_ci } else { 67362306a36Sopenharmony_ci u16 offset = le16_to_cpu(entry->e_value_offs); 67462306a36Sopenharmony_ci void *p = (void *)IFIRST(header) + offset; 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci if (unlikely(p + size > end)) 67762306a36Sopenharmony_ci goto cleanup; 67862306a36Sopenharmony_ci memcpy(buffer, p, size); 67962306a36Sopenharmony_ci } 68062306a36Sopenharmony_ci } 68162306a36Sopenharmony_ci error = size; 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_cicleanup: 68462306a36Sopenharmony_ci brelse(iloc.bh); 68562306a36Sopenharmony_ci return error; 68662306a36Sopenharmony_ci} 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci/* 68962306a36Sopenharmony_ci * ext4_xattr_get() 69062306a36Sopenharmony_ci * 69162306a36Sopenharmony_ci * Copy an extended attribute into the buffer 69262306a36Sopenharmony_ci * provided, or compute the buffer size required. 69362306a36Sopenharmony_ci * Buffer is NULL to compute the size of the buffer required. 69462306a36Sopenharmony_ci * 69562306a36Sopenharmony_ci * Returns a negative error number on failure, or the number of bytes 69662306a36Sopenharmony_ci * used / required on success. 69762306a36Sopenharmony_ci */ 69862306a36Sopenharmony_ciint 69962306a36Sopenharmony_ciext4_xattr_get(struct inode *inode, int name_index, const char *name, 70062306a36Sopenharmony_ci void *buffer, size_t buffer_size) 70162306a36Sopenharmony_ci{ 70262306a36Sopenharmony_ci int error; 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci if (unlikely(ext4_forced_shutdown(inode->i_sb))) 70562306a36Sopenharmony_ci return -EIO; 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci if (strlen(name) > 255) 70862306a36Sopenharmony_ci return -ERANGE; 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci down_read(&EXT4_I(inode)->xattr_sem); 71162306a36Sopenharmony_ci error = ext4_xattr_ibody_get(inode, name_index, name, buffer, 71262306a36Sopenharmony_ci buffer_size); 71362306a36Sopenharmony_ci if (error == -ENODATA) 71462306a36Sopenharmony_ci error = ext4_xattr_block_get(inode, name_index, name, buffer, 71562306a36Sopenharmony_ci buffer_size); 71662306a36Sopenharmony_ci up_read(&EXT4_I(inode)->xattr_sem); 71762306a36Sopenharmony_ci return error; 71862306a36Sopenharmony_ci} 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_cistatic int 72162306a36Sopenharmony_ciext4_xattr_list_entries(struct dentry *dentry, struct ext4_xattr_entry *entry, 72262306a36Sopenharmony_ci char *buffer, size_t buffer_size) 72362306a36Sopenharmony_ci{ 72462306a36Sopenharmony_ci size_t rest = buffer_size; 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci for (; !IS_LAST_ENTRY(entry); entry = EXT4_XATTR_NEXT(entry)) { 72762306a36Sopenharmony_ci const char *prefix; 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci prefix = ext4_xattr_prefix(entry->e_name_index, dentry); 73062306a36Sopenharmony_ci if (prefix) { 73162306a36Sopenharmony_ci size_t prefix_len = strlen(prefix); 73262306a36Sopenharmony_ci size_t size = prefix_len + entry->e_name_len + 1; 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci if (buffer) { 73562306a36Sopenharmony_ci if (size > rest) 73662306a36Sopenharmony_ci return -ERANGE; 73762306a36Sopenharmony_ci memcpy(buffer, prefix, prefix_len); 73862306a36Sopenharmony_ci buffer += prefix_len; 73962306a36Sopenharmony_ci memcpy(buffer, entry->e_name, entry->e_name_len); 74062306a36Sopenharmony_ci buffer += entry->e_name_len; 74162306a36Sopenharmony_ci *buffer++ = 0; 74262306a36Sopenharmony_ci } 74362306a36Sopenharmony_ci rest -= size; 74462306a36Sopenharmony_ci } 74562306a36Sopenharmony_ci } 74662306a36Sopenharmony_ci return buffer_size - rest; /* total size */ 74762306a36Sopenharmony_ci} 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_cistatic int 75062306a36Sopenharmony_ciext4_xattr_block_list(struct dentry *dentry, char *buffer, size_t buffer_size) 75162306a36Sopenharmony_ci{ 75262306a36Sopenharmony_ci struct inode *inode = d_inode(dentry); 75362306a36Sopenharmony_ci struct buffer_head *bh = NULL; 75462306a36Sopenharmony_ci int error; 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci ea_idebug(inode, "buffer=%p, buffer_size=%ld", 75762306a36Sopenharmony_ci buffer, (long)buffer_size); 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci if (!EXT4_I(inode)->i_file_acl) 76062306a36Sopenharmony_ci return 0; 76162306a36Sopenharmony_ci ea_idebug(inode, "reading block %llu", 76262306a36Sopenharmony_ci (unsigned long long)EXT4_I(inode)->i_file_acl); 76362306a36Sopenharmony_ci bh = ext4_sb_bread(inode->i_sb, EXT4_I(inode)->i_file_acl, REQ_PRIO); 76462306a36Sopenharmony_ci if (IS_ERR(bh)) 76562306a36Sopenharmony_ci return PTR_ERR(bh); 76662306a36Sopenharmony_ci ea_bdebug(bh, "b_count=%d, refcount=%d", 76762306a36Sopenharmony_ci atomic_read(&(bh->b_count)), le32_to_cpu(BHDR(bh)->h_refcount)); 76862306a36Sopenharmony_ci error = ext4_xattr_check_block(inode, bh); 76962306a36Sopenharmony_ci if (error) 77062306a36Sopenharmony_ci goto cleanup; 77162306a36Sopenharmony_ci ext4_xattr_block_cache_insert(EA_BLOCK_CACHE(inode), bh); 77262306a36Sopenharmony_ci error = ext4_xattr_list_entries(dentry, BFIRST(bh), buffer, 77362306a36Sopenharmony_ci buffer_size); 77462306a36Sopenharmony_cicleanup: 77562306a36Sopenharmony_ci brelse(bh); 77662306a36Sopenharmony_ci return error; 77762306a36Sopenharmony_ci} 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_cistatic int 78062306a36Sopenharmony_ciext4_xattr_ibody_list(struct dentry *dentry, char *buffer, size_t buffer_size) 78162306a36Sopenharmony_ci{ 78262306a36Sopenharmony_ci struct inode *inode = d_inode(dentry); 78362306a36Sopenharmony_ci struct ext4_xattr_ibody_header *header; 78462306a36Sopenharmony_ci struct ext4_inode *raw_inode; 78562306a36Sopenharmony_ci struct ext4_iloc iloc; 78662306a36Sopenharmony_ci void *end; 78762306a36Sopenharmony_ci int error; 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci if (!ext4_test_inode_state(inode, EXT4_STATE_XATTR)) 79062306a36Sopenharmony_ci return 0; 79162306a36Sopenharmony_ci error = ext4_get_inode_loc(inode, &iloc); 79262306a36Sopenharmony_ci if (error) 79362306a36Sopenharmony_ci return error; 79462306a36Sopenharmony_ci raw_inode = ext4_raw_inode(&iloc); 79562306a36Sopenharmony_ci header = IHDR(inode, raw_inode); 79662306a36Sopenharmony_ci end = (void *)raw_inode + EXT4_SB(inode->i_sb)->s_inode_size; 79762306a36Sopenharmony_ci error = xattr_check_inode(inode, header, end); 79862306a36Sopenharmony_ci if (error) 79962306a36Sopenharmony_ci goto cleanup; 80062306a36Sopenharmony_ci error = ext4_xattr_list_entries(dentry, IFIRST(header), 80162306a36Sopenharmony_ci buffer, buffer_size); 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_cicleanup: 80462306a36Sopenharmony_ci brelse(iloc.bh); 80562306a36Sopenharmony_ci return error; 80662306a36Sopenharmony_ci} 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci/* 80962306a36Sopenharmony_ci * Inode operation listxattr() 81062306a36Sopenharmony_ci * 81162306a36Sopenharmony_ci * d_inode(dentry)->i_rwsem: don't care 81262306a36Sopenharmony_ci * 81362306a36Sopenharmony_ci * Copy a list of attribute names into the buffer 81462306a36Sopenharmony_ci * provided, or compute the buffer size required. 81562306a36Sopenharmony_ci * Buffer is NULL to compute the size of the buffer required. 81662306a36Sopenharmony_ci * 81762306a36Sopenharmony_ci * Returns a negative error number on failure, or the number of bytes 81862306a36Sopenharmony_ci * used / required on success. 81962306a36Sopenharmony_ci */ 82062306a36Sopenharmony_cissize_t 82162306a36Sopenharmony_ciext4_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size) 82262306a36Sopenharmony_ci{ 82362306a36Sopenharmony_ci int ret, ret2; 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci down_read(&EXT4_I(d_inode(dentry))->xattr_sem); 82662306a36Sopenharmony_ci ret = ret2 = ext4_xattr_ibody_list(dentry, buffer, buffer_size); 82762306a36Sopenharmony_ci if (ret < 0) 82862306a36Sopenharmony_ci goto errout; 82962306a36Sopenharmony_ci if (buffer) { 83062306a36Sopenharmony_ci buffer += ret; 83162306a36Sopenharmony_ci buffer_size -= ret; 83262306a36Sopenharmony_ci } 83362306a36Sopenharmony_ci ret = ext4_xattr_block_list(dentry, buffer, buffer_size); 83462306a36Sopenharmony_ci if (ret < 0) 83562306a36Sopenharmony_ci goto errout; 83662306a36Sopenharmony_ci ret += ret2; 83762306a36Sopenharmony_cierrout: 83862306a36Sopenharmony_ci up_read(&EXT4_I(d_inode(dentry))->xattr_sem); 83962306a36Sopenharmony_ci return ret; 84062306a36Sopenharmony_ci} 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci/* 84362306a36Sopenharmony_ci * If the EXT4_FEATURE_COMPAT_EXT_ATTR feature of this file system is 84462306a36Sopenharmony_ci * not set, set it. 84562306a36Sopenharmony_ci */ 84662306a36Sopenharmony_cistatic void ext4_xattr_update_super_block(handle_t *handle, 84762306a36Sopenharmony_ci struct super_block *sb) 84862306a36Sopenharmony_ci{ 84962306a36Sopenharmony_ci if (ext4_has_feature_xattr(sb)) 85062306a36Sopenharmony_ci return; 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_ci BUFFER_TRACE(EXT4_SB(sb)->s_sbh, "get_write_access"); 85362306a36Sopenharmony_ci if (ext4_journal_get_write_access(handle, sb, EXT4_SB(sb)->s_sbh, 85462306a36Sopenharmony_ci EXT4_JTR_NONE) == 0) { 85562306a36Sopenharmony_ci lock_buffer(EXT4_SB(sb)->s_sbh); 85662306a36Sopenharmony_ci ext4_set_feature_xattr(sb); 85762306a36Sopenharmony_ci ext4_superblock_csum_set(sb); 85862306a36Sopenharmony_ci unlock_buffer(EXT4_SB(sb)->s_sbh); 85962306a36Sopenharmony_ci ext4_handle_dirty_metadata(handle, NULL, EXT4_SB(sb)->s_sbh); 86062306a36Sopenharmony_ci } 86162306a36Sopenharmony_ci} 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ciint ext4_get_inode_usage(struct inode *inode, qsize_t *usage) 86462306a36Sopenharmony_ci{ 86562306a36Sopenharmony_ci struct ext4_iloc iloc = { .bh = NULL }; 86662306a36Sopenharmony_ci struct buffer_head *bh = NULL; 86762306a36Sopenharmony_ci struct ext4_inode *raw_inode; 86862306a36Sopenharmony_ci struct ext4_xattr_ibody_header *header; 86962306a36Sopenharmony_ci struct ext4_xattr_entry *entry; 87062306a36Sopenharmony_ci qsize_t ea_inode_refs = 0; 87162306a36Sopenharmony_ci void *end; 87262306a36Sopenharmony_ci int ret; 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci lockdep_assert_held_read(&EXT4_I(inode)->xattr_sem); 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci if (ext4_test_inode_state(inode, EXT4_STATE_XATTR)) { 87762306a36Sopenharmony_ci ret = ext4_get_inode_loc(inode, &iloc); 87862306a36Sopenharmony_ci if (ret) 87962306a36Sopenharmony_ci goto out; 88062306a36Sopenharmony_ci raw_inode = ext4_raw_inode(&iloc); 88162306a36Sopenharmony_ci header = IHDR(inode, raw_inode); 88262306a36Sopenharmony_ci end = (void *)raw_inode + EXT4_SB(inode->i_sb)->s_inode_size; 88362306a36Sopenharmony_ci ret = xattr_check_inode(inode, header, end); 88462306a36Sopenharmony_ci if (ret) 88562306a36Sopenharmony_ci goto out; 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci for (entry = IFIRST(header); !IS_LAST_ENTRY(entry); 88862306a36Sopenharmony_ci entry = EXT4_XATTR_NEXT(entry)) 88962306a36Sopenharmony_ci if (entry->e_value_inum) 89062306a36Sopenharmony_ci ea_inode_refs++; 89162306a36Sopenharmony_ci } 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci if (EXT4_I(inode)->i_file_acl) { 89462306a36Sopenharmony_ci bh = ext4_sb_bread(inode->i_sb, EXT4_I(inode)->i_file_acl, REQ_PRIO); 89562306a36Sopenharmony_ci if (IS_ERR(bh)) { 89662306a36Sopenharmony_ci ret = PTR_ERR(bh); 89762306a36Sopenharmony_ci bh = NULL; 89862306a36Sopenharmony_ci goto out; 89962306a36Sopenharmony_ci } 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci ret = ext4_xattr_check_block(inode, bh); 90262306a36Sopenharmony_ci if (ret) 90362306a36Sopenharmony_ci goto out; 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci for (entry = BFIRST(bh); !IS_LAST_ENTRY(entry); 90662306a36Sopenharmony_ci entry = EXT4_XATTR_NEXT(entry)) 90762306a36Sopenharmony_ci if (entry->e_value_inum) 90862306a36Sopenharmony_ci ea_inode_refs++; 90962306a36Sopenharmony_ci } 91062306a36Sopenharmony_ci *usage = ea_inode_refs + 1; 91162306a36Sopenharmony_ci ret = 0; 91262306a36Sopenharmony_ciout: 91362306a36Sopenharmony_ci brelse(iloc.bh); 91462306a36Sopenharmony_ci brelse(bh); 91562306a36Sopenharmony_ci return ret; 91662306a36Sopenharmony_ci} 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_cistatic inline size_t round_up_cluster(struct inode *inode, size_t length) 91962306a36Sopenharmony_ci{ 92062306a36Sopenharmony_ci struct super_block *sb = inode->i_sb; 92162306a36Sopenharmony_ci size_t cluster_size = 1 << (EXT4_SB(sb)->s_cluster_bits + 92262306a36Sopenharmony_ci inode->i_blkbits); 92362306a36Sopenharmony_ci size_t mask = ~(cluster_size - 1); 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ci return (length + cluster_size - 1) & mask; 92662306a36Sopenharmony_ci} 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_cistatic int ext4_xattr_inode_alloc_quota(struct inode *inode, size_t len) 92962306a36Sopenharmony_ci{ 93062306a36Sopenharmony_ci int err; 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ci err = dquot_alloc_inode(inode); 93362306a36Sopenharmony_ci if (err) 93462306a36Sopenharmony_ci return err; 93562306a36Sopenharmony_ci err = dquot_alloc_space_nodirty(inode, round_up_cluster(inode, len)); 93662306a36Sopenharmony_ci if (err) 93762306a36Sopenharmony_ci dquot_free_inode(inode); 93862306a36Sopenharmony_ci return err; 93962306a36Sopenharmony_ci} 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_cistatic void ext4_xattr_inode_free_quota(struct inode *parent, 94262306a36Sopenharmony_ci struct inode *ea_inode, 94362306a36Sopenharmony_ci size_t len) 94462306a36Sopenharmony_ci{ 94562306a36Sopenharmony_ci if (ea_inode && 94662306a36Sopenharmony_ci ext4_test_inode_state(ea_inode, EXT4_STATE_LUSTRE_EA_INODE)) 94762306a36Sopenharmony_ci return; 94862306a36Sopenharmony_ci dquot_free_space_nodirty(parent, round_up_cluster(parent, len)); 94962306a36Sopenharmony_ci dquot_free_inode(parent); 95062306a36Sopenharmony_ci} 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_ciint __ext4_xattr_set_credits(struct super_block *sb, struct inode *inode, 95362306a36Sopenharmony_ci struct buffer_head *block_bh, size_t value_len, 95462306a36Sopenharmony_ci bool is_create) 95562306a36Sopenharmony_ci{ 95662306a36Sopenharmony_ci int credits; 95762306a36Sopenharmony_ci int blocks; 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci /* 96062306a36Sopenharmony_ci * 1) Owner inode update 96162306a36Sopenharmony_ci * 2) Ref count update on old xattr block 96262306a36Sopenharmony_ci * 3) new xattr block 96362306a36Sopenharmony_ci * 4) block bitmap update for new xattr block 96462306a36Sopenharmony_ci * 5) group descriptor for new xattr block 96562306a36Sopenharmony_ci * 6) block bitmap update for old xattr block 96662306a36Sopenharmony_ci * 7) group descriptor for old block 96762306a36Sopenharmony_ci * 96862306a36Sopenharmony_ci * 6 & 7 can happen if we have two racing threads T_a and T_b 96962306a36Sopenharmony_ci * which are each trying to set an xattr on inodes I_a and I_b 97062306a36Sopenharmony_ci * which were both initially sharing an xattr block. 97162306a36Sopenharmony_ci */ 97262306a36Sopenharmony_ci credits = 7; 97362306a36Sopenharmony_ci 97462306a36Sopenharmony_ci /* Quota updates. */ 97562306a36Sopenharmony_ci credits += EXT4_MAXQUOTAS_TRANS_BLOCKS(sb); 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci /* 97862306a36Sopenharmony_ci * In case of inline data, we may push out the data to a block, 97962306a36Sopenharmony_ci * so we need to reserve credits for this eventuality 98062306a36Sopenharmony_ci */ 98162306a36Sopenharmony_ci if (inode && ext4_has_inline_data(inode)) 98262306a36Sopenharmony_ci credits += ext4_writepage_trans_blocks(inode) + 1; 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci /* We are done if ea_inode feature is not enabled. */ 98562306a36Sopenharmony_ci if (!ext4_has_feature_ea_inode(sb)) 98662306a36Sopenharmony_ci return credits; 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci /* New ea_inode, inode map, block bitmap, group descriptor. */ 98962306a36Sopenharmony_ci credits += 4; 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_ci /* Data blocks. */ 99262306a36Sopenharmony_ci blocks = (value_len + sb->s_blocksize - 1) >> sb->s_blocksize_bits; 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_ci /* Indirection block or one level of extent tree. */ 99562306a36Sopenharmony_ci blocks += 1; 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_ci /* Block bitmap and group descriptor updates for each block. */ 99862306a36Sopenharmony_ci credits += blocks * 2; 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci /* Blocks themselves. */ 100162306a36Sopenharmony_ci credits += blocks; 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_ci if (!is_create) { 100462306a36Sopenharmony_ci /* Dereference ea_inode holding old xattr value. 100562306a36Sopenharmony_ci * Old ea_inode, inode map, block bitmap, group descriptor. 100662306a36Sopenharmony_ci */ 100762306a36Sopenharmony_ci credits += 4; 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_ci /* Data blocks for old ea_inode. */ 101062306a36Sopenharmony_ci blocks = XATTR_SIZE_MAX >> sb->s_blocksize_bits; 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ci /* Indirection block or one level of extent tree for old 101362306a36Sopenharmony_ci * ea_inode. 101462306a36Sopenharmony_ci */ 101562306a36Sopenharmony_ci blocks += 1; 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_ci /* Block bitmap and group descriptor updates for each block. */ 101862306a36Sopenharmony_ci credits += blocks * 2; 101962306a36Sopenharmony_ci } 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_ci /* We may need to clone the existing xattr block in which case we need 102262306a36Sopenharmony_ci * to increment ref counts for existing ea_inodes referenced by it. 102362306a36Sopenharmony_ci */ 102462306a36Sopenharmony_ci if (block_bh) { 102562306a36Sopenharmony_ci struct ext4_xattr_entry *entry = BFIRST(block_bh); 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci for (; !IS_LAST_ENTRY(entry); entry = EXT4_XATTR_NEXT(entry)) 102862306a36Sopenharmony_ci if (entry->e_value_inum) 102962306a36Sopenharmony_ci /* Ref count update on ea_inode. */ 103062306a36Sopenharmony_ci credits += 1; 103162306a36Sopenharmony_ci } 103262306a36Sopenharmony_ci return credits; 103362306a36Sopenharmony_ci} 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_cistatic int ext4_xattr_inode_update_ref(handle_t *handle, struct inode *ea_inode, 103662306a36Sopenharmony_ci int ref_change) 103762306a36Sopenharmony_ci{ 103862306a36Sopenharmony_ci struct ext4_iloc iloc; 103962306a36Sopenharmony_ci s64 ref_count; 104062306a36Sopenharmony_ci int ret; 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_ci inode_lock(ea_inode); 104362306a36Sopenharmony_ci 104462306a36Sopenharmony_ci ret = ext4_reserve_inode_write(handle, ea_inode, &iloc); 104562306a36Sopenharmony_ci if (ret) 104662306a36Sopenharmony_ci goto out; 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_ci ref_count = ext4_xattr_inode_get_ref(ea_inode); 104962306a36Sopenharmony_ci ref_count += ref_change; 105062306a36Sopenharmony_ci ext4_xattr_inode_set_ref(ea_inode, ref_count); 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_ci if (ref_change > 0) { 105362306a36Sopenharmony_ci WARN_ONCE(ref_count <= 0, "EA inode %lu ref_count=%lld", 105462306a36Sopenharmony_ci ea_inode->i_ino, ref_count); 105562306a36Sopenharmony_ci 105662306a36Sopenharmony_ci if (ref_count == 1) { 105762306a36Sopenharmony_ci WARN_ONCE(ea_inode->i_nlink, "EA inode %lu i_nlink=%u", 105862306a36Sopenharmony_ci ea_inode->i_ino, ea_inode->i_nlink); 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_ci set_nlink(ea_inode, 1); 106162306a36Sopenharmony_ci ext4_orphan_del(handle, ea_inode); 106262306a36Sopenharmony_ci } 106362306a36Sopenharmony_ci } else { 106462306a36Sopenharmony_ci WARN_ONCE(ref_count < 0, "EA inode %lu ref_count=%lld", 106562306a36Sopenharmony_ci ea_inode->i_ino, ref_count); 106662306a36Sopenharmony_ci 106762306a36Sopenharmony_ci if (ref_count == 0) { 106862306a36Sopenharmony_ci WARN_ONCE(ea_inode->i_nlink != 1, 106962306a36Sopenharmony_ci "EA inode %lu i_nlink=%u", 107062306a36Sopenharmony_ci ea_inode->i_ino, ea_inode->i_nlink); 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_ci clear_nlink(ea_inode); 107362306a36Sopenharmony_ci ext4_orphan_add(handle, ea_inode); 107462306a36Sopenharmony_ci } 107562306a36Sopenharmony_ci } 107662306a36Sopenharmony_ci 107762306a36Sopenharmony_ci ret = ext4_mark_iloc_dirty(handle, ea_inode, &iloc); 107862306a36Sopenharmony_ci if (ret) 107962306a36Sopenharmony_ci ext4_warning_inode(ea_inode, 108062306a36Sopenharmony_ci "ext4_mark_iloc_dirty() failed ret=%d", ret); 108162306a36Sopenharmony_ciout: 108262306a36Sopenharmony_ci inode_unlock(ea_inode); 108362306a36Sopenharmony_ci return ret; 108462306a36Sopenharmony_ci} 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_cistatic int ext4_xattr_inode_inc_ref(handle_t *handle, struct inode *ea_inode) 108762306a36Sopenharmony_ci{ 108862306a36Sopenharmony_ci return ext4_xattr_inode_update_ref(handle, ea_inode, 1); 108962306a36Sopenharmony_ci} 109062306a36Sopenharmony_ci 109162306a36Sopenharmony_cistatic int ext4_xattr_inode_dec_ref(handle_t *handle, struct inode *ea_inode) 109262306a36Sopenharmony_ci{ 109362306a36Sopenharmony_ci return ext4_xattr_inode_update_ref(handle, ea_inode, -1); 109462306a36Sopenharmony_ci} 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_cistatic int ext4_xattr_inode_inc_ref_all(handle_t *handle, struct inode *parent, 109762306a36Sopenharmony_ci struct ext4_xattr_entry *first) 109862306a36Sopenharmony_ci{ 109962306a36Sopenharmony_ci struct inode *ea_inode; 110062306a36Sopenharmony_ci struct ext4_xattr_entry *entry; 110162306a36Sopenharmony_ci struct ext4_xattr_entry *failed_entry; 110262306a36Sopenharmony_ci unsigned int ea_ino; 110362306a36Sopenharmony_ci int err, saved_err; 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_ci for (entry = first; !IS_LAST_ENTRY(entry); 110662306a36Sopenharmony_ci entry = EXT4_XATTR_NEXT(entry)) { 110762306a36Sopenharmony_ci if (!entry->e_value_inum) 110862306a36Sopenharmony_ci continue; 110962306a36Sopenharmony_ci ea_ino = le32_to_cpu(entry->e_value_inum); 111062306a36Sopenharmony_ci err = ext4_xattr_inode_iget(parent, ea_ino, 111162306a36Sopenharmony_ci le32_to_cpu(entry->e_hash), 111262306a36Sopenharmony_ci &ea_inode); 111362306a36Sopenharmony_ci if (err) 111462306a36Sopenharmony_ci goto cleanup; 111562306a36Sopenharmony_ci err = ext4_xattr_inode_inc_ref(handle, ea_inode); 111662306a36Sopenharmony_ci if (err) { 111762306a36Sopenharmony_ci ext4_warning_inode(ea_inode, "inc ref error %d", err); 111862306a36Sopenharmony_ci iput(ea_inode); 111962306a36Sopenharmony_ci goto cleanup; 112062306a36Sopenharmony_ci } 112162306a36Sopenharmony_ci iput(ea_inode); 112262306a36Sopenharmony_ci } 112362306a36Sopenharmony_ci return 0; 112462306a36Sopenharmony_ci 112562306a36Sopenharmony_cicleanup: 112662306a36Sopenharmony_ci saved_err = err; 112762306a36Sopenharmony_ci failed_entry = entry; 112862306a36Sopenharmony_ci 112962306a36Sopenharmony_ci for (entry = first; entry != failed_entry; 113062306a36Sopenharmony_ci entry = EXT4_XATTR_NEXT(entry)) { 113162306a36Sopenharmony_ci if (!entry->e_value_inum) 113262306a36Sopenharmony_ci continue; 113362306a36Sopenharmony_ci ea_ino = le32_to_cpu(entry->e_value_inum); 113462306a36Sopenharmony_ci err = ext4_xattr_inode_iget(parent, ea_ino, 113562306a36Sopenharmony_ci le32_to_cpu(entry->e_hash), 113662306a36Sopenharmony_ci &ea_inode); 113762306a36Sopenharmony_ci if (err) { 113862306a36Sopenharmony_ci ext4_warning(parent->i_sb, 113962306a36Sopenharmony_ci "cleanup ea_ino %u iget error %d", ea_ino, 114062306a36Sopenharmony_ci err); 114162306a36Sopenharmony_ci continue; 114262306a36Sopenharmony_ci } 114362306a36Sopenharmony_ci err = ext4_xattr_inode_dec_ref(handle, ea_inode); 114462306a36Sopenharmony_ci if (err) 114562306a36Sopenharmony_ci ext4_warning_inode(ea_inode, "cleanup dec ref error %d", 114662306a36Sopenharmony_ci err); 114762306a36Sopenharmony_ci iput(ea_inode); 114862306a36Sopenharmony_ci } 114962306a36Sopenharmony_ci return saved_err; 115062306a36Sopenharmony_ci} 115162306a36Sopenharmony_ci 115262306a36Sopenharmony_cistatic int ext4_xattr_restart_fn(handle_t *handle, struct inode *inode, 115362306a36Sopenharmony_ci struct buffer_head *bh, bool block_csum, bool dirty) 115462306a36Sopenharmony_ci{ 115562306a36Sopenharmony_ci int error; 115662306a36Sopenharmony_ci 115762306a36Sopenharmony_ci if (bh && dirty) { 115862306a36Sopenharmony_ci if (block_csum) 115962306a36Sopenharmony_ci ext4_xattr_block_csum_set(inode, bh); 116062306a36Sopenharmony_ci error = ext4_handle_dirty_metadata(handle, NULL, bh); 116162306a36Sopenharmony_ci if (error) { 116262306a36Sopenharmony_ci ext4_warning(inode->i_sb, "Handle metadata (error %d)", 116362306a36Sopenharmony_ci error); 116462306a36Sopenharmony_ci return error; 116562306a36Sopenharmony_ci } 116662306a36Sopenharmony_ci } 116762306a36Sopenharmony_ci return 0; 116862306a36Sopenharmony_ci} 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_cistatic void 117162306a36Sopenharmony_ciext4_xattr_inode_dec_ref_all(handle_t *handle, struct inode *parent, 117262306a36Sopenharmony_ci struct buffer_head *bh, 117362306a36Sopenharmony_ci struct ext4_xattr_entry *first, bool block_csum, 117462306a36Sopenharmony_ci struct ext4_xattr_inode_array **ea_inode_array, 117562306a36Sopenharmony_ci int extra_credits, bool skip_quota) 117662306a36Sopenharmony_ci{ 117762306a36Sopenharmony_ci struct inode *ea_inode; 117862306a36Sopenharmony_ci struct ext4_xattr_entry *entry; 117962306a36Sopenharmony_ci bool dirty = false; 118062306a36Sopenharmony_ci unsigned int ea_ino; 118162306a36Sopenharmony_ci int err; 118262306a36Sopenharmony_ci int credits; 118362306a36Sopenharmony_ci 118462306a36Sopenharmony_ci /* One credit for dec ref on ea_inode, one for orphan list addition, */ 118562306a36Sopenharmony_ci credits = 2 + extra_credits; 118662306a36Sopenharmony_ci 118762306a36Sopenharmony_ci for (entry = first; !IS_LAST_ENTRY(entry); 118862306a36Sopenharmony_ci entry = EXT4_XATTR_NEXT(entry)) { 118962306a36Sopenharmony_ci if (!entry->e_value_inum) 119062306a36Sopenharmony_ci continue; 119162306a36Sopenharmony_ci ea_ino = le32_to_cpu(entry->e_value_inum); 119262306a36Sopenharmony_ci err = ext4_xattr_inode_iget(parent, ea_ino, 119362306a36Sopenharmony_ci le32_to_cpu(entry->e_hash), 119462306a36Sopenharmony_ci &ea_inode); 119562306a36Sopenharmony_ci if (err) 119662306a36Sopenharmony_ci continue; 119762306a36Sopenharmony_ci 119862306a36Sopenharmony_ci err = ext4_expand_inode_array(ea_inode_array, ea_inode); 119962306a36Sopenharmony_ci if (err) { 120062306a36Sopenharmony_ci ext4_warning_inode(ea_inode, 120162306a36Sopenharmony_ci "Expand inode array err=%d", err); 120262306a36Sopenharmony_ci iput(ea_inode); 120362306a36Sopenharmony_ci continue; 120462306a36Sopenharmony_ci } 120562306a36Sopenharmony_ci 120662306a36Sopenharmony_ci err = ext4_journal_ensure_credits_fn(handle, credits, credits, 120762306a36Sopenharmony_ci ext4_free_metadata_revoke_credits(parent->i_sb, 1), 120862306a36Sopenharmony_ci ext4_xattr_restart_fn(handle, parent, bh, block_csum, 120962306a36Sopenharmony_ci dirty)); 121062306a36Sopenharmony_ci if (err < 0) { 121162306a36Sopenharmony_ci ext4_warning_inode(ea_inode, "Ensure credits err=%d", 121262306a36Sopenharmony_ci err); 121362306a36Sopenharmony_ci continue; 121462306a36Sopenharmony_ci } 121562306a36Sopenharmony_ci if (err > 0) { 121662306a36Sopenharmony_ci err = ext4_journal_get_write_access(handle, 121762306a36Sopenharmony_ci parent->i_sb, bh, EXT4_JTR_NONE); 121862306a36Sopenharmony_ci if (err) { 121962306a36Sopenharmony_ci ext4_warning_inode(ea_inode, 122062306a36Sopenharmony_ci "Re-get write access err=%d", 122162306a36Sopenharmony_ci err); 122262306a36Sopenharmony_ci continue; 122362306a36Sopenharmony_ci } 122462306a36Sopenharmony_ci } 122562306a36Sopenharmony_ci 122662306a36Sopenharmony_ci err = ext4_xattr_inode_dec_ref(handle, ea_inode); 122762306a36Sopenharmony_ci if (err) { 122862306a36Sopenharmony_ci ext4_warning_inode(ea_inode, "ea_inode dec ref err=%d", 122962306a36Sopenharmony_ci err); 123062306a36Sopenharmony_ci continue; 123162306a36Sopenharmony_ci } 123262306a36Sopenharmony_ci 123362306a36Sopenharmony_ci if (!skip_quota) 123462306a36Sopenharmony_ci ext4_xattr_inode_free_quota(parent, ea_inode, 123562306a36Sopenharmony_ci le32_to_cpu(entry->e_value_size)); 123662306a36Sopenharmony_ci 123762306a36Sopenharmony_ci /* 123862306a36Sopenharmony_ci * Forget about ea_inode within the same transaction that 123962306a36Sopenharmony_ci * decrements the ref count. This avoids duplicate decrements in 124062306a36Sopenharmony_ci * case the rest of the work spills over to subsequent 124162306a36Sopenharmony_ci * transactions. 124262306a36Sopenharmony_ci */ 124362306a36Sopenharmony_ci entry->e_value_inum = 0; 124462306a36Sopenharmony_ci entry->e_value_size = 0; 124562306a36Sopenharmony_ci 124662306a36Sopenharmony_ci dirty = true; 124762306a36Sopenharmony_ci } 124862306a36Sopenharmony_ci 124962306a36Sopenharmony_ci if (dirty) { 125062306a36Sopenharmony_ci /* 125162306a36Sopenharmony_ci * Note that we are deliberately skipping csum calculation for 125262306a36Sopenharmony_ci * the final update because we do not expect any journal 125362306a36Sopenharmony_ci * restarts until xattr block is freed. 125462306a36Sopenharmony_ci */ 125562306a36Sopenharmony_ci 125662306a36Sopenharmony_ci err = ext4_handle_dirty_metadata(handle, NULL, bh); 125762306a36Sopenharmony_ci if (err) 125862306a36Sopenharmony_ci ext4_warning_inode(parent, 125962306a36Sopenharmony_ci "handle dirty metadata err=%d", err); 126062306a36Sopenharmony_ci } 126162306a36Sopenharmony_ci} 126262306a36Sopenharmony_ci 126362306a36Sopenharmony_ci/* 126462306a36Sopenharmony_ci * Release the xattr block BH: If the reference count is > 1, decrement it; 126562306a36Sopenharmony_ci * otherwise free the block. 126662306a36Sopenharmony_ci */ 126762306a36Sopenharmony_cistatic void 126862306a36Sopenharmony_ciext4_xattr_release_block(handle_t *handle, struct inode *inode, 126962306a36Sopenharmony_ci struct buffer_head *bh, 127062306a36Sopenharmony_ci struct ext4_xattr_inode_array **ea_inode_array, 127162306a36Sopenharmony_ci int extra_credits) 127262306a36Sopenharmony_ci{ 127362306a36Sopenharmony_ci struct mb_cache *ea_block_cache = EA_BLOCK_CACHE(inode); 127462306a36Sopenharmony_ci u32 hash, ref; 127562306a36Sopenharmony_ci int error = 0; 127662306a36Sopenharmony_ci 127762306a36Sopenharmony_ci BUFFER_TRACE(bh, "get_write_access"); 127862306a36Sopenharmony_ci error = ext4_journal_get_write_access(handle, inode->i_sb, bh, 127962306a36Sopenharmony_ci EXT4_JTR_NONE); 128062306a36Sopenharmony_ci if (error) 128162306a36Sopenharmony_ci goto out; 128262306a36Sopenharmony_ci 128362306a36Sopenharmony_ciretry_ref: 128462306a36Sopenharmony_ci lock_buffer(bh); 128562306a36Sopenharmony_ci hash = le32_to_cpu(BHDR(bh)->h_hash); 128662306a36Sopenharmony_ci ref = le32_to_cpu(BHDR(bh)->h_refcount); 128762306a36Sopenharmony_ci if (ref == 1) { 128862306a36Sopenharmony_ci ea_bdebug(bh, "refcount now=0; freeing"); 128962306a36Sopenharmony_ci /* 129062306a36Sopenharmony_ci * This must happen under buffer lock for 129162306a36Sopenharmony_ci * ext4_xattr_block_set() to reliably detect freed block 129262306a36Sopenharmony_ci */ 129362306a36Sopenharmony_ci if (ea_block_cache) { 129462306a36Sopenharmony_ci struct mb_cache_entry *oe; 129562306a36Sopenharmony_ci 129662306a36Sopenharmony_ci oe = mb_cache_entry_delete_or_get(ea_block_cache, hash, 129762306a36Sopenharmony_ci bh->b_blocknr); 129862306a36Sopenharmony_ci if (oe) { 129962306a36Sopenharmony_ci unlock_buffer(bh); 130062306a36Sopenharmony_ci mb_cache_entry_wait_unused(oe); 130162306a36Sopenharmony_ci mb_cache_entry_put(ea_block_cache, oe); 130262306a36Sopenharmony_ci goto retry_ref; 130362306a36Sopenharmony_ci } 130462306a36Sopenharmony_ci } 130562306a36Sopenharmony_ci get_bh(bh); 130662306a36Sopenharmony_ci unlock_buffer(bh); 130762306a36Sopenharmony_ci 130862306a36Sopenharmony_ci if (ext4_has_feature_ea_inode(inode->i_sb)) 130962306a36Sopenharmony_ci ext4_xattr_inode_dec_ref_all(handle, inode, bh, 131062306a36Sopenharmony_ci BFIRST(bh), 131162306a36Sopenharmony_ci true /* block_csum */, 131262306a36Sopenharmony_ci ea_inode_array, 131362306a36Sopenharmony_ci extra_credits, 131462306a36Sopenharmony_ci true /* skip_quota */); 131562306a36Sopenharmony_ci ext4_free_blocks(handle, inode, bh, 0, 1, 131662306a36Sopenharmony_ci EXT4_FREE_BLOCKS_METADATA | 131762306a36Sopenharmony_ci EXT4_FREE_BLOCKS_FORGET); 131862306a36Sopenharmony_ci } else { 131962306a36Sopenharmony_ci ref--; 132062306a36Sopenharmony_ci BHDR(bh)->h_refcount = cpu_to_le32(ref); 132162306a36Sopenharmony_ci if (ref == EXT4_XATTR_REFCOUNT_MAX - 1) { 132262306a36Sopenharmony_ci struct mb_cache_entry *ce; 132362306a36Sopenharmony_ci 132462306a36Sopenharmony_ci if (ea_block_cache) { 132562306a36Sopenharmony_ci ce = mb_cache_entry_get(ea_block_cache, hash, 132662306a36Sopenharmony_ci bh->b_blocknr); 132762306a36Sopenharmony_ci if (ce) { 132862306a36Sopenharmony_ci set_bit(MBE_REUSABLE_B, &ce->e_flags); 132962306a36Sopenharmony_ci mb_cache_entry_put(ea_block_cache, ce); 133062306a36Sopenharmony_ci } 133162306a36Sopenharmony_ci } 133262306a36Sopenharmony_ci } 133362306a36Sopenharmony_ci 133462306a36Sopenharmony_ci ext4_xattr_block_csum_set(inode, bh); 133562306a36Sopenharmony_ci /* 133662306a36Sopenharmony_ci * Beware of this ugliness: Releasing of xattr block references 133762306a36Sopenharmony_ci * from different inodes can race and so we have to protect 133862306a36Sopenharmony_ci * from a race where someone else frees the block (and releases 133962306a36Sopenharmony_ci * its journal_head) before we are done dirtying the buffer. In 134062306a36Sopenharmony_ci * nojournal mode this race is harmless and we actually cannot 134162306a36Sopenharmony_ci * call ext4_handle_dirty_metadata() with locked buffer as 134262306a36Sopenharmony_ci * that function can call sync_dirty_buffer() so for that case 134362306a36Sopenharmony_ci * we handle the dirtying after unlocking the buffer. 134462306a36Sopenharmony_ci */ 134562306a36Sopenharmony_ci if (ext4_handle_valid(handle)) 134662306a36Sopenharmony_ci error = ext4_handle_dirty_metadata(handle, inode, bh); 134762306a36Sopenharmony_ci unlock_buffer(bh); 134862306a36Sopenharmony_ci if (!ext4_handle_valid(handle)) 134962306a36Sopenharmony_ci error = ext4_handle_dirty_metadata(handle, inode, bh); 135062306a36Sopenharmony_ci if (IS_SYNC(inode)) 135162306a36Sopenharmony_ci ext4_handle_sync(handle); 135262306a36Sopenharmony_ci dquot_free_block(inode, EXT4_C2B(EXT4_SB(inode->i_sb), 1)); 135362306a36Sopenharmony_ci ea_bdebug(bh, "refcount now=%d; releasing", 135462306a36Sopenharmony_ci le32_to_cpu(BHDR(bh)->h_refcount)); 135562306a36Sopenharmony_ci } 135662306a36Sopenharmony_ciout: 135762306a36Sopenharmony_ci ext4_std_error(inode->i_sb, error); 135862306a36Sopenharmony_ci return; 135962306a36Sopenharmony_ci} 136062306a36Sopenharmony_ci 136162306a36Sopenharmony_ci/* 136262306a36Sopenharmony_ci * Find the available free space for EAs. This also returns the total number of 136362306a36Sopenharmony_ci * bytes used by EA entries. 136462306a36Sopenharmony_ci */ 136562306a36Sopenharmony_cistatic size_t ext4_xattr_free_space(struct ext4_xattr_entry *last, 136662306a36Sopenharmony_ci size_t *min_offs, void *base, int *total) 136762306a36Sopenharmony_ci{ 136862306a36Sopenharmony_ci for (; !IS_LAST_ENTRY(last); last = EXT4_XATTR_NEXT(last)) { 136962306a36Sopenharmony_ci if (!last->e_value_inum && last->e_value_size) { 137062306a36Sopenharmony_ci size_t offs = le16_to_cpu(last->e_value_offs); 137162306a36Sopenharmony_ci if (offs < *min_offs) 137262306a36Sopenharmony_ci *min_offs = offs; 137362306a36Sopenharmony_ci } 137462306a36Sopenharmony_ci if (total) 137562306a36Sopenharmony_ci *total += EXT4_XATTR_LEN(last->e_name_len); 137662306a36Sopenharmony_ci } 137762306a36Sopenharmony_ci return (*min_offs - ((void *)last - base) - sizeof(__u32)); 137862306a36Sopenharmony_ci} 137962306a36Sopenharmony_ci 138062306a36Sopenharmony_ci/* 138162306a36Sopenharmony_ci * Write the value of the EA in an inode. 138262306a36Sopenharmony_ci */ 138362306a36Sopenharmony_cistatic int ext4_xattr_inode_write(handle_t *handle, struct inode *ea_inode, 138462306a36Sopenharmony_ci const void *buf, int bufsize) 138562306a36Sopenharmony_ci{ 138662306a36Sopenharmony_ci struct buffer_head *bh = NULL; 138762306a36Sopenharmony_ci unsigned long block = 0; 138862306a36Sopenharmony_ci int blocksize = ea_inode->i_sb->s_blocksize; 138962306a36Sopenharmony_ci int max_blocks = (bufsize + blocksize - 1) >> ea_inode->i_blkbits; 139062306a36Sopenharmony_ci int csize, wsize = 0; 139162306a36Sopenharmony_ci int ret = 0, ret2 = 0; 139262306a36Sopenharmony_ci int retries = 0; 139362306a36Sopenharmony_ci 139462306a36Sopenharmony_ciretry: 139562306a36Sopenharmony_ci while (ret >= 0 && ret < max_blocks) { 139662306a36Sopenharmony_ci struct ext4_map_blocks map; 139762306a36Sopenharmony_ci map.m_lblk = block += ret; 139862306a36Sopenharmony_ci map.m_len = max_blocks -= ret; 139962306a36Sopenharmony_ci 140062306a36Sopenharmony_ci ret = ext4_map_blocks(handle, ea_inode, &map, 140162306a36Sopenharmony_ci EXT4_GET_BLOCKS_CREATE); 140262306a36Sopenharmony_ci if (ret <= 0) { 140362306a36Sopenharmony_ci ext4_mark_inode_dirty(handle, ea_inode); 140462306a36Sopenharmony_ci if (ret == -ENOSPC && 140562306a36Sopenharmony_ci ext4_should_retry_alloc(ea_inode->i_sb, &retries)) { 140662306a36Sopenharmony_ci ret = 0; 140762306a36Sopenharmony_ci goto retry; 140862306a36Sopenharmony_ci } 140962306a36Sopenharmony_ci break; 141062306a36Sopenharmony_ci } 141162306a36Sopenharmony_ci } 141262306a36Sopenharmony_ci 141362306a36Sopenharmony_ci if (ret < 0) 141462306a36Sopenharmony_ci return ret; 141562306a36Sopenharmony_ci 141662306a36Sopenharmony_ci block = 0; 141762306a36Sopenharmony_ci while (wsize < bufsize) { 141862306a36Sopenharmony_ci brelse(bh); 141962306a36Sopenharmony_ci csize = (bufsize - wsize) > blocksize ? blocksize : 142062306a36Sopenharmony_ci bufsize - wsize; 142162306a36Sopenharmony_ci bh = ext4_getblk(handle, ea_inode, block, 0); 142262306a36Sopenharmony_ci if (IS_ERR(bh)) 142362306a36Sopenharmony_ci return PTR_ERR(bh); 142462306a36Sopenharmony_ci if (!bh) { 142562306a36Sopenharmony_ci WARN_ON_ONCE(1); 142662306a36Sopenharmony_ci EXT4_ERROR_INODE(ea_inode, 142762306a36Sopenharmony_ci "ext4_getblk() return bh = NULL"); 142862306a36Sopenharmony_ci return -EFSCORRUPTED; 142962306a36Sopenharmony_ci } 143062306a36Sopenharmony_ci ret = ext4_journal_get_write_access(handle, ea_inode->i_sb, bh, 143162306a36Sopenharmony_ci EXT4_JTR_NONE); 143262306a36Sopenharmony_ci if (ret) 143362306a36Sopenharmony_ci goto out; 143462306a36Sopenharmony_ci 143562306a36Sopenharmony_ci memcpy(bh->b_data, buf, csize); 143662306a36Sopenharmony_ci set_buffer_uptodate(bh); 143762306a36Sopenharmony_ci ext4_handle_dirty_metadata(handle, ea_inode, bh); 143862306a36Sopenharmony_ci 143962306a36Sopenharmony_ci buf += csize; 144062306a36Sopenharmony_ci wsize += csize; 144162306a36Sopenharmony_ci block += 1; 144262306a36Sopenharmony_ci } 144362306a36Sopenharmony_ci 144462306a36Sopenharmony_ci inode_lock(ea_inode); 144562306a36Sopenharmony_ci i_size_write(ea_inode, wsize); 144662306a36Sopenharmony_ci ext4_update_i_disksize(ea_inode, wsize); 144762306a36Sopenharmony_ci inode_unlock(ea_inode); 144862306a36Sopenharmony_ci 144962306a36Sopenharmony_ci ret2 = ext4_mark_inode_dirty(handle, ea_inode); 145062306a36Sopenharmony_ci if (unlikely(ret2 && !ret)) 145162306a36Sopenharmony_ci ret = ret2; 145262306a36Sopenharmony_ci 145362306a36Sopenharmony_ciout: 145462306a36Sopenharmony_ci brelse(bh); 145562306a36Sopenharmony_ci 145662306a36Sopenharmony_ci return ret; 145762306a36Sopenharmony_ci} 145862306a36Sopenharmony_ci 145962306a36Sopenharmony_ci/* 146062306a36Sopenharmony_ci * Create an inode to store the value of a large EA. 146162306a36Sopenharmony_ci */ 146262306a36Sopenharmony_cistatic struct inode *ext4_xattr_inode_create(handle_t *handle, 146362306a36Sopenharmony_ci struct inode *inode, u32 hash) 146462306a36Sopenharmony_ci{ 146562306a36Sopenharmony_ci struct inode *ea_inode = NULL; 146662306a36Sopenharmony_ci uid_t owner[2] = { i_uid_read(inode), i_gid_read(inode) }; 146762306a36Sopenharmony_ci int err; 146862306a36Sopenharmony_ci 146962306a36Sopenharmony_ci if (inode->i_sb->s_root == NULL) { 147062306a36Sopenharmony_ci ext4_warning(inode->i_sb, 147162306a36Sopenharmony_ci "refuse to create EA inode when umounting"); 147262306a36Sopenharmony_ci WARN_ON(1); 147362306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 147462306a36Sopenharmony_ci } 147562306a36Sopenharmony_ci 147662306a36Sopenharmony_ci /* 147762306a36Sopenharmony_ci * Let the next inode be the goal, so we try and allocate the EA inode 147862306a36Sopenharmony_ci * in the same group, or nearby one. 147962306a36Sopenharmony_ci */ 148062306a36Sopenharmony_ci ea_inode = ext4_new_inode(handle, inode->i_sb->s_root->d_inode, 148162306a36Sopenharmony_ci S_IFREG | 0600, NULL, inode->i_ino + 1, owner, 148262306a36Sopenharmony_ci EXT4_EA_INODE_FL); 148362306a36Sopenharmony_ci if (!IS_ERR(ea_inode)) { 148462306a36Sopenharmony_ci ea_inode->i_op = &ext4_file_inode_operations; 148562306a36Sopenharmony_ci ea_inode->i_fop = &ext4_file_operations; 148662306a36Sopenharmony_ci ext4_set_aops(ea_inode); 148762306a36Sopenharmony_ci ext4_xattr_inode_set_class(ea_inode); 148862306a36Sopenharmony_ci unlock_new_inode(ea_inode); 148962306a36Sopenharmony_ci ext4_xattr_inode_set_ref(ea_inode, 1); 149062306a36Sopenharmony_ci ext4_xattr_inode_set_hash(ea_inode, hash); 149162306a36Sopenharmony_ci err = ext4_mark_inode_dirty(handle, ea_inode); 149262306a36Sopenharmony_ci if (!err) 149362306a36Sopenharmony_ci err = ext4_inode_attach_jinode(ea_inode); 149462306a36Sopenharmony_ci if (err) { 149562306a36Sopenharmony_ci if (ext4_xattr_inode_dec_ref(handle, ea_inode)) 149662306a36Sopenharmony_ci ext4_warning_inode(ea_inode, 149762306a36Sopenharmony_ci "cleanup dec ref error %d", err); 149862306a36Sopenharmony_ci iput(ea_inode); 149962306a36Sopenharmony_ci return ERR_PTR(err); 150062306a36Sopenharmony_ci } 150162306a36Sopenharmony_ci 150262306a36Sopenharmony_ci /* 150362306a36Sopenharmony_ci * Xattr inodes are shared therefore quota charging is performed 150462306a36Sopenharmony_ci * at a higher level. 150562306a36Sopenharmony_ci */ 150662306a36Sopenharmony_ci dquot_free_inode(ea_inode); 150762306a36Sopenharmony_ci dquot_drop(ea_inode); 150862306a36Sopenharmony_ci inode_lock(ea_inode); 150962306a36Sopenharmony_ci ea_inode->i_flags |= S_NOQUOTA; 151062306a36Sopenharmony_ci inode_unlock(ea_inode); 151162306a36Sopenharmony_ci } 151262306a36Sopenharmony_ci 151362306a36Sopenharmony_ci return ea_inode; 151462306a36Sopenharmony_ci} 151562306a36Sopenharmony_ci 151662306a36Sopenharmony_cistatic struct inode * 151762306a36Sopenharmony_ciext4_xattr_inode_cache_find(struct inode *inode, const void *value, 151862306a36Sopenharmony_ci size_t value_len, u32 hash) 151962306a36Sopenharmony_ci{ 152062306a36Sopenharmony_ci struct inode *ea_inode; 152162306a36Sopenharmony_ci struct mb_cache_entry *ce; 152262306a36Sopenharmony_ci struct mb_cache *ea_inode_cache = EA_INODE_CACHE(inode); 152362306a36Sopenharmony_ci void *ea_data; 152462306a36Sopenharmony_ci 152562306a36Sopenharmony_ci if (!ea_inode_cache) 152662306a36Sopenharmony_ci return NULL; 152762306a36Sopenharmony_ci 152862306a36Sopenharmony_ci ce = mb_cache_entry_find_first(ea_inode_cache, hash); 152962306a36Sopenharmony_ci if (!ce) 153062306a36Sopenharmony_ci return NULL; 153162306a36Sopenharmony_ci 153262306a36Sopenharmony_ci WARN_ON_ONCE(ext4_handle_valid(journal_current_handle()) && 153362306a36Sopenharmony_ci !(current->flags & PF_MEMALLOC_NOFS)); 153462306a36Sopenharmony_ci 153562306a36Sopenharmony_ci ea_data = kvmalloc(value_len, GFP_KERNEL); 153662306a36Sopenharmony_ci if (!ea_data) { 153762306a36Sopenharmony_ci mb_cache_entry_put(ea_inode_cache, ce); 153862306a36Sopenharmony_ci return NULL; 153962306a36Sopenharmony_ci } 154062306a36Sopenharmony_ci 154162306a36Sopenharmony_ci while (ce) { 154262306a36Sopenharmony_ci ea_inode = ext4_iget(inode->i_sb, ce->e_value, 154362306a36Sopenharmony_ci EXT4_IGET_EA_INODE); 154462306a36Sopenharmony_ci if (IS_ERR(ea_inode)) 154562306a36Sopenharmony_ci goto next_entry; 154662306a36Sopenharmony_ci ext4_xattr_inode_set_class(ea_inode); 154762306a36Sopenharmony_ci if (i_size_read(ea_inode) == value_len && 154862306a36Sopenharmony_ci !ext4_xattr_inode_read(ea_inode, ea_data, value_len) && 154962306a36Sopenharmony_ci !ext4_xattr_inode_verify_hashes(ea_inode, NULL, ea_data, 155062306a36Sopenharmony_ci value_len) && 155162306a36Sopenharmony_ci !memcmp(value, ea_data, value_len)) { 155262306a36Sopenharmony_ci mb_cache_entry_touch(ea_inode_cache, ce); 155362306a36Sopenharmony_ci mb_cache_entry_put(ea_inode_cache, ce); 155462306a36Sopenharmony_ci kvfree(ea_data); 155562306a36Sopenharmony_ci return ea_inode; 155662306a36Sopenharmony_ci } 155762306a36Sopenharmony_ci iput(ea_inode); 155862306a36Sopenharmony_ci next_entry: 155962306a36Sopenharmony_ci ce = mb_cache_entry_find_next(ea_inode_cache, ce); 156062306a36Sopenharmony_ci } 156162306a36Sopenharmony_ci kvfree(ea_data); 156262306a36Sopenharmony_ci return NULL; 156362306a36Sopenharmony_ci} 156462306a36Sopenharmony_ci 156562306a36Sopenharmony_ci/* 156662306a36Sopenharmony_ci * Add value of the EA in an inode. 156762306a36Sopenharmony_ci */ 156862306a36Sopenharmony_cistatic int ext4_xattr_inode_lookup_create(handle_t *handle, struct inode *inode, 156962306a36Sopenharmony_ci const void *value, size_t value_len, 157062306a36Sopenharmony_ci struct inode **ret_inode) 157162306a36Sopenharmony_ci{ 157262306a36Sopenharmony_ci struct inode *ea_inode; 157362306a36Sopenharmony_ci u32 hash; 157462306a36Sopenharmony_ci int err; 157562306a36Sopenharmony_ci 157662306a36Sopenharmony_ci hash = ext4_xattr_inode_hash(EXT4_SB(inode->i_sb), value, value_len); 157762306a36Sopenharmony_ci ea_inode = ext4_xattr_inode_cache_find(inode, value, value_len, hash); 157862306a36Sopenharmony_ci if (ea_inode) { 157962306a36Sopenharmony_ci err = ext4_xattr_inode_inc_ref(handle, ea_inode); 158062306a36Sopenharmony_ci if (err) { 158162306a36Sopenharmony_ci iput(ea_inode); 158262306a36Sopenharmony_ci return err; 158362306a36Sopenharmony_ci } 158462306a36Sopenharmony_ci 158562306a36Sopenharmony_ci *ret_inode = ea_inode; 158662306a36Sopenharmony_ci return 0; 158762306a36Sopenharmony_ci } 158862306a36Sopenharmony_ci 158962306a36Sopenharmony_ci /* Create an inode for the EA value */ 159062306a36Sopenharmony_ci ea_inode = ext4_xattr_inode_create(handle, inode, hash); 159162306a36Sopenharmony_ci if (IS_ERR(ea_inode)) 159262306a36Sopenharmony_ci return PTR_ERR(ea_inode); 159362306a36Sopenharmony_ci 159462306a36Sopenharmony_ci err = ext4_xattr_inode_write(handle, ea_inode, value, value_len); 159562306a36Sopenharmony_ci if (err) { 159662306a36Sopenharmony_ci if (ext4_xattr_inode_dec_ref(handle, ea_inode)) 159762306a36Sopenharmony_ci ext4_warning_inode(ea_inode, "cleanup dec ref error %d", err); 159862306a36Sopenharmony_ci iput(ea_inode); 159962306a36Sopenharmony_ci return err; 160062306a36Sopenharmony_ci } 160162306a36Sopenharmony_ci 160262306a36Sopenharmony_ci if (EA_INODE_CACHE(inode)) 160362306a36Sopenharmony_ci mb_cache_entry_create(EA_INODE_CACHE(inode), GFP_NOFS, hash, 160462306a36Sopenharmony_ci ea_inode->i_ino, true /* reusable */); 160562306a36Sopenharmony_ci 160662306a36Sopenharmony_ci *ret_inode = ea_inode; 160762306a36Sopenharmony_ci return 0; 160862306a36Sopenharmony_ci} 160962306a36Sopenharmony_ci 161062306a36Sopenharmony_ci/* 161162306a36Sopenharmony_ci * Reserve min(block_size/8, 1024) bytes for xattr entries/names if ea_inode 161262306a36Sopenharmony_ci * feature is enabled. 161362306a36Sopenharmony_ci */ 161462306a36Sopenharmony_ci#define EXT4_XATTR_BLOCK_RESERVE(inode) min(i_blocksize(inode)/8, 1024U) 161562306a36Sopenharmony_ci 161662306a36Sopenharmony_cistatic int ext4_xattr_set_entry(struct ext4_xattr_info *i, 161762306a36Sopenharmony_ci struct ext4_xattr_search *s, 161862306a36Sopenharmony_ci handle_t *handle, struct inode *inode, 161962306a36Sopenharmony_ci bool is_block) 162062306a36Sopenharmony_ci{ 162162306a36Sopenharmony_ci struct ext4_xattr_entry *last, *next; 162262306a36Sopenharmony_ci struct ext4_xattr_entry *here = s->here; 162362306a36Sopenharmony_ci size_t min_offs = s->end - s->base, name_len = strlen(i->name); 162462306a36Sopenharmony_ci int in_inode = i->in_inode; 162562306a36Sopenharmony_ci struct inode *old_ea_inode = NULL; 162662306a36Sopenharmony_ci struct inode *new_ea_inode = NULL; 162762306a36Sopenharmony_ci size_t old_size, new_size; 162862306a36Sopenharmony_ci int ret; 162962306a36Sopenharmony_ci 163062306a36Sopenharmony_ci /* Space used by old and new values. */ 163162306a36Sopenharmony_ci old_size = (!s->not_found && !here->e_value_inum) ? 163262306a36Sopenharmony_ci EXT4_XATTR_SIZE(le32_to_cpu(here->e_value_size)) : 0; 163362306a36Sopenharmony_ci new_size = (i->value && !in_inode) ? EXT4_XATTR_SIZE(i->value_len) : 0; 163462306a36Sopenharmony_ci 163562306a36Sopenharmony_ci /* 163662306a36Sopenharmony_ci * Optimization for the simple case when old and new values have the 163762306a36Sopenharmony_ci * same padded sizes. Not applicable if external inodes are involved. 163862306a36Sopenharmony_ci */ 163962306a36Sopenharmony_ci if (new_size && new_size == old_size) { 164062306a36Sopenharmony_ci size_t offs = le16_to_cpu(here->e_value_offs); 164162306a36Sopenharmony_ci void *val = s->base + offs; 164262306a36Sopenharmony_ci 164362306a36Sopenharmony_ci here->e_value_size = cpu_to_le32(i->value_len); 164462306a36Sopenharmony_ci if (i->value == EXT4_ZERO_XATTR_VALUE) { 164562306a36Sopenharmony_ci memset(val, 0, new_size); 164662306a36Sopenharmony_ci } else { 164762306a36Sopenharmony_ci memcpy(val, i->value, i->value_len); 164862306a36Sopenharmony_ci /* Clear padding bytes. */ 164962306a36Sopenharmony_ci memset(val + i->value_len, 0, new_size - i->value_len); 165062306a36Sopenharmony_ci } 165162306a36Sopenharmony_ci goto update_hash; 165262306a36Sopenharmony_ci } 165362306a36Sopenharmony_ci 165462306a36Sopenharmony_ci /* Compute min_offs and last. */ 165562306a36Sopenharmony_ci last = s->first; 165662306a36Sopenharmony_ci for (; !IS_LAST_ENTRY(last); last = next) { 165762306a36Sopenharmony_ci next = EXT4_XATTR_NEXT(last); 165862306a36Sopenharmony_ci if ((void *)next >= s->end) { 165962306a36Sopenharmony_ci EXT4_ERROR_INODE(inode, "corrupted xattr entries"); 166062306a36Sopenharmony_ci ret = -EFSCORRUPTED; 166162306a36Sopenharmony_ci goto out; 166262306a36Sopenharmony_ci } 166362306a36Sopenharmony_ci if (!last->e_value_inum && last->e_value_size) { 166462306a36Sopenharmony_ci size_t offs = le16_to_cpu(last->e_value_offs); 166562306a36Sopenharmony_ci if (offs < min_offs) 166662306a36Sopenharmony_ci min_offs = offs; 166762306a36Sopenharmony_ci } 166862306a36Sopenharmony_ci } 166962306a36Sopenharmony_ci 167062306a36Sopenharmony_ci /* Check whether we have enough space. */ 167162306a36Sopenharmony_ci if (i->value) { 167262306a36Sopenharmony_ci size_t free; 167362306a36Sopenharmony_ci 167462306a36Sopenharmony_ci free = min_offs - ((void *)last - s->base) - sizeof(__u32); 167562306a36Sopenharmony_ci if (!s->not_found) 167662306a36Sopenharmony_ci free += EXT4_XATTR_LEN(name_len) + old_size; 167762306a36Sopenharmony_ci 167862306a36Sopenharmony_ci if (free < EXT4_XATTR_LEN(name_len) + new_size) { 167962306a36Sopenharmony_ci ret = -ENOSPC; 168062306a36Sopenharmony_ci goto out; 168162306a36Sopenharmony_ci } 168262306a36Sopenharmony_ci 168362306a36Sopenharmony_ci /* 168462306a36Sopenharmony_ci * If storing the value in an external inode is an option, 168562306a36Sopenharmony_ci * reserve space for xattr entries/names in the external 168662306a36Sopenharmony_ci * attribute block so that a long value does not occupy the 168762306a36Sopenharmony_ci * whole space and prevent further entries being added. 168862306a36Sopenharmony_ci */ 168962306a36Sopenharmony_ci if (ext4_has_feature_ea_inode(inode->i_sb) && 169062306a36Sopenharmony_ci new_size && is_block && 169162306a36Sopenharmony_ci (min_offs + old_size - new_size) < 169262306a36Sopenharmony_ci EXT4_XATTR_BLOCK_RESERVE(inode)) { 169362306a36Sopenharmony_ci ret = -ENOSPC; 169462306a36Sopenharmony_ci goto out; 169562306a36Sopenharmony_ci } 169662306a36Sopenharmony_ci } 169762306a36Sopenharmony_ci 169862306a36Sopenharmony_ci /* 169962306a36Sopenharmony_ci * Getting access to old and new ea inodes is subject to failures. 170062306a36Sopenharmony_ci * Finish that work before doing any modifications to the xattr data. 170162306a36Sopenharmony_ci */ 170262306a36Sopenharmony_ci if (!s->not_found && here->e_value_inum) { 170362306a36Sopenharmony_ci ret = ext4_xattr_inode_iget(inode, 170462306a36Sopenharmony_ci le32_to_cpu(here->e_value_inum), 170562306a36Sopenharmony_ci le32_to_cpu(here->e_hash), 170662306a36Sopenharmony_ci &old_ea_inode); 170762306a36Sopenharmony_ci if (ret) { 170862306a36Sopenharmony_ci old_ea_inode = NULL; 170962306a36Sopenharmony_ci goto out; 171062306a36Sopenharmony_ci } 171162306a36Sopenharmony_ci } 171262306a36Sopenharmony_ci if (i->value && in_inode) { 171362306a36Sopenharmony_ci WARN_ON_ONCE(!i->value_len); 171462306a36Sopenharmony_ci 171562306a36Sopenharmony_ci ret = ext4_xattr_inode_alloc_quota(inode, i->value_len); 171662306a36Sopenharmony_ci if (ret) 171762306a36Sopenharmony_ci goto out; 171862306a36Sopenharmony_ci 171962306a36Sopenharmony_ci ret = ext4_xattr_inode_lookup_create(handle, inode, i->value, 172062306a36Sopenharmony_ci i->value_len, 172162306a36Sopenharmony_ci &new_ea_inode); 172262306a36Sopenharmony_ci if (ret) { 172362306a36Sopenharmony_ci new_ea_inode = NULL; 172462306a36Sopenharmony_ci ext4_xattr_inode_free_quota(inode, NULL, i->value_len); 172562306a36Sopenharmony_ci goto out; 172662306a36Sopenharmony_ci } 172762306a36Sopenharmony_ci } 172862306a36Sopenharmony_ci 172962306a36Sopenharmony_ci if (old_ea_inode) { 173062306a36Sopenharmony_ci /* We are ready to release ref count on the old_ea_inode. */ 173162306a36Sopenharmony_ci ret = ext4_xattr_inode_dec_ref(handle, old_ea_inode); 173262306a36Sopenharmony_ci if (ret) { 173362306a36Sopenharmony_ci /* Release newly required ref count on new_ea_inode. */ 173462306a36Sopenharmony_ci if (new_ea_inode) { 173562306a36Sopenharmony_ci int err; 173662306a36Sopenharmony_ci 173762306a36Sopenharmony_ci err = ext4_xattr_inode_dec_ref(handle, 173862306a36Sopenharmony_ci new_ea_inode); 173962306a36Sopenharmony_ci if (err) 174062306a36Sopenharmony_ci ext4_warning_inode(new_ea_inode, 174162306a36Sopenharmony_ci "dec ref new_ea_inode err=%d", 174262306a36Sopenharmony_ci err); 174362306a36Sopenharmony_ci ext4_xattr_inode_free_quota(inode, new_ea_inode, 174462306a36Sopenharmony_ci i->value_len); 174562306a36Sopenharmony_ci } 174662306a36Sopenharmony_ci goto out; 174762306a36Sopenharmony_ci } 174862306a36Sopenharmony_ci 174962306a36Sopenharmony_ci ext4_xattr_inode_free_quota(inode, old_ea_inode, 175062306a36Sopenharmony_ci le32_to_cpu(here->e_value_size)); 175162306a36Sopenharmony_ci } 175262306a36Sopenharmony_ci 175362306a36Sopenharmony_ci /* No failures allowed past this point. */ 175462306a36Sopenharmony_ci 175562306a36Sopenharmony_ci if (!s->not_found && here->e_value_size && !here->e_value_inum) { 175662306a36Sopenharmony_ci /* Remove the old value. */ 175762306a36Sopenharmony_ci void *first_val = s->base + min_offs; 175862306a36Sopenharmony_ci size_t offs = le16_to_cpu(here->e_value_offs); 175962306a36Sopenharmony_ci void *val = s->base + offs; 176062306a36Sopenharmony_ci 176162306a36Sopenharmony_ci memmove(first_val + old_size, first_val, val - first_val); 176262306a36Sopenharmony_ci memset(first_val, 0, old_size); 176362306a36Sopenharmony_ci min_offs += old_size; 176462306a36Sopenharmony_ci 176562306a36Sopenharmony_ci /* Adjust all value offsets. */ 176662306a36Sopenharmony_ci last = s->first; 176762306a36Sopenharmony_ci while (!IS_LAST_ENTRY(last)) { 176862306a36Sopenharmony_ci size_t o = le16_to_cpu(last->e_value_offs); 176962306a36Sopenharmony_ci 177062306a36Sopenharmony_ci if (!last->e_value_inum && 177162306a36Sopenharmony_ci last->e_value_size && o < offs) 177262306a36Sopenharmony_ci last->e_value_offs = cpu_to_le16(o + old_size); 177362306a36Sopenharmony_ci last = EXT4_XATTR_NEXT(last); 177462306a36Sopenharmony_ci } 177562306a36Sopenharmony_ci } 177662306a36Sopenharmony_ci 177762306a36Sopenharmony_ci if (!i->value) { 177862306a36Sopenharmony_ci /* Remove old name. */ 177962306a36Sopenharmony_ci size_t size = EXT4_XATTR_LEN(name_len); 178062306a36Sopenharmony_ci 178162306a36Sopenharmony_ci last = ENTRY((void *)last - size); 178262306a36Sopenharmony_ci memmove(here, (void *)here + size, 178362306a36Sopenharmony_ci (void *)last - (void *)here + sizeof(__u32)); 178462306a36Sopenharmony_ci memset(last, 0, size); 178562306a36Sopenharmony_ci 178662306a36Sopenharmony_ci /* 178762306a36Sopenharmony_ci * Update i_inline_off - moved ibody region might contain 178862306a36Sopenharmony_ci * system.data attribute. Handling a failure here won't 178962306a36Sopenharmony_ci * cause other complications for setting an xattr. 179062306a36Sopenharmony_ci */ 179162306a36Sopenharmony_ci if (!is_block && ext4_has_inline_data(inode)) { 179262306a36Sopenharmony_ci ret = ext4_find_inline_data_nolock(inode); 179362306a36Sopenharmony_ci if (ret) { 179462306a36Sopenharmony_ci ext4_warning_inode(inode, 179562306a36Sopenharmony_ci "unable to update i_inline_off"); 179662306a36Sopenharmony_ci goto out; 179762306a36Sopenharmony_ci } 179862306a36Sopenharmony_ci } 179962306a36Sopenharmony_ci } else if (s->not_found) { 180062306a36Sopenharmony_ci /* Insert new name. */ 180162306a36Sopenharmony_ci size_t size = EXT4_XATTR_LEN(name_len); 180262306a36Sopenharmony_ci size_t rest = (void *)last - (void *)here + sizeof(__u32); 180362306a36Sopenharmony_ci 180462306a36Sopenharmony_ci memmove((void *)here + size, here, rest); 180562306a36Sopenharmony_ci memset(here, 0, size); 180662306a36Sopenharmony_ci here->e_name_index = i->name_index; 180762306a36Sopenharmony_ci here->e_name_len = name_len; 180862306a36Sopenharmony_ci memcpy(here->e_name, i->name, name_len); 180962306a36Sopenharmony_ci } else { 181062306a36Sopenharmony_ci /* This is an update, reset value info. */ 181162306a36Sopenharmony_ci here->e_value_inum = 0; 181262306a36Sopenharmony_ci here->e_value_offs = 0; 181362306a36Sopenharmony_ci here->e_value_size = 0; 181462306a36Sopenharmony_ci } 181562306a36Sopenharmony_ci 181662306a36Sopenharmony_ci if (i->value) { 181762306a36Sopenharmony_ci /* Insert new value. */ 181862306a36Sopenharmony_ci if (in_inode) { 181962306a36Sopenharmony_ci here->e_value_inum = cpu_to_le32(new_ea_inode->i_ino); 182062306a36Sopenharmony_ci } else if (i->value_len) { 182162306a36Sopenharmony_ci void *val = s->base + min_offs - new_size; 182262306a36Sopenharmony_ci 182362306a36Sopenharmony_ci here->e_value_offs = cpu_to_le16(min_offs - new_size); 182462306a36Sopenharmony_ci if (i->value == EXT4_ZERO_XATTR_VALUE) { 182562306a36Sopenharmony_ci memset(val, 0, new_size); 182662306a36Sopenharmony_ci } else { 182762306a36Sopenharmony_ci memcpy(val, i->value, i->value_len); 182862306a36Sopenharmony_ci /* Clear padding bytes. */ 182962306a36Sopenharmony_ci memset(val + i->value_len, 0, 183062306a36Sopenharmony_ci new_size - i->value_len); 183162306a36Sopenharmony_ci } 183262306a36Sopenharmony_ci } 183362306a36Sopenharmony_ci here->e_value_size = cpu_to_le32(i->value_len); 183462306a36Sopenharmony_ci } 183562306a36Sopenharmony_ci 183662306a36Sopenharmony_ciupdate_hash: 183762306a36Sopenharmony_ci if (i->value) { 183862306a36Sopenharmony_ci __le32 hash = 0; 183962306a36Sopenharmony_ci 184062306a36Sopenharmony_ci /* Entry hash calculation. */ 184162306a36Sopenharmony_ci if (in_inode) { 184262306a36Sopenharmony_ci __le32 crc32c_hash; 184362306a36Sopenharmony_ci 184462306a36Sopenharmony_ci /* 184562306a36Sopenharmony_ci * Feed crc32c hash instead of the raw value for entry 184662306a36Sopenharmony_ci * hash calculation. This is to avoid walking 184762306a36Sopenharmony_ci * potentially long value buffer again. 184862306a36Sopenharmony_ci */ 184962306a36Sopenharmony_ci crc32c_hash = cpu_to_le32( 185062306a36Sopenharmony_ci ext4_xattr_inode_get_hash(new_ea_inode)); 185162306a36Sopenharmony_ci hash = ext4_xattr_hash_entry(here->e_name, 185262306a36Sopenharmony_ci here->e_name_len, 185362306a36Sopenharmony_ci &crc32c_hash, 1); 185462306a36Sopenharmony_ci } else if (is_block) { 185562306a36Sopenharmony_ci __le32 *value = s->base + le16_to_cpu( 185662306a36Sopenharmony_ci here->e_value_offs); 185762306a36Sopenharmony_ci 185862306a36Sopenharmony_ci hash = ext4_xattr_hash_entry(here->e_name, 185962306a36Sopenharmony_ci here->e_name_len, value, 186062306a36Sopenharmony_ci new_size >> 2); 186162306a36Sopenharmony_ci } 186262306a36Sopenharmony_ci here->e_hash = hash; 186362306a36Sopenharmony_ci } 186462306a36Sopenharmony_ci 186562306a36Sopenharmony_ci if (is_block) 186662306a36Sopenharmony_ci ext4_xattr_rehash((struct ext4_xattr_header *)s->base); 186762306a36Sopenharmony_ci 186862306a36Sopenharmony_ci ret = 0; 186962306a36Sopenharmony_ciout: 187062306a36Sopenharmony_ci iput(old_ea_inode); 187162306a36Sopenharmony_ci iput(new_ea_inode); 187262306a36Sopenharmony_ci return ret; 187362306a36Sopenharmony_ci} 187462306a36Sopenharmony_ci 187562306a36Sopenharmony_cistruct ext4_xattr_block_find { 187662306a36Sopenharmony_ci struct ext4_xattr_search s; 187762306a36Sopenharmony_ci struct buffer_head *bh; 187862306a36Sopenharmony_ci}; 187962306a36Sopenharmony_ci 188062306a36Sopenharmony_cistatic int 188162306a36Sopenharmony_ciext4_xattr_block_find(struct inode *inode, struct ext4_xattr_info *i, 188262306a36Sopenharmony_ci struct ext4_xattr_block_find *bs) 188362306a36Sopenharmony_ci{ 188462306a36Sopenharmony_ci struct super_block *sb = inode->i_sb; 188562306a36Sopenharmony_ci int error; 188662306a36Sopenharmony_ci 188762306a36Sopenharmony_ci ea_idebug(inode, "name=%d.%s, value=%p, value_len=%ld", 188862306a36Sopenharmony_ci i->name_index, i->name, i->value, (long)i->value_len); 188962306a36Sopenharmony_ci 189062306a36Sopenharmony_ci if (EXT4_I(inode)->i_file_acl) { 189162306a36Sopenharmony_ci /* The inode already has an extended attribute block. */ 189262306a36Sopenharmony_ci bs->bh = ext4_sb_bread(sb, EXT4_I(inode)->i_file_acl, REQ_PRIO); 189362306a36Sopenharmony_ci if (IS_ERR(bs->bh)) { 189462306a36Sopenharmony_ci error = PTR_ERR(bs->bh); 189562306a36Sopenharmony_ci bs->bh = NULL; 189662306a36Sopenharmony_ci return error; 189762306a36Sopenharmony_ci } 189862306a36Sopenharmony_ci ea_bdebug(bs->bh, "b_count=%d, refcount=%d", 189962306a36Sopenharmony_ci atomic_read(&(bs->bh->b_count)), 190062306a36Sopenharmony_ci le32_to_cpu(BHDR(bs->bh)->h_refcount)); 190162306a36Sopenharmony_ci error = ext4_xattr_check_block(inode, bs->bh); 190262306a36Sopenharmony_ci if (error) 190362306a36Sopenharmony_ci return error; 190462306a36Sopenharmony_ci /* Find the named attribute. */ 190562306a36Sopenharmony_ci bs->s.base = BHDR(bs->bh); 190662306a36Sopenharmony_ci bs->s.first = BFIRST(bs->bh); 190762306a36Sopenharmony_ci bs->s.end = bs->bh->b_data + bs->bh->b_size; 190862306a36Sopenharmony_ci bs->s.here = bs->s.first; 190962306a36Sopenharmony_ci error = xattr_find_entry(inode, &bs->s.here, bs->s.end, 191062306a36Sopenharmony_ci i->name_index, i->name, 1); 191162306a36Sopenharmony_ci if (error && error != -ENODATA) 191262306a36Sopenharmony_ci return error; 191362306a36Sopenharmony_ci bs->s.not_found = error; 191462306a36Sopenharmony_ci } 191562306a36Sopenharmony_ci return 0; 191662306a36Sopenharmony_ci} 191762306a36Sopenharmony_ci 191862306a36Sopenharmony_cistatic int 191962306a36Sopenharmony_ciext4_xattr_block_set(handle_t *handle, struct inode *inode, 192062306a36Sopenharmony_ci struct ext4_xattr_info *i, 192162306a36Sopenharmony_ci struct ext4_xattr_block_find *bs) 192262306a36Sopenharmony_ci{ 192362306a36Sopenharmony_ci struct super_block *sb = inode->i_sb; 192462306a36Sopenharmony_ci struct buffer_head *new_bh = NULL; 192562306a36Sopenharmony_ci struct ext4_xattr_search s_copy = bs->s; 192662306a36Sopenharmony_ci struct ext4_xattr_search *s = &s_copy; 192762306a36Sopenharmony_ci struct mb_cache_entry *ce = NULL; 192862306a36Sopenharmony_ci int error = 0; 192962306a36Sopenharmony_ci struct mb_cache *ea_block_cache = EA_BLOCK_CACHE(inode); 193062306a36Sopenharmony_ci struct inode *ea_inode = NULL, *tmp_inode; 193162306a36Sopenharmony_ci size_t old_ea_inode_quota = 0; 193262306a36Sopenharmony_ci unsigned int ea_ino; 193362306a36Sopenharmony_ci 193462306a36Sopenharmony_ci 193562306a36Sopenharmony_ci#define header(x) ((struct ext4_xattr_header *)(x)) 193662306a36Sopenharmony_ci 193762306a36Sopenharmony_ci if (s->base) { 193862306a36Sopenharmony_ci int offset = (char *)s->here - bs->bh->b_data; 193962306a36Sopenharmony_ci 194062306a36Sopenharmony_ci BUFFER_TRACE(bs->bh, "get_write_access"); 194162306a36Sopenharmony_ci error = ext4_journal_get_write_access(handle, sb, bs->bh, 194262306a36Sopenharmony_ci EXT4_JTR_NONE); 194362306a36Sopenharmony_ci if (error) 194462306a36Sopenharmony_ci goto cleanup; 194562306a36Sopenharmony_ci lock_buffer(bs->bh); 194662306a36Sopenharmony_ci 194762306a36Sopenharmony_ci if (header(s->base)->h_refcount == cpu_to_le32(1)) { 194862306a36Sopenharmony_ci __u32 hash = le32_to_cpu(BHDR(bs->bh)->h_hash); 194962306a36Sopenharmony_ci 195062306a36Sopenharmony_ci /* 195162306a36Sopenharmony_ci * This must happen under buffer lock for 195262306a36Sopenharmony_ci * ext4_xattr_block_set() to reliably detect modified 195362306a36Sopenharmony_ci * block 195462306a36Sopenharmony_ci */ 195562306a36Sopenharmony_ci if (ea_block_cache) { 195662306a36Sopenharmony_ci struct mb_cache_entry *oe; 195762306a36Sopenharmony_ci 195862306a36Sopenharmony_ci oe = mb_cache_entry_delete_or_get(ea_block_cache, 195962306a36Sopenharmony_ci hash, bs->bh->b_blocknr); 196062306a36Sopenharmony_ci if (oe) { 196162306a36Sopenharmony_ci /* 196262306a36Sopenharmony_ci * Xattr block is getting reused. Leave 196362306a36Sopenharmony_ci * it alone. 196462306a36Sopenharmony_ci */ 196562306a36Sopenharmony_ci mb_cache_entry_put(ea_block_cache, oe); 196662306a36Sopenharmony_ci goto clone_block; 196762306a36Sopenharmony_ci } 196862306a36Sopenharmony_ci } 196962306a36Sopenharmony_ci ea_bdebug(bs->bh, "modifying in-place"); 197062306a36Sopenharmony_ci error = ext4_xattr_set_entry(i, s, handle, inode, 197162306a36Sopenharmony_ci true /* is_block */); 197262306a36Sopenharmony_ci ext4_xattr_block_csum_set(inode, bs->bh); 197362306a36Sopenharmony_ci unlock_buffer(bs->bh); 197462306a36Sopenharmony_ci if (error == -EFSCORRUPTED) 197562306a36Sopenharmony_ci goto bad_block; 197662306a36Sopenharmony_ci if (!error) 197762306a36Sopenharmony_ci error = ext4_handle_dirty_metadata(handle, 197862306a36Sopenharmony_ci inode, 197962306a36Sopenharmony_ci bs->bh); 198062306a36Sopenharmony_ci if (error) 198162306a36Sopenharmony_ci goto cleanup; 198262306a36Sopenharmony_ci goto inserted; 198362306a36Sopenharmony_ci } 198462306a36Sopenharmony_ciclone_block: 198562306a36Sopenharmony_ci unlock_buffer(bs->bh); 198662306a36Sopenharmony_ci ea_bdebug(bs->bh, "cloning"); 198762306a36Sopenharmony_ci s->base = kmemdup(BHDR(bs->bh), bs->bh->b_size, GFP_NOFS); 198862306a36Sopenharmony_ci error = -ENOMEM; 198962306a36Sopenharmony_ci if (s->base == NULL) 199062306a36Sopenharmony_ci goto cleanup; 199162306a36Sopenharmony_ci s->first = ENTRY(header(s->base)+1); 199262306a36Sopenharmony_ci header(s->base)->h_refcount = cpu_to_le32(1); 199362306a36Sopenharmony_ci s->here = ENTRY(s->base + offset); 199462306a36Sopenharmony_ci s->end = s->base + bs->bh->b_size; 199562306a36Sopenharmony_ci 199662306a36Sopenharmony_ci /* 199762306a36Sopenharmony_ci * If existing entry points to an xattr inode, we need 199862306a36Sopenharmony_ci * to prevent ext4_xattr_set_entry() from decrementing 199962306a36Sopenharmony_ci * ref count on it because the reference belongs to the 200062306a36Sopenharmony_ci * original block. In this case, make the entry look 200162306a36Sopenharmony_ci * like it has an empty value. 200262306a36Sopenharmony_ci */ 200362306a36Sopenharmony_ci if (!s->not_found && s->here->e_value_inum) { 200462306a36Sopenharmony_ci ea_ino = le32_to_cpu(s->here->e_value_inum); 200562306a36Sopenharmony_ci error = ext4_xattr_inode_iget(inode, ea_ino, 200662306a36Sopenharmony_ci le32_to_cpu(s->here->e_hash), 200762306a36Sopenharmony_ci &tmp_inode); 200862306a36Sopenharmony_ci if (error) 200962306a36Sopenharmony_ci goto cleanup; 201062306a36Sopenharmony_ci 201162306a36Sopenharmony_ci if (!ext4_test_inode_state(tmp_inode, 201262306a36Sopenharmony_ci EXT4_STATE_LUSTRE_EA_INODE)) { 201362306a36Sopenharmony_ci /* 201462306a36Sopenharmony_ci * Defer quota free call for previous 201562306a36Sopenharmony_ci * inode until success is guaranteed. 201662306a36Sopenharmony_ci */ 201762306a36Sopenharmony_ci old_ea_inode_quota = le32_to_cpu( 201862306a36Sopenharmony_ci s->here->e_value_size); 201962306a36Sopenharmony_ci } 202062306a36Sopenharmony_ci iput(tmp_inode); 202162306a36Sopenharmony_ci 202262306a36Sopenharmony_ci s->here->e_value_inum = 0; 202362306a36Sopenharmony_ci s->here->e_value_size = 0; 202462306a36Sopenharmony_ci } 202562306a36Sopenharmony_ci } else { 202662306a36Sopenharmony_ci /* Allocate a buffer where we construct the new block. */ 202762306a36Sopenharmony_ci s->base = kzalloc(sb->s_blocksize, GFP_NOFS); 202862306a36Sopenharmony_ci error = -ENOMEM; 202962306a36Sopenharmony_ci if (s->base == NULL) 203062306a36Sopenharmony_ci goto cleanup; 203162306a36Sopenharmony_ci header(s->base)->h_magic = cpu_to_le32(EXT4_XATTR_MAGIC); 203262306a36Sopenharmony_ci header(s->base)->h_blocks = cpu_to_le32(1); 203362306a36Sopenharmony_ci header(s->base)->h_refcount = cpu_to_le32(1); 203462306a36Sopenharmony_ci s->first = ENTRY(header(s->base)+1); 203562306a36Sopenharmony_ci s->here = ENTRY(header(s->base)+1); 203662306a36Sopenharmony_ci s->end = s->base + sb->s_blocksize; 203762306a36Sopenharmony_ci } 203862306a36Sopenharmony_ci 203962306a36Sopenharmony_ci error = ext4_xattr_set_entry(i, s, handle, inode, true /* is_block */); 204062306a36Sopenharmony_ci if (error == -EFSCORRUPTED) 204162306a36Sopenharmony_ci goto bad_block; 204262306a36Sopenharmony_ci if (error) 204362306a36Sopenharmony_ci goto cleanup; 204462306a36Sopenharmony_ci 204562306a36Sopenharmony_ci if (i->value && s->here->e_value_inum) { 204662306a36Sopenharmony_ci /* 204762306a36Sopenharmony_ci * A ref count on ea_inode has been taken as part of the call to 204862306a36Sopenharmony_ci * ext4_xattr_set_entry() above. We would like to drop this 204962306a36Sopenharmony_ci * extra ref but we have to wait until the xattr block is 205062306a36Sopenharmony_ci * initialized and has its own ref count on the ea_inode. 205162306a36Sopenharmony_ci */ 205262306a36Sopenharmony_ci ea_ino = le32_to_cpu(s->here->e_value_inum); 205362306a36Sopenharmony_ci error = ext4_xattr_inode_iget(inode, ea_ino, 205462306a36Sopenharmony_ci le32_to_cpu(s->here->e_hash), 205562306a36Sopenharmony_ci &ea_inode); 205662306a36Sopenharmony_ci if (error) { 205762306a36Sopenharmony_ci ea_inode = NULL; 205862306a36Sopenharmony_ci goto cleanup; 205962306a36Sopenharmony_ci } 206062306a36Sopenharmony_ci } 206162306a36Sopenharmony_ci 206262306a36Sopenharmony_ciinserted: 206362306a36Sopenharmony_ci if (!IS_LAST_ENTRY(s->first)) { 206462306a36Sopenharmony_ci new_bh = ext4_xattr_block_cache_find(inode, header(s->base), 206562306a36Sopenharmony_ci &ce); 206662306a36Sopenharmony_ci if (new_bh) { 206762306a36Sopenharmony_ci /* We found an identical block in the cache. */ 206862306a36Sopenharmony_ci if (new_bh == bs->bh) 206962306a36Sopenharmony_ci ea_bdebug(new_bh, "keeping"); 207062306a36Sopenharmony_ci else { 207162306a36Sopenharmony_ci u32 ref; 207262306a36Sopenharmony_ci 207362306a36Sopenharmony_ci#ifdef EXT4_XATTR_DEBUG 207462306a36Sopenharmony_ci WARN_ON_ONCE(dquot_initialize_needed(inode)); 207562306a36Sopenharmony_ci#endif 207662306a36Sopenharmony_ci /* The old block is released after updating 207762306a36Sopenharmony_ci the inode. */ 207862306a36Sopenharmony_ci error = dquot_alloc_block(inode, 207962306a36Sopenharmony_ci EXT4_C2B(EXT4_SB(sb), 1)); 208062306a36Sopenharmony_ci if (error) 208162306a36Sopenharmony_ci goto cleanup; 208262306a36Sopenharmony_ci BUFFER_TRACE(new_bh, "get_write_access"); 208362306a36Sopenharmony_ci error = ext4_journal_get_write_access( 208462306a36Sopenharmony_ci handle, sb, new_bh, 208562306a36Sopenharmony_ci EXT4_JTR_NONE); 208662306a36Sopenharmony_ci if (error) 208762306a36Sopenharmony_ci goto cleanup_dquot; 208862306a36Sopenharmony_ci lock_buffer(new_bh); 208962306a36Sopenharmony_ci /* 209062306a36Sopenharmony_ci * We have to be careful about races with 209162306a36Sopenharmony_ci * adding references to xattr block. Once we 209262306a36Sopenharmony_ci * hold buffer lock xattr block's state is 209362306a36Sopenharmony_ci * stable so we can check the additional 209462306a36Sopenharmony_ci * reference fits. 209562306a36Sopenharmony_ci */ 209662306a36Sopenharmony_ci ref = le32_to_cpu(BHDR(new_bh)->h_refcount) + 1; 209762306a36Sopenharmony_ci if (ref > EXT4_XATTR_REFCOUNT_MAX) { 209862306a36Sopenharmony_ci /* 209962306a36Sopenharmony_ci * Undo everything and check mbcache 210062306a36Sopenharmony_ci * again. 210162306a36Sopenharmony_ci */ 210262306a36Sopenharmony_ci unlock_buffer(new_bh); 210362306a36Sopenharmony_ci dquot_free_block(inode, 210462306a36Sopenharmony_ci EXT4_C2B(EXT4_SB(sb), 210562306a36Sopenharmony_ci 1)); 210662306a36Sopenharmony_ci brelse(new_bh); 210762306a36Sopenharmony_ci mb_cache_entry_put(ea_block_cache, ce); 210862306a36Sopenharmony_ci ce = NULL; 210962306a36Sopenharmony_ci new_bh = NULL; 211062306a36Sopenharmony_ci goto inserted; 211162306a36Sopenharmony_ci } 211262306a36Sopenharmony_ci BHDR(new_bh)->h_refcount = cpu_to_le32(ref); 211362306a36Sopenharmony_ci if (ref == EXT4_XATTR_REFCOUNT_MAX) 211462306a36Sopenharmony_ci clear_bit(MBE_REUSABLE_B, &ce->e_flags); 211562306a36Sopenharmony_ci ea_bdebug(new_bh, "reusing; refcount now=%d", 211662306a36Sopenharmony_ci ref); 211762306a36Sopenharmony_ci ext4_xattr_block_csum_set(inode, new_bh); 211862306a36Sopenharmony_ci unlock_buffer(new_bh); 211962306a36Sopenharmony_ci error = ext4_handle_dirty_metadata(handle, 212062306a36Sopenharmony_ci inode, 212162306a36Sopenharmony_ci new_bh); 212262306a36Sopenharmony_ci if (error) 212362306a36Sopenharmony_ci goto cleanup_dquot; 212462306a36Sopenharmony_ci } 212562306a36Sopenharmony_ci mb_cache_entry_touch(ea_block_cache, ce); 212662306a36Sopenharmony_ci mb_cache_entry_put(ea_block_cache, ce); 212762306a36Sopenharmony_ci ce = NULL; 212862306a36Sopenharmony_ci } else if (bs->bh && s->base == bs->bh->b_data) { 212962306a36Sopenharmony_ci /* We were modifying this block in-place. */ 213062306a36Sopenharmony_ci ea_bdebug(bs->bh, "keeping this block"); 213162306a36Sopenharmony_ci ext4_xattr_block_cache_insert(ea_block_cache, bs->bh); 213262306a36Sopenharmony_ci new_bh = bs->bh; 213362306a36Sopenharmony_ci get_bh(new_bh); 213462306a36Sopenharmony_ci } else { 213562306a36Sopenharmony_ci /* We need to allocate a new block */ 213662306a36Sopenharmony_ci ext4_fsblk_t goal, block; 213762306a36Sopenharmony_ci 213862306a36Sopenharmony_ci#ifdef EXT4_XATTR_DEBUG 213962306a36Sopenharmony_ci WARN_ON_ONCE(dquot_initialize_needed(inode)); 214062306a36Sopenharmony_ci#endif 214162306a36Sopenharmony_ci goal = ext4_group_first_block_no(sb, 214262306a36Sopenharmony_ci EXT4_I(inode)->i_block_group); 214362306a36Sopenharmony_ci block = ext4_new_meta_blocks(handle, inode, goal, 0, 214462306a36Sopenharmony_ci NULL, &error); 214562306a36Sopenharmony_ci if (error) 214662306a36Sopenharmony_ci goto cleanup; 214762306a36Sopenharmony_ci 214862306a36Sopenharmony_ci ea_idebug(inode, "creating block %llu", 214962306a36Sopenharmony_ci (unsigned long long)block); 215062306a36Sopenharmony_ci 215162306a36Sopenharmony_ci new_bh = sb_getblk(sb, block); 215262306a36Sopenharmony_ci if (unlikely(!new_bh)) { 215362306a36Sopenharmony_ci error = -ENOMEM; 215462306a36Sopenharmony_cigetblk_failed: 215562306a36Sopenharmony_ci ext4_free_blocks(handle, inode, NULL, block, 1, 215662306a36Sopenharmony_ci EXT4_FREE_BLOCKS_METADATA); 215762306a36Sopenharmony_ci goto cleanup; 215862306a36Sopenharmony_ci } 215962306a36Sopenharmony_ci error = ext4_xattr_inode_inc_ref_all(handle, inode, 216062306a36Sopenharmony_ci ENTRY(header(s->base)+1)); 216162306a36Sopenharmony_ci if (error) 216262306a36Sopenharmony_ci goto getblk_failed; 216362306a36Sopenharmony_ci if (ea_inode) { 216462306a36Sopenharmony_ci /* Drop the extra ref on ea_inode. */ 216562306a36Sopenharmony_ci error = ext4_xattr_inode_dec_ref(handle, 216662306a36Sopenharmony_ci ea_inode); 216762306a36Sopenharmony_ci if (error) 216862306a36Sopenharmony_ci ext4_warning_inode(ea_inode, 216962306a36Sopenharmony_ci "dec ref error=%d", 217062306a36Sopenharmony_ci error); 217162306a36Sopenharmony_ci iput(ea_inode); 217262306a36Sopenharmony_ci ea_inode = NULL; 217362306a36Sopenharmony_ci } 217462306a36Sopenharmony_ci 217562306a36Sopenharmony_ci lock_buffer(new_bh); 217662306a36Sopenharmony_ci error = ext4_journal_get_create_access(handle, sb, 217762306a36Sopenharmony_ci new_bh, EXT4_JTR_NONE); 217862306a36Sopenharmony_ci if (error) { 217962306a36Sopenharmony_ci unlock_buffer(new_bh); 218062306a36Sopenharmony_ci error = -EIO; 218162306a36Sopenharmony_ci goto getblk_failed; 218262306a36Sopenharmony_ci } 218362306a36Sopenharmony_ci memcpy(new_bh->b_data, s->base, new_bh->b_size); 218462306a36Sopenharmony_ci ext4_xattr_block_csum_set(inode, new_bh); 218562306a36Sopenharmony_ci set_buffer_uptodate(new_bh); 218662306a36Sopenharmony_ci unlock_buffer(new_bh); 218762306a36Sopenharmony_ci ext4_xattr_block_cache_insert(ea_block_cache, new_bh); 218862306a36Sopenharmony_ci error = ext4_handle_dirty_metadata(handle, inode, 218962306a36Sopenharmony_ci new_bh); 219062306a36Sopenharmony_ci if (error) 219162306a36Sopenharmony_ci goto cleanup; 219262306a36Sopenharmony_ci } 219362306a36Sopenharmony_ci } 219462306a36Sopenharmony_ci 219562306a36Sopenharmony_ci if (old_ea_inode_quota) 219662306a36Sopenharmony_ci ext4_xattr_inode_free_quota(inode, NULL, old_ea_inode_quota); 219762306a36Sopenharmony_ci 219862306a36Sopenharmony_ci /* Update the inode. */ 219962306a36Sopenharmony_ci EXT4_I(inode)->i_file_acl = new_bh ? new_bh->b_blocknr : 0; 220062306a36Sopenharmony_ci 220162306a36Sopenharmony_ci /* Drop the previous xattr block. */ 220262306a36Sopenharmony_ci if (bs->bh && bs->bh != new_bh) { 220362306a36Sopenharmony_ci struct ext4_xattr_inode_array *ea_inode_array = NULL; 220462306a36Sopenharmony_ci 220562306a36Sopenharmony_ci ext4_xattr_release_block(handle, inode, bs->bh, 220662306a36Sopenharmony_ci &ea_inode_array, 220762306a36Sopenharmony_ci 0 /* extra_credits */); 220862306a36Sopenharmony_ci ext4_xattr_inode_array_free(ea_inode_array); 220962306a36Sopenharmony_ci } 221062306a36Sopenharmony_ci error = 0; 221162306a36Sopenharmony_ci 221262306a36Sopenharmony_cicleanup: 221362306a36Sopenharmony_ci if (ea_inode) { 221462306a36Sopenharmony_ci int error2; 221562306a36Sopenharmony_ci 221662306a36Sopenharmony_ci error2 = ext4_xattr_inode_dec_ref(handle, ea_inode); 221762306a36Sopenharmony_ci if (error2) 221862306a36Sopenharmony_ci ext4_warning_inode(ea_inode, "dec ref error=%d", 221962306a36Sopenharmony_ci error2); 222062306a36Sopenharmony_ci 222162306a36Sopenharmony_ci /* If there was an error, revert the quota charge. */ 222262306a36Sopenharmony_ci if (error) 222362306a36Sopenharmony_ci ext4_xattr_inode_free_quota(inode, ea_inode, 222462306a36Sopenharmony_ci i_size_read(ea_inode)); 222562306a36Sopenharmony_ci iput(ea_inode); 222662306a36Sopenharmony_ci } 222762306a36Sopenharmony_ci if (ce) 222862306a36Sopenharmony_ci mb_cache_entry_put(ea_block_cache, ce); 222962306a36Sopenharmony_ci brelse(new_bh); 223062306a36Sopenharmony_ci if (!(bs->bh && s->base == bs->bh->b_data)) 223162306a36Sopenharmony_ci kfree(s->base); 223262306a36Sopenharmony_ci 223362306a36Sopenharmony_ci return error; 223462306a36Sopenharmony_ci 223562306a36Sopenharmony_cicleanup_dquot: 223662306a36Sopenharmony_ci dquot_free_block(inode, EXT4_C2B(EXT4_SB(sb), 1)); 223762306a36Sopenharmony_ci goto cleanup; 223862306a36Sopenharmony_ci 223962306a36Sopenharmony_cibad_block: 224062306a36Sopenharmony_ci EXT4_ERROR_INODE(inode, "bad block %llu", 224162306a36Sopenharmony_ci EXT4_I(inode)->i_file_acl); 224262306a36Sopenharmony_ci goto cleanup; 224362306a36Sopenharmony_ci 224462306a36Sopenharmony_ci#undef header 224562306a36Sopenharmony_ci} 224662306a36Sopenharmony_ci 224762306a36Sopenharmony_ciint ext4_xattr_ibody_find(struct inode *inode, struct ext4_xattr_info *i, 224862306a36Sopenharmony_ci struct ext4_xattr_ibody_find *is) 224962306a36Sopenharmony_ci{ 225062306a36Sopenharmony_ci struct ext4_xattr_ibody_header *header; 225162306a36Sopenharmony_ci struct ext4_inode *raw_inode; 225262306a36Sopenharmony_ci int error; 225362306a36Sopenharmony_ci 225462306a36Sopenharmony_ci if (!EXT4_INODE_HAS_XATTR_SPACE(inode)) 225562306a36Sopenharmony_ci return 0; 225662306a36Sopenharmony_ci 225762306a36Sopenharmony_ci raw_inode = ext4_raw_inode(&is->iloc); 225862306a36Sopenharmony_ci header = IHDR(inode, raw_inode); 225962306a36Sopenharmony_ci is->s.base = is->s.first = IFIRST(header); 226062306a36Sopenharmony_ci is->s.here = is->s.first; 226162306a36Sopenharmony_ci is->s.end = (void *)raw_inode + EXT4_SB(inode->i_sb)->s_inode_size; 226262306a36Sopenharmony_ci if (ext4_test_inode_state(inode, EXT4_STATE_XATTR)) { 226362306a36Sopenharmony_ci error = xattr_check_inode(inode, header, is->s.end); 226462306a36Sopenharmony_ci if (error) 226562306a36Sopenharmony_ci return error; 226662306a36Sopenharmony_ci /* Find the named attribute. */ 226762306a36Sopenharmony_ci error = xattr_find_entry(inode, &is->s.here, is->s.end, 226862306a36Sopenharmony_ci i->name_index, i->name, 0); 226962306a36Sopenharmony_ci if (error && error != -ENODATA) 227062306a36Sopenharmony_ci return error; 227162306a36Sopenharmony_ci is->s.not_found = error; 227262306a36Sopenharmony_ci } 227362306a36Sopenharmony_ci return 0; 227462306a36Sopenharmony_ci} 227562306a36Sopenharmony_ci 227662306a36Sopenharmony_ciint ext4_xattr_ibody_set(handle_t *handle, struct inode *inode, 227762306a36Sopenharmony_ci struct ext4_xattr_info *i, 227862306a36Sopenharmony_ci struct ext4_xattr_ibody_find *is) 227962306a36Sopenharmony_ci{ 228062306a36Sopenharmony_ci struct ext4_xattr_ibody_header *header; 228162306a36Sopenharmony_ci struct ext4_xattr_search *s = &is->s; 228262306a36Sopenharmony_ci int error; 228362306a36Sopenharmony_ci 228462306a36Sopenharmony_ci if (!EXT4_INODE_HAS_XATTR_SPACE(inode)) 228562306a36Sopenharmony_ci return -ENOSPC; 228662306a36Sopenharmony_ci 228762306a36Sopenharmony_ci error = ext4_xattr_set_entry(i, s, handle, inode, false /* is_block */); 228862306a36Sopenharmony_ci if (error) 228962306a36Sopenharmony_ci return error; 229062306a36Sopenharmony_ci header = IHDR(inode, ext4_raw_inode(&is->iloc)); 229162306a36Sopenharmony_ci if (!IS_LAST_ENTRY(s->first)) { 229262306a36Sopenharmony_ci header->h_magic = cpu_to_le32(EXT4_XATTR_MAGIC); 229362306a36Sopenharmony_ci ext4_set_inode_state(inode, EXT4_STATE_XATTR); 229462306a36Sopenharmony_ci } else { 229562306a36Sopenharmony_ci header->h_magic = cpu_to_le32(0); 229662306a36Sopenharmony_ci ext4_clear_inode_state(inode, EXT4_STATE_XATTR); 229762306a36Sopenharmony_ci } 229862306a36Sopenharmony_ci return 0; 229962306a36Sopenharmony_ci} 230062306a36Sopenharmony_ci 230162306a36Sopenharmony_cistatic int ext4_xattr_value_same(struct ext4_xattr_search *s, 230262306a36Sopenharmony_ci struct ext4_xattr_info *i) 230362306a36Sopenharmony_ci{ 230462306a36Sopenharmony_ci void *value; 230562306a36Sopenharmony_ci 230662306a36Sopenharmony_ci /* When e_value_inum is set the value is stored externally. */ 230762306a36Sopenharmony_ci if (s->here->e_value_inum) 230862306a36Sopenharmony_ci return 0; 230962306a36Sopenharmony_ci if (le32_to_cpu(s->here->e_value_size) != i->value_len) 231062306a36Sopenharmony_ci return 0; 231162306a36Sopenharmony_ci value = ((void *)s->base) + le16_to_cpu(s->here->e_value_offs); 231262306a36Sopenharmony_ci return !memcmp(value, i->value, i->value_len); 231362306a36Sopenharmony_ci} 231462306a36Sopenharmony_ci 231562306a36Sopenharmony_cistatic struct buffer_head *ext4_xattr_get_block(struct inode *inode) 231662306a36Sopenharmony_ci{ 231762306a36Sopenharmony_ci struct buffer_head *bh; 231862306a36Sopenharmony_ci int error; 231962306a36Sopenharmony_ci 232062306a36Sopenharmony_ci if (!EXT4_I(inode)->i_file_acl) 232162306a36Sopenharmony_ci return NULL; 232262306a36Sopenharmony_ci bh = ext4_sb_bread(inode->i_sb, EXT4_I(inode)->i_file_acl, REQ_PRIO); 232362306a36Sopenharmony_ci if (IS_ERR(bh)) 232462306a36Sopenharmony_ci return bh; 232562306a36Sopenharmony_ci error = ext4_xattr_check_block(inode, bh); 232662306a36Sopenharmony_ci if (error) { 232762306a36Sopenharmony_ci brelse(bh); 232862306a36Sopenharmony_ci return ERR_PTR(error); 232962306a36Sopenharmony_ci } 233062306a36Sopenharmony_ci return bh; 233162306a36Sopenharmony_ci} 233262306a36Sopenharmony_ci 233362306a36Sopenharmony_ci/* 233462306a36Sopenharmony_ci * ext4_xattr_set_handle() 233562306a36Sopenharmony_ci * 233662306a36Sopenharmony_ci * Create, replace or remove an extended attribute for this inode. Value 233762306a36Sopenharmony_ci * is NULL to remove an existing extended attribute, and non-NULL to 233862306a36Sopenharmony_ci * either replace an existing extended attribute, or create a new extended 233962306a36Sopenharmony_ci * attribute. The flags XATTR_REPLACE and XATTR_CREATE 234062306a36Sopenharmony_ci * specify that an extended attribute must exist and must not exist 234162306a36Sopenharmony_ci * previous to the call, respectively. 234262306a36Sopenharmony_ci * 234362306a36Sopenharmony_ci * Returns 0, or a negative error number on failure. 234462306a36Sopenharmony_ci */ 234562306a36Sopenharmony_ciint 234662306a36Sopenharmony_ciext4_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index, 234762306a36Sopenharmony_ci const char *name, const void *value, size_t value_len, 234862306a36Sopenharmony_ci int flags) 234962306a36Sopenharmony_ci{ 235062306a36Sopenharmony_ci struct ext4_xattr_info i = { 235162306a36Sopenharmony_ci .name_index = name_index, 235262306a36Sopenharmony_ci .name = name, 235362306a36Sopenharmony_ci .value = value, 235462306a36Sopenharmony_ci .value_len = value_len, 235562306a36Sopenharmony_ci .in_inode = 0, 235662306a36Sopenharmony_ci }; 235762306a36Sopenharmony_ci struct ext4_xattr_ibody_find is = { 235862306a36Sopenharmony_ci .s = { .not_found = -ENODATA, }, 235962306a36Sopenharmony_ci }; 236062306a36Sopenharmony_ci struct ext4_xattr_block_find bs = { 236162306a36Sopenharmony_ci .s = { .not_found = -ENODATA, }, 236262306a36Sopenharmony_ci }; 236362306a36Sopenharmony_ci int no_expand; 236462306a36Sopenharmony_ci int error; 236562306a36Sopenharmony_ci 236662306a36Sopenharmony_ci if (!name) 236762306a36Sopenharmony_ci return -EINVAL; 236862306a36Sopenharmony_ci if (strlen(name) > 255) 236962306a36Sopenharmony_ci return -ERANGE; 237062306a36Sopenharmony_ci 237162306a36Sopenharmony_ci ext4_write_lock_xattr(inode, &no_expand); 237262306a36Sopenharmony_ci 237362306a36Sopenharmony_ci /* Check journal credits under write lock. */ 237462306a36Sopenharmony_ci if (ext4_handle_valid(handle)) { 237562306a36Sopenharmony_ci struct buffer_head *bh; 237662306a36Sopenharmony_ci int credits; 237762306a36Sopenharmony_ci 237862306a36Sopenharmony_ci bh = ext4_xattr_get_block(inode); 237962306a36Sopenharmony_ci if (IS_ERR(bh)) { 238062306a36Sopenharmony_ci error = PTR_ERR(bh); 238162306a36Sopenharmony_ci goto cleanup; 238262306a36Sopenharmony_ci } 238362306a36Sopenharmony_ci 238462306a36Sopenharmony_ci credits = __ext4_xattr_set_credits(inode->i_sb, inode, bh, 238562306a36Sopenharmony_ci value_len, 238662306a36Sopenharmony_ci flags & XATTR_CREATE); 238762306a36Sopenharmony_ci brelse(bh); 238862306a36Sopenharmony_ci 238962306a36Sopenharmony_ci if (jbd2_handle_buffer_credits(handle) < credits) { 239062306a36Sopenharmony_ci error = -ENOSPC; 239162306a36Sopenharmony_ci goto cleanup; 239262306a36Sopenharmony_ci } 239362306a36Sopenharmony_ci WARN_ON_ONCE(!(current->flags & PF_MEMALLOC_NOFS)); 239462306a36Sopenharmony_ci } 239562306a36Sopenharmony_ci 239662306a36Sopenharmony_ci error = ext4_reserve_inode_write(handle, inode, &is.iloc); 239762306a36Sopenharmony_ci if (error) 239862306a36Sopenharmony_ci goto cleanup; 239962306a36Sopenharmony_ci 240062306a36Sopenharmony_ci if (ext4_test_inode_state(inode, EXT4_STATE_NEW)) { 240162306a36Sopenharmony_ci struct ext4_inode *raw_inode = ext4_raw_inode(&is.iloc); 240262306a36Sopenharmony_ci memset(raw_inode, 0, EXT4_SB(inode->i_sb)->s_inode_size); 240362306a36Sopenharmony_ci ext4_clear_inode_state(inode, EXT4_STATE_NEW); 240462306a36Sopenharmony_ci } 240562306a36Sopenharmony_ci 240662306a36Sopenharmony_ci error = ext4_xattr_ibody_find(inode, &i, &is); 240762306a36Sopenharmony_ci if (error) 240862306a36Sopenharmony_ci goto cleanup; 240962306a36Sopenharmony_ci if (is.s.not_found) 241062306a36Sopenharmony_ci error = ext4_xattr_block_find(inode, &i, &bs); 241162306a36Sopenharmony_ci if (error) 241262306a36Sopenharmony_ci goto cleanup; 241362306a36Sopenharmony_ci if (is.s.not_found && bs.s.not_found) { 241462306a36Sopenharmony_ci error = -ENODATA; 241562306a36Sopenharmony_ci if (flags & XATTR_REPLACE) 241662306a36Sopenharmony_ci goto cleanup; 241762306a36Sopenharmony_ci error = 0; 241862306a36Sopenharmony_ci if (!value) 241962306a36Sopenharmony_ci goto cleanup; 242062306a36Sopenharmony_ci } else { 242162306a36Sopenharmony_ci error = -EEXIST; 242262306a36Sopenharmony_ci if (flags & XATTR_CREATE) 242362306a36Sopenharmony_ci goto cleanup; 242462306a36Sopenharmony_ci } 242562306a36Sopenharmony_ci 242662306a36Sopenharmony_ci if (!value) { 242762306a36Sopenharmony_ci if (!is.s.not_found) 242862306a36Sopenharmony_ci error = ext4_xattr_ibody_set(handle, inode, &i, &is); 242962306a36Sopenharmony_ci else if (!bs.s.not_found) 243062306a36Sopenharmony_ci error = ext4_xattr_block_set(handle, inode, &i, &bs); 243162306a36Sopenharmony_ci } else { 243262306a36Sopenharmony_ci error = 0; 243362306a36Sopenharmony_ci /* Xattr value did not change? Save us some work and bail out */ 243462306a36Sopenharmony_ci if (!is.s.not_found && ext4_xattr_value_same(&is.s, &i)) 243562306a36Sopenharmony_ci goto cleanup; 243662306a36Sopenharmony_ci if (!bs.s.not_found && ext4_xattr_value_same(&bs.s, &i)) 243762306a36Sopenharmony_ci goto cleanup; 243862306a36Sopenharmony_ci 243962306a36Sopenharmony_ci if (ext4_has_feature_ea_inode(inode->i_sb) && 244062306a36Sopenharmony_ci (EXT4_XATTR_SIZE(i.value_len) > 244162306a36Sopenharmony_ci EXT4_XATTR_MIN_LARGE_EA_SIZE(inode->i_sb->s_blocksize))) 244262306a36Sopenharmony_ci i.in_inode = 1; 244362306a36Sopenharmony_ciretry_inode: 244462306a36Sopenharmony_ci error = ext4_xattr_ibody_set(handle, inode, &i, &is); 244562306a36Sopenharmony_ci if (!error && !bs.s.not_found) { 244662306a36Sopenharmony_ci i.value = NULL; 244762306a36Sopenharmony_ci error = ext4_xattr_block_set(handle, inode, &i, &bs); 244862306a36Sopenharmony_ci } else if (error == -ENOSPC) { 244962306a36Sopenharmony_ci if (EXT4_I(inode)->i_file_acl && !bs.s.base) { 245062306a36Sopenharmony_ci brelse(bs.bh); 245162306a36Sopenharmony_ci bs.bh = NULL; 245262306a36Sopenharmony_ci error = ext4_xattr_block_find(inode, &i, &bs); 245362306a36Sopenharmony_ci if (error) 245462306a36Sopenharmony_ci goto cleanup; 245562306a36Sopenharmony_ci } 245662306a36Sopenharmony_ci error = ext4_xattr_block_set(handle, inode, &i, &bs); 245762306a36Sopenharmony_ci if (!error && !is.s.not_found) { 245862306a36Sopenharmony_ci i.value = NULL; 245962306a36Sopenharmony_ci error = ext4_xattr_ibody_set(handle, inode, &i, 246062306a36Sopenharmony_ci &is); 246162306a36Sopenharmony_ci } else if (error == -ENOSPC) { 246262306a36Sopenharmony_ci /* 246362306a36Sopenharmony_ci * Xattr does not fit in the block, store at 246462306a36Sopenharmony_ci * external inode if possible. 246562306a36Sopenharmony_ci */ 246662306a36Sopenharmony_ci if (ext4_has_feature_ea_inode(inode->i_sb) && 246762306a36Sopenharmony_ci i.value_len && !i.in_inode) { 246862306a36Sopenharmony_ci i.in_inode = 1; 246962306a36Sopenharmony_ci goto retry_inode; 247062306a36Sopenharmony_ci } 247162306a36Sopenharmony_ci } 247262306a36Sopenharmony_ci } 247362306a36Sopenharmony_ci } 247462306a36Sopenharmony_ci if (!error) { 247562306a36Sopenharmony_ci ext4_xattr_update_super_block(handle, inode->i_sb); 247662306a36Sopenharmony_ci inode_set_ctime_current(inode); 247762306a36Sopenharmony_ci inode_inc_iversion(inode); 247862306a36Sopenharmony_ci if (!value) 247962306a36Sopenharmony_ci no_expand = 0; 248062306a36Sopenharmony_ci error = ext4_mark_iloc_dirty(handle, inode, &is.iloc); 248162306a36Sopenharmony_ci /* 248262306a36Sopenharmony_ci * The bh is consumed by ext4_mark_iloc_dirty, even with 248362306a36Sopenharmony_ci * error != 0. 248462306a36Sopenharmony_ci */ 248562306a36Sopenharmony_ci is.iloc.bh = NULL; 248662306a36Sopenharmony_ci if (IS_SYNC(inode)) 248762306a36Sopenharmony_ci ext4_handle_sync(handle); 248862306a36Sopenharmony_ci } 248962306a36Sopenharmony_ci ext4_fc_mark_ineligible(inode->i_sb, EXT4_FC_REASON_XATTR, handle); 249062306a36Sopenharmony_ci 249162306a36Sopenharmony_cicleanup: 249262306a36Sopenharmony_ci brelse(is.iloc.bh); 249362306a36Sopenharmony_ci brelse(bs.bh); 249462306a36Sopenharmony_ci ext4_write_unlock_xattr(inode, &no_expand); 249562306a36Sopenharmony_ci return error; 249662306a36Sopenharmony_ci} 249762306a36Sopenharmony_ci 249862306a36Sopenharmony_ciint ext4_xattr_set_credits(struct inode *inode, size_t value_len, 249962306a36Sopenharmony_ci bool is_create, int *credits) 250062306a36Sopenharmony_ci{ 250162306a36Sopenharmony_ci struct buffer_head *bh; 250262306a36Sopenharmony_ci int err; 250362306a36Sopenharmony_ci 250462306a36Sopenharmony_ci *credits = 0; 250562306a36Sopenharmony_ci 250662306a36Sopenharmony_ci if (!EXT4_SB(inode->i_sb)->s_journal) 250762306a36Sopenharmony_ci return 0; 250862306a36Sopenharmony_ci 250962306a36Sopenharmony_ci down_read(&EXT4_I(inode)->xattr_sem); 251062306a36Sopenharmony_ci 251162306a36Sopenharmony_ci bh = ext4_xattr_get_block(inode); 251262306a36Sopenharmony_ci if (IS_ERR(bh)) { 251362306a36Sopenharmony_ci err = PTR_ERR(bh); 251462306a36Sopenharmony_ci } else { 251562306a36Sopenharmony_ci *credits = __ext4_xattr_set_credits(inode->i_sb, inode, bh, 251662306a36Sopenharmony_ci value_len, is_create); 251762306a36Sopenharmony_ci brelse(bh); 251862306a36Sopenharmony_ci err = 0; 251962306a36Sopenharmony_ci } 252062306a36Sopenharmony_ci 252162306a36Sopenharmony_ci up_read(&EXT4_I(inode)->xattr_sem); 252262306a36Sopenharmony_ci return err; 252362306a36Sopenharmony_ci} 252462306a36Sopenharmony_ci 252562306a36Sopenharmony_ci/* 252662306a36Sopenharmony_ci * ext4_xattr_set() 252762306a36Sopenharmony_ci * 252862306a36Sopenharmony_ci * Like ext4_xattr_set_handle, but start from an inode. This extended 252962306a36Sopenharmony_ci * attribute modification is a filesystem transaction by itself. 253062306a36Sopenharmony_ci * 253162306a36Sopenharmony_ci * Returns 0, or a negative error number on failure. 253262306a36Sopenharmony_ci */ 253362306a36Sopenharmony_ciint 253462306a36Sopenharmony_ciext4_xattr_set(struct inode *inode, int name_index, const char *name, 253562306a36Sopenharmony_ci const void *value, size_t value_len, int flags) 253662306a36Sopenharmony_ci{ 253762306a36Sopenharmony_ci handle_t *handle; 253862306a36Sopenharmony_ci struct super_block *sb = inode->i_sb; 253962306a36Sopenharmony_ci int error, retries = 0; 254062306a36Sopenharmony_ci int credits; 254162306a36Sopenharmony_ci 254262306a36Sopenharmony_ci error = dquot_initialize(inode); 254362306a36Sopenharmony_ci if (error) 254462306a36Sopenharmony_ci return error; 254562306a36Sopenharmony_ci 254662306a36Sopenharmony_ciretry: 254762306a36Sopenharmony_ci error = ext4_xattr_set_credits(inode, value_len, flags & XATTR_CREATE, 254862306a36Sopenharmony_ci &credits); 254962306a36Sopenharmony_ci if (error) 255062306a36Sopenharmony_ci return error; 255162306a36Sopenharmony_ci 255262306a36Sopenharmony_ci handle = ext4_journal_start(inode, EXT4_HT_XATTR, credits); 255362306a36Sopenharmony_ci if (IS_ERR(handle)) { 255462306a36Sopenharmony_ci error = PTR_ERR(handle); 255562306a36Sopenharmony_ci } else { 255662306a36Sopenharmony_ci int error2; 255762306a36Sopenharmony_ci 255862306a36Sopenharmony_ci error = ext4_xattr_set_handle(handle, inode, name_index, name, 255962306a36Sopenharmony_ci value, value_len, flags); 256062306a36Sopenharmony_ci error2 = ext4_journal_stop(handle); 256162306a36Sopenharmony_ci if (error == -ENOSPC && 256262306a36Sopenharmony_ci ext4_should_retry_alloc(sb, &retries)) 256362306a36Sopenharmony_ci goto retry; 256462306a36Sopenharmony_ci if (error == 0) 256562306a36Sopenharmony_ci error = error2; 256662306a36Sopenharmony_ci } 256762306a36Sopenharmony_ci ext4_fc_mark_ineligible(inode->i_sb, EXT4_FC_REASON_XATTR, NULL); 256862306a36Sopenharmony_ci 256962306a36Sopenharmony_ci return error; 257062306a36Sopenharmony_ci} 257162306a36Sopenharmony_ci 257262306a36Sopenharmony_ci/* 257362306a36Sopenharmony_ci * Shift the EA entries in the inode to create space for the increased 257462306a36Sopenharmony_ci * i_extra_isize. 257562306a36Sopenharmony_ci */ 257662306a36Sopenharmony_cistatic void ext4_xattr_shift_entries(struct ext4_xattr_entry *entry, 257762306a36Sopenharmony_ci int value_offs_shift, void *to, 257862306a36Sopenharmony_ci void *from, size_t n) 257962306a36Sopenharmony_ci{ 258062306a36Sopenharmony_ci struct ext4_xattr_entry *last = entry; 258162306a36Sopenharmony_ci int new_offs; 258262306a36Sopenharmony_ci 258362306a36Sopenharmony_ci /* We always shift xattr headers further thus offsets get lower */ 258462306a36Sopenharmony_ci BUG_ON(value_offs_shift > 0); 258562306a36Sopenharmony_ci 258662306a36Sopenharmony_ci /* Adjust the value offsets of the entries */ 258762306a36Sopenharmony_ci for (; !IS_LAST_ENTRY(last); last = EXT4_XATTR_NEXT(last)) { 258862306a36Sopenharmony_ci if (!last->e_value_inum && last->e_value_size) { 258962306a36Sopenharmony_ci new_offs = le16_to_cpu(last->e_value_offs) + 259062306a36Sopenharmony_ci value_offs_shift; 259162306a36Sopenharmony_ci last->e_value_offs = cpu_to_le16(new_offs); 259262306a36Sopenharmony_ci } 259362306a36Sopenharmony_ci } 259462306a36Sopenharmony_ci /* Shift the entries by n bytes */ 259562306a36Sopenharmony_ci memmove(to, from, n); 259662306a36Sopenharmony_ci} 259762306a36Sopenharmony_ci 259862306a36Sopenharmony_ci/* 259962306a36Sopenharmony_ci * Move xattr pointed to by 'entry' from inode into external xattr block 260062306a36Sopenharmony_ci */ 260162306a36Sopenharmony_cistatic int ext4_xattr_move_to_block(handle_t *handle, struct inode *inode, 260262306a36Sopenharmony_ci struct ext4_inode *raw_inode, 260362306a36Sopenharmony_ci struct ext4_xattr_entry *entry) 260462306a36Sopenharmony_ci{ 260562306a36Sopenharmony_ci struct ext4_xattr_ibody_find *is = NULL; 260662306a36Sopenharmony_ci struct ext4_xattr_block_find *bs = NULL; 260762306a36Sopenharmony_ci char *buffer = NULL, *b_entry_name = NULL; 260862306a36Sopenharmony_ci size_t value_size = le32_to_cpu(entry->e_value_size); 260962306a36Sopenharmony_ci struct ext4_xattr_info i = { 261062306a36Sopenharmony_ci .value = NULL, 261162306a36Sopenharmony_ci .value_len = 0, 261262306a36Sopenharmony_ci .name_index = entry->e_name_index, 261362306a36Sopenharmony_ci .in_inode = !!entry->e_value_inum, 261462306a36Sopenharmony_ci }; 261562306a36Sopenharmony_ci struct ext4_xattr_ibody_header *header = IHDR(inode, raw_inode); 261662306a36Sopenharmony_ci int needs_kvfree = 0; 261762306a36Sopenharmony_ci int error; 261862306a36Sopenharmony_ci 261962306a36Sopenharmony_ci is = kzalloc(sizeof(struct ext4_xattr_ibody_find), GFP_NOFS); 262062306a36Sopenharmony_ci bs = kzalloc(sizeof(struct ext4_xattr_block_find), GFP_NOFS); 262162306a36Sopenharmony_ci b_entry_name = kmalloc(entry->e_name_len + 1, GFP_NOFS); 262262306a36Sopenharmony_ci if (!is || !bs || !b_entry_name) { 262362306a36Sopenharmony_ci error = -ENOMEM; 262462306a36Sopenharmony_ci goto out; 262562306a36Sopenharmony_ci } 262662306a36Sopenharmony_ci 262762306a36Sopenharmony_ci is->s.not_found = -ENODATA; 262862306a36Sopenharmony_ci bs->s.not_found = -ENODATA; 262962306a36Sopenharmony_ci is->iloc.bh = NULL; 263062306a36Sopenharmony_ci bs->bh = NULL; 263162306a36Sopenharmony_ci 263262306a36Sopenharmony_ci /* Save the entry name and the entry value */ 263362306a36Sopenharmony_ci if (entry->e_value_inum) { 263462306a36Sopenharmony_ci buffer = kvmalloc(value_size, GFP_NOFS); 263562306a36Sopenharmony_ci if (!buffer) { 263662306a36Sopenharmony_ci error = -ENOMEM; 263762306a36Sopenharmony_ci goto out; 263862306a36Sopenharmony_ci } 263962306a36Sopenharmony_ci needs_kvfree = 1; 264062306a36Sopenharmony_ci error = ext4_xattr_inode_get(inode, entry, buffer, value_size); 264162306a36Sopenharmony_ci if (error) 264262306a36Sopenharmony_ci goto out; 264362306a36Sopenharmony_ci } else { 264462306a36Sopenharmony_ci size_t value_offs = le16_to_cpu(entry->e_value_offs); 264562306a36Sopenharmony_ci buffer = (void *)IFIRST(header) + value_offs; 264662306a36Sopenharmony_ci } 264762306a36Sopenharmony_ci 264862306a36Sopenharmony_ci memcpy(b_entry_name, entry->e_name, entry->e_name_len); 264962306a36Sopenharmony_ci b_entry_name[entry->e_name_len] = '\0'; 265062306a36Sopenharmony_ci i.name = b_entry_name; 265162306a36Sopenharmony_ci 265262306a36Sopenharmony_ci error = ext4_get_inode_loc(inode, &is->iloc); 265362306a36Sopenharmony_ci if (error) 265462306a36Sopenharmony_ci goto out; 265562306a36Sopenharmony_ci 265662306a36Sopenharmony_ci error = ext4_xattr_ibody_find(inode, &i, is); 265762306a36Sopenharmony_ci if (error) 265862306a36Sopenharmony_ci goto out; 265962306a36Sopenharmony_ci 266062306a36Sopenharmony_ci i.value = buffer; 266162306a36Sopenharmony_ci i.value_len = value_size; 266262306a36Sopenharmony_ci error = ext4_xattr_block_find(inode, &i, bs); 266362306a36Sopenharmony_ci if (error) 266462306a36Sopenharmony_ci goto out; 266562306a36Sopenharmony_ci 266662306a36Sopenharmony_ci /* Move ea entry from the inode into the block */ 266762306a36Sopenharmony_ci error = ext4_xattr_block_set(handle, inode, &i, bs); 266862306a36Sopenharmony_ci if (error) 266962306a36Sopenharmony_ci goto out; 267062306a36Sopenharmony_ci 267162306a36Sopenharmony_ci /* Remove the chosen entry from the inode */ 267262306a36Sopenharmony_ci i.value = NULL; 267362306a36Sopenharmony_ci i.value_len = 0; 267462306a36Sopenharmony_ci error = ext4_xattr_ibody_set(handle, inode, &i, is); 267562306a36Sopenharmony_ci 267662306a36Sopenharmony_ciout: 267762306a36Sopenharmony_ci kfree(b_entry_name); 267862306a36Sopenharmony_ci if (needs_kvfree && buffer) 267962306a36Sopenharmony_ci kvfree(buffer); 268062306a36Sopenharmony_ci if (is) 268162306a36Sopenharmony_ci brelse(is->iloc.bh); 268262306a36Sopenharmony_ci if (bs) 268362306a36Sopenharmony_ci brelse(bs->bh); 268462306a36Sopenharmony_ci kfree(is); 268562306a36Sopenharmony_ci kfree(bs); 268662306a36Sopenharmony_ci 268762306a36Sopenharmony_ci return error; 268862306a36Sopenharmony_ci} 268962306a36Sopenharmony_ci 269062306a36Sopenharmony_cistatic int ext4_xattr_make_inode_space(handle_t *handle, struct inode *inode, 269162306a36Sopenharmony_ci struct ext4_inode *raw_inode, 269262306a36Sopenharmony_ci int isize_diff, size_t ifree, 269362306a36Sopenharmony_ci size_t bfree, int *total_ino) 269462306a36Sopenharmony_ci{ 269562306a36Sopenharmony_ci struct ext4_xattr_ibody_header *header = IHDR(inode, raw_inode); 269662306a36Sopenharmony_ci struct ext4_xattr_entry *small_entry; 269762306a36Sopenharmony_ci struct ext4_xattr_entry *entry; 269862306a36Sopenharmony_ci struct ext4_xattr_entry *last; 269962306a36Sopenharmony_ci unsigned int entry_size; /* EA entry size */ 270062306a36Sopenharmony_ci unsigned int total_size; /* EA entry size + value size */ 270162306a36Sopenharmony_ci unsigned int min_total_size; 270262306a36Sopenharmony_ci int error; 270362306a36Sopenharmony_ci 270462306a36Sopenharmony_ci while (isize_diff > ifree) { 270562306a36Sopenharmony_ci entry = NULL; 270662306a36Sopenharmony_ci small_entry = NULL; 270762306a36Sopenharmony_ci min_total_size = ~0U; 270862306a36Sopenharmony_ci last = IFIRST(header); 270962306a36Sopenharmony_ci /* Find the entry best suited to be pushed into EA block */ 271062306a36Sopenharmony_ci for (; !IS_LAST_ENTRY(last); last = EXT4_XATTR_NEXT(last)) { 271162306a36Sopenharmony_ci /* never move system.data out of the inode */ 271262306a36Sopenharmony_ci if ((last->e_name_len == 4) && 271362306a36Sopenharmony_ci (last->e_name_index == EXT4_XATTR_INDEX_SYSTEM) && 271462306a36Sopenharmony_ci !memcmp(last->e_name, "data", 4)) 271562306a36Sopenharmony_ci continue; 271662306a36Sopenharmony_ci total_size = EXT4_XATTR_LEN(last->e_name_len); 271762306a36Sopenharmony_ci if (!last->e_value_inum) 271862306a36Sopenharmony_ci total_size += EXT4_XATTR_SIZE( 271962306a36Sopenharmony_ci le32_to_cpu(last->e_value_size)); 272062306a36Sopenharmony_ci if (total_size <= bfree && 272162306a36Sopenharmony_ci total_size < min_total_size) { 272262306a36Sopenharmony_ci if (total_size + ifree < isize_diff) { 272362306a36Sopenharmony_ci small_entry = last; 272462306a36Sopenharmony_ci } else { 272562306a36Sopenharmony_ci entry = last; 272662306a36Sopenharmony_ci min_total_size = total_size; 272762306a36Sopenharmony_ci } 272862306a36Sopenharmony_ci } 272962306a36Sopenharmony_ci } 273062306a36Sopenharmony_ci 273162306a36Sopenharmony_ci if (entry == NULL) { 273262306a36Sopenharmony_ci if (small_entry == NULL) 273362306a36Sopenharmony_ci return -ENOSPC; 273462306a36Sopenharmony_ci entry = small_entry; 273562306a36Sopenharmony_ci } 273662306a36Sopenharmony_ci 273762306a36Sopenharmony_ci entry_size = EXT4_XATTR_LEN(entry->e_name_len); 273862306a36Sopenharmony_ci total_size = entry_size; 273962306a36Sopenharmony_ci if (!entry->e_value_inum) 274062306a36Sopenharmony_ci total_size += EXT4_XATTR_SIZE( 274162306a36Sopenharmony_ci le32_to_cpu(entry->e_value_size)); 274262306a36Sopenharmony_ci error = ext4_xattr_move_to_block(handle, inode, raw_inode, 274362306a36Sopenharmony_ci entry); 274462306a36Sopenharmony_ci if (error) 274562306a36Sopenharmony_ci return error; 274662306a36Sopenharmony_ci 274762306a36Sopenharmony_ci *total_ino -= entry_size; 274862306a36Sopenharmony_ci ifree += total_size; 274962306a36Sopenharmony_ci bfree -= total_size; 275062306a36Sopenharmony_ci } 275162306a36Sopenharmony_ci 275262306a36Sopenharmony_ci return 0; 275362306a36Sopenharmony_ci} 275462306a36Sopenharmony_ci 275562306a36Sopenharmony_ci/* 275662306a36Sopenharmony_ci * Expand an inode by new_extra_isize bytes when EAs are present. 275762306a36Sopenharmony_ci * Returns 0 on success or negative error number on failure. 275862306a36Sopenharmony_ci */ 275962306a36Sopenharmony_ciint ext4_expand_extra_isize_ea(struct inode *inode, int new_extra_isize, 276062306a36Sopenharmony_ci struct ext4_inode *raw_inode, handle_t *handle) 276162306a36Sopenharmony_ci{ 276262306a36Sopenharmony_ci struct ext4_xattr_ibody_header *header; 276362306a36Sopenharmony_ci struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); 276462306a36Sopenharmony_ci static unsigned int mnt_count; 276562306a36Sopenharmony_ci size_t min_offs; 276662306a36Sopenharmony_ci size_t ifree, bfree; 276762306a36Sopenharmony_ci int total_ino; 276862306a36Sopenharmony_ci void *base, *end; 276962306a36Sopenharmony_ci int error = 0, tried_min_extra_isize = 0; 277062306a36Sopenharmony_ci int s_min_extra_isize = le16_to_cpu(sbi->s_es->s_min_extra_isize); 277162306a36Sopenharmony_ci int isize_diff; /* How much do we need to grow i_extra_isize */ 277262306a36Sopenharmony_ci 277362306a36Sopenharmony_ciretry: 277462306a36Sopenharmony_ci isize_diff = new_extra_isize - EXT4_I(inode)->i_extra_isize; 277562306a36Sopenharmony_ci if (EXT4_I(inode)->i_extra_isize >= new_extra_isize) 277662306a36Sopenharmony_ci return 0; 277762306a36Sopenharmony_ci 277862306a36Sopenharmony_ci header = IHDR(inode, raw_inode); 277962306a36Sopenharmony_ci 278062306a36Sopenharmony_ci /* 278162306a36Sopenharmony_ci * Check if enough free space is available in the inode to shift the 278262306a36Sopenharmony_ci * entries ahead by new_extra_isize. 278362306a36Sopenharmony_ci */ 278462306a36Sopenharmony_ci 278562306a36Sopenharmony_ci base = IFIRST(header); 278662306a36Sopenharmony_ci end = (void *)raw_inode + EXT4_SB(inode->i_sb)->s_inode_size; 278762306a36Sopenharmony_ci min_offs = end - base; 278862306a36Sopenharmony_ci total_ino = sizeof(struct ext4_xattr_ibody_header) + sizeof(u32); 278962306a36Sopenharmony_ci 279062306a36Sopenharmony_ci error = xattr_check_inode(inode, header, end); 279162306a36Sopenharmony_ci if (error) 279262306a36Sopenharmony_ci goto cleanup; 279362306a36Sopenharmony_ci 279462306a36Sopenharmony_ci ifree = ext4_xattr_free_space(base, &min_offs, base, &total_ino); 279562306a36Sopenharmony_ci if (ifree >= isize_diff) 279662306a36Sopenharmony_ci goto shift; 279762306a36Sopenharmony_ci 279862306a36Sopenharmony_ci /* 279962306a36Sopenharmony_ci * Enough free space isn't available in the inode, check if 280062306a36Sopenharmony_ci * EA block can hold new_extra_isize bytes. 280162306a36Sopenharmony_ci */ 280262306a36Sopenharmony_ci if (EXT4_I(inode)->i_file_acl) { 280362306a36Sopenharmony_ci struct buffer_head *bh; 280462306a36Sopenharmony_ci 280562306a36Sopenharmony_ci bh = ext4_sb_bread(inode->i_sb, EXT4_I(inode)->i_file_acl, REQ_PRIO); 280662306a36Sopenharmony_ci if (IS_ERR(bh)) { 280762306a36Sopenharmony_ci error = PTR_ERR(bh); 280862306a36Sopenharmony_ci goto cleanup; 280962306a36Sopenharmony_ci } 281062306a36Sopenharmony_ci error = ext4_xattr_check_block(inode, bh); 281162306a36Sopenharmony_ci if (error) { 281262306a36Sopenharmony_ci brelse(bh); 281362306a36Sopenharmony_ci goto cleanup; 281462306a36Sopenharmony_ci } 281562306a36Sopenharmony_ci base = BHDR(bh); 281662306a36Sopenharmony_ci end = bh->b_data + bh->b_size; 281762306a36Sopenharmony_ci min_offs = end - base; 281862306a36Sopenharmony_ci bfree = ext4_xattr_free_space(BFIRST(bh), &min_offs, base, 281962306a36Sopenharmony_ci NULL); 282062306a36Sopenharmony_ci brelse(bh); 282162306a36Sopenharmony_ci if (bfree + ifree < isize_diff) { 282262306a36Sopenharmony_ci if (!tried_min_extra_isize && s_min_extra_isize) { 282362306a36Sopenharmony_ci tried_min_extra_isize++; 282462306a36Sopenharmony_ci new_extra_isize = s_min_extra_isize; 282562306a36Sopenharmony_ci goto retry; 282662306a36Sopenharmony_ci } 282762306a36Sopenharmony_ci error = -ENOSPC; 282862306a36Sopenharmony_ci goto cleanup; 282962306a36Sopenharmony_ci } 283062306a36Sopenharmony_ci } else { 283162306a36Sopenharmony_ci bfree = inode->i_sb->s_blocksize; 283262306a36Sopenharmony_ci } 283362306a36Sopenharmony_ci 283462306a36Sopenharmony_ci error = ext4_xattr_make_inode_space(handle, inode, raw_inode, 283562306a36Sopenharmony_ci isize_diff, ifree, bfree, 283662306a36Sopenharmony_ci &total_ino); 283762306a36Sopenharmony_ci if (error) { 283862306a36Sopenharmony_ci if (error == -ENOSPC && !tried_min_extra_isize && 283962306a36Sopenharmony_ci s_min_extra_isize) { 284062306a36Sopenharmony_ci tried_min_extra_isize++; 284162306a36Sopenharmony_ci new_extra_isize = s_min_extra_isize; 284262306a36Sopenharmony_ci goto retry; 284362306a36Sopenharmony_ci } 284462306a36Sopenharmony_ci goto cleanup; 284562306a36Sopenharmony_ci } 284662306a36Sopenharmony_cishift: 284762306a36Sopenharmony_ci /* Adjust the offsets and shift the remaining entries ahead */ 284862306a36Sopenharmony_ci ext4_xattr_shift_entries(IFIRST(header), EXT4_I(inode)->i_extra_isize 284962306a36Sopenharmony_ci - new_extra_isize, (void *)raw_inode + 285062306a36Sopenharmony_ci EXT4_GOOD_OLD_INODE_SIZE + new_extra_isize, 285162306a36Sopenharmony_ci (void *)header, total_ino); 285262306a36Sopenharmony_ci EXT4_I(inode)->i_extra_isize = new_extra_isize; 285362306a36Sopenharmony_ci 285462306a36Sopenharmony_ci if (ext4_has_inline_data(inode)) 285562306a36Sopenharmony_ci error = ext4_find_inline_data_nolock(inode); 285662306a36Sopenharmony_ci 285762306a36Sopenharmony_cicleanup: 285862306a36Sopenharmony_ci if (error && (mnt_count != le16_to_cpu(sbi->s_es->s_mnt_count))) { 285962306a36Sopenharmony_ci ext4_warning(inode->i_sb, "Unable to expand inode %lu. Delete some EAs or run e2fsck.", 286062306a36Sopenharmony_ci inode->i_ino); 286162306a36Sopenharmony_ci mnt_count = le16_to_cpu(sbi->s_es->s_mnt_count); 286262306a36Sopenharmony_ci } 286362306a36Sopenharmony_ci return error; 286462306a36Sopenharmony_ci} 286562306a36Sopenharmony_ci 286662306a36Sopenharmony_ci#define EIA_INCR 16 /* must be 2^n */ 286762306a36Sopenharmony_ci#define EIA_MASK (EIA_INCR - 1) 286862306a36Sopenharmony_ci 286962306a36Sopenharmony_ci/* Add the large xattr @inode into @ea_inode_array for deferred iput(). 287062306a36Sopenharmony_ci * If @ea_inode_array is new or full it will be grown and the old 287162306a36Sopenharmony_ci * contents copied over. 287262306a36Sopenharmony_ci */ 287362306a36Sopenharmony_cistatic int 287462306a36Sopenharmony_ciext4_expand_inode_array(struct ext4_xattr_inode_array **ea_inode_array, 287562306a36Sopenharmony_ci struct inode *inode) 287662306a36Sopenharmony_ci{ 287762306a36Sopenharmony_ci if (*ea_inode_array == NULL) { 287862306a36Sopenharmony_ci /* 287962306a36Sopenharmony_ci * Start with 15 inodes, so it fits into a power-of-two size. 288062306a36Sopenharmony_ci * If *ea_inode_array is NULL, this is essentially offsetof() 288162306a36Sopenharmony_ci */ 288262306a36Sopenharmony_ci (*ea_inode_array) = 288362306a36Sopenharmony_ci kmalloc(offsetof(struct ext4_xattr_inode_array, 288462306a36Sopenharmony_ci inodes[EIA_MASK]), 288562306a36Sopenharmony_ci GFP_NOFS); 288662306a36Sopenharmony_ci if (*ea_inode_array == NULL) 288762306a36Sopenharmony_ci return -ENOMEM; 288862306a36Sopenharmony_ci (*ea_inode_array)->count = 0; 288962306a36Sopenharmony_ci } else if (((*ea_inode_array)->count & EIA_MASK) == EIA_MASK) { 289062306a36Sopenharmony_ci /* expand the array once all 15 + n * 16 slots are full */ 289162306a36Sopenharmony_ci struct ext4_xattr_inode_array *new_array = NULL; 289262306a36Sopenharmony_ci int count = (*ea_inode_array)->count; 289362306a36Sopenharmony_ci 289462306a36Sopenharmony_ci /* if new_array is NULL, this is essentially offsetof() */ 289562306a36Sopenharmony_ci new_array = kmalloc( 289662306a36Sopenharmony_ci offsetof(struct ext4_xattr_inode_array, 289762306a36Sopenharmony_ci inodes[count + EIA_INCR]), 289862306a36Sopenharmony_ci GFP_NOFS); 289962306a36Sopenharmony_ci if (new_array == NULL) 290062306a36Sopenharmony_ci return -ENOMEM; 290162306a36Sopenharmony_ci memcpy(new_array, *ea_inode_array, 290262306a36Sopenharmony_ci offsetof(struct ext4_xattr_inode_array, inodes[count])); 290362306a36Sopenharmony_ci kfree(*ea_inode_array); 290462306a36Sopenharmony_ci *ea_inode_array = new_array; 290562306a36Sopenharmony_ci } 290662306a36Sopenharmony_ci (*ea_inode_array)->inodes[(*ea_inode_array)->count++] = inode; 290762306a36Sopenharmony_ci return 0; 290862306a36Sopenharmony_ci} 290962306a36Sopenharmony_ci 291062306a36Sopenharmony_ci/* 291162306a36Sopenharmony_ci * ext4_xattr_delete_inode() 291262306a36Sopenharmony_ci * 291362306a36Sopenharmony_ci * Free extended attribute resources associated with this inode. Traverse 291462306a36Sopenharmony_ci * all entries and decrement reference on any xattr inodes associated with this 291562306a36Sopenharmony_ci * inode. This is called immediately before an inode is freed. We have exclusive 291662306a36Sopenharmony_ci * access to the inode. If an orphan inode is deleted it will also release its 291762306a36Sopenharmony_ci * references on xattr block and xattr inodes. 291862306a36Sopenharmony_ci */ 291962306a36Sopenharmony_ciint ext4_xattr_delete_inode(handle_t *handle, struct inode *inode, 292062306a36Sopenharmony_ci struct ext4_xattr_inode_array **ea_inode_array, 292162306a36Sopenharmony_ci int extra_credits) 292262306a36Sopenharmony_ci{ 292362306a36Sopenharmony_ci struct buffer_head *bh = NULL; 292462306a36Sopenharmony_ci struct ext4_xattr_ibody_header *header; 292562306a36Sopenharmony_ci struct ext4_iloc iloc = { .bh = NULL }; 292662306a36Sopenharmony_ci struct ext4_xattr_entry *entry; 292762306a36Sopenharmony_ci struct inode *ea_inode; 292862306a36Sopenharmony_ci int error; 292962306a36Sopenharmony_ci 293062306a36Sopenharmony_ci error = ext4_journal_ensure_credits(handle, extra_credits, 293162306a36Sopenharmony_ci ext4_free_metadata_revoke_credits(inode->i_sb, 1)); 293262306a36Sopenharmony_ci if (error < 0) { 293362306a36Sopenharmony_ci EXT4_ERROR_INODE(inode, "ensure credits (error %d)", error); 293462306a36Sopenharmony_ci goto cleanup; 293562306a36Sopenharmony_ci } 293662306a36Sopenharmony_ci 293762306a36Sopenharmony_ci if (ext4_has_feature_ea_inode(inode->i_sb) && 293862306a36Sopenharmony_ci ext4_test_inode_state(inode, EXT4_STATE_XATTR)) { 293962306a36Sopenharmony_ci 294062306a36Sopenharmony_ci error = ext4_get_inode_loc(inode, &iloc); 294162306a36Sopenharmony_ci if (error) { 294262306a36Sopenharmony_ci EXT4_ERROR_INODE(inode, "inode loc (error %d)", error); 294362306a36Sopenharmony_ci goto cleanup; 294462306a36Sopenharmony_ci } 294562306a36Sopenharmony_ci 294662306a36Sopenharmony_ci error = ext4_journal_get_write_access(handle, inode->i_sb, 294762306a36Sopenharmony_ci iloc.bh, EXT4_JTR_NONE); 294862306a36Sopenharmony_ci if (error) { 294962306a36Sopenharmony_ci EXT4_ERROR_INODE(inode, "write access (error %d)", 295062306a36Sopenharmony_ci error); 295162306a36Sopenharmony_ci goto cleanup; 295262306a36Sopenharmony_ci } 295362306a36Sopenharmony_ci 295462306a36Sopenharmony_ci header = IHDR(inode, ext4_raw_inode(&iloc)); 295562306a36Sopenharmony_ci if (header->h_magic == cpu_to_le32(EXT4_XATTR_MAGIC)) 295662306a36Sopenharmony_ci ext4_xattr_inode_dec_ref_all(handle, inode, iloc.bh, 295762306a36Sopenharmony_ci IFIRST(header), 295862306a36Sopenharmony_ci false /* block_csum */, 295962306a36Sopenharmony_ci ea_inode_array, 296062306a36Sopenharmony_ci extra_credits, 296162306a36Sopenharmony_ci false /* skip_quota */); 296262306a36Sopenharmony_ci } 296362306a36Sopenharmony_ci 296462306a36Sopenharmony_ci if (EXT4_I(inode)->i_file_acl) { 296562306a36Sopenharmony_ci bh = ext4_sb_bread(inode->i_sb, EXT4_I(inode)->i_file_acl, REQ_PRIO); 296662306a36Sopenharmony_ci if (IS_ERR(bh)) { 296762306a36Sopenharmony_ci error = PTR_ERR(bh); 296862306a36Sopenharmony_ci if (error == -EIO) { 296962306a36Sopenharmony_ci EXT4_ERROR_INODE_ERR(inode, EIO, 297062306a36Sopenharmony_ci "block %llu read error", 297162306a36Sopenharmony_ci EXT4_I(inode)->i_file_acl); 297262306a36Sopenharmony_ci } 297362306a36Sopenharmony_ci bh = NULL; 297462306a36Sopenharmony_ci goto cleanup; 297562306a36Sopenharmony_ci } 297662306a36Sopenharmony_ci error = ext4_xattr_check_block(inode, bh); 297762306a36Sopenharmony_ci if (error) 297862306a36Sopenharmony_ci goto cleanup; 297962306a36Sopenharmony_ci 298062306a36Sopenharmony_ci if (ext4_has_feature_ea_inode(inode->i_sb)) { 298162306a36Sopenharmony_ci for (entry = BFIRST(bh); !IS_LAST_ENTRY(entry); 298262306a36Sopenharmony_ci entry = EXT4_XATTR_NEXT(entry)) { 298362306a36Sopenharmony_ci if (!entry->e_value_inum) 298462306a36Sopenharmony_ci continue; 298562306a36Sopenharmony_ci error = ext4_xattr_inode_iget(inode, 298662306a36Sopenharmony_ci le32_to_cpu(entry->e_value_inum), 298762306a36Sopenharmony_ci le32_to_cpu(entry->e_hash), 298862306a36Sopenharmony_ci &ea_inode); 298962306a36Sopenharmony_ci if (error) 299062306a36Sopenharmony_ci continue; 299162306a36Sopenharmony_ci ext4_xattr_inode_free_quota(inode, ea_inode, 299262306a36Sopenharmony_ci le32_to_cpu(entry->e_value_size)); 299362306a36Sopenharmony_ci iput(ea_inode); 299462306a36Sopenharmony_ci } 299562306a36Sopenharmony_ci 299662306a36Sopenharmony_ci } 299762306a36Sopenharmony_ci 299862306a36Sopenharmony_ci ext4_xattr_release_block(handle, inode, bh, ea_inode_array, 299962306a36Sopenharmony_ci extra_credits); 300062306a36Sopenharmony_ci /* 300162306a36Sopenharmony_ci * Update i_file_acl value in the same transaction that releases 300262306a36Sopenharmony_ci * block. 300362306a36Sopenharmony_ci */ 300462306a36Sopenharmony_ci EXT4_I(inode)->i_file_acl = 0; 300562306a36Sopenharmony_ci error = ext4_mark_inode_dirty(handle, inode); 300662306a36Sopenharmony_ci if (error) { 300762306a36Sopenharmony_ci EXT4_ERROR_INODE(inode, "mark inode dirty (error %d)", 300862306a36Sopenharmony_ci error); 300962306a36Sopenharmony_ci goto cleanup; 301062306a36Sopenharmony_ci } 301162306a36Sopenharmony_ci ext4_fc_mark_ineligible(inode->i_sb, EXT4_FC_REASON_XATTR, handle); 301262306a36Sopenharmony_ci } 301362306a36Sopenharmony_ci error = 0; 301462306a36Sopenharmony_cicleanup: 301562306a36Sopenharmony_ci brelse(iloc.bh); 301662306a36Sopenharmony_ci brelse(bh); 301762306a36Sopenharmony_ci return error; 301862306a36Sopenharmony_ci} 301962306a36Sopenharmony_ci 302062306a36Sopenharmony_civoid ext4_xattr_inode_array_free(struct ext4_xattr_inode_array *ea_inode_array) 302162306a36Sopenharmony_ci{ 302262306a36Sopenharmony_ci int idx; 302362306a36Sopenharmony_ci 302462306a36Sopenharmony_ci if (ea_inode_array == NULL) 302562306a36Sopenharmony_ci return; 302662306a36Sopenharmony_ci 302762306a36Sopenharmony_ci for (idx = 0; idx < ea_inode_array->count; ++idx) 302862306a36Sopenharmony_ci iput(ea_inode_array->inodes[idx]); 302962306a36Sopenharmony_ci kfree(ea_inode_array); 303062306a36Sopenharmony_ci} 303162306a36Sopenharmony_ci 303262306a36Sopenharmony_ci/* 303362306a36Sopenharmony_ci * ext4_xattr_block_cache_insert() 303462306a36Sopenharmony_ci * 303562306a36Sopenharmony_ci * Create a new entry in the extended attribute block cache, and insert 303662306a36Sopenharmony_ci * it unless such an entry is already in the cache. 303762306a36Sopenharmony_ci * 303862306a36Sopenharmony_ci * Returns 0, or a negative error number on failure. 303962306a36Sopenharmony_ci */ 304062306a36Sopenharmony_cistatic void 304162306a36Sopenharmony_ciext4_xattr_block_cache_insert(struct mb_cache *ea_block_cache, 304262306a36Sopenharmony_ci struct buffer_head *bh) 304362306a36Sopenharmony_ci{ 304462306a36Sopenharmony_ci struct ext4_xattr_header *header = BHDR(bh); 304562306a36Sopenharmony_ci __u32 hash = le32_to_cpu(header->h_hash); 304662306a36Sopenharmony_ci int reusable = le32_to_cpu(header->h_refcount) < 304762306a36Sopenharmony_ci EXT4_XATTR_REFCOUNT_MAX; 304862306a36Sopenharmony_ci int error; 304962306a36Sopenharmony_ci 305062306a36Sopenharmony_ci if (!ea_block_cache) 305162306a36Sopenharmony_ci return; 305262306a36Sopenharmony_ci error = mb_cache_entry_create(ea_block_cache, GFP_NOFS, hash, 305362306a36Sopenharmony_ci bh->b_blocknr, reusable); 305462306a36Sopenharmony_ci if (error) { 305562306a36Sopenharmony_ci if (error == -EBUSY) 305662306a36Sopenharmony_ci ea_bdebug(bh, "already in cache"); 305762306a36Sopenharmony_ci } else 305862306a36Sopenharmony_ci ea_bdebug(bh, "inserting [%x]", (int)hash); 305962306a36Sopenharmony_ci} 306062306a36Sopenharmony_ci 306162306a36Sopenharmony_ci/* 306262306a36Sopenharmony_ci * ext4_xattr_cmp() 306362306a36Sopenharmony_ci * 306462306a36Sopenharmony_ci * Compare two extended attribute blocks for equality. 306562306a36Sopenharmony_ci * 306662306a36Sopenharmony_ci * Returns 0 if the blocks are equal, 1 if they differ, and 306762306a36Sopenharmony_ci * a negative error number on errors. 306862306a36Sopenharmony_ci */ 306962306a36Sopenharmony_cistatic int 307062306a36Sopenharmony_ciext4_xattr_cmp(struct ext4_xattr_header *header1, 307162306a36Sopenharmony_ci struct ext4_xattr_header *header2) 307262306a36Sopenharmony_ci{ 307362306a36Sopenharmony_ci struct ext4_xattr_entry *entry1, *entry2; 307462306a36Sopenharmony_ci 307562306a36Sopenharmony_ci entry1 = ENTRY(header1+1); 307662306a36Sopenharmony_ci entry2 = ENTRY(header2+1); 307762306a36Sopenharmony_ci while (!IS_LAST_ENTRY(entry1)) { 307862306a36Sopenharmony_ci if (IS_LAST_ENTRY(entry2)) 307962306a36Sopenharmony_ci return 1; 308062306a36Sopenharmony_ci if (entry1->e_hash != entry2->e_hash || 308162306a36Sopenharmony_ci entry1->e_name_index != entry2->e_name_index || 308262306a36Sopenharmony_ci entry1->e_name_len != entry2->e_name_len || 308362306a36Sopenharmony_ci entry1->e_value_size != entry2->e_value_size || 308462306a36Sopenharmony_ci entry1->e_value_inum != entry2->e_value_inum || 308562306a36Sopenharmony_ci memcmp(entry1->e_name, entry2->e_name, entry1->e_name_len)) 308662306a36Sopenharmony_ci return 1; 308762306a36Sopenharmony_ci if (!entry1->e_value_inum && 308862306a36Sopenharmony_ci memcmp((char *)header1 + le16_to_cpu(entry1->e_value_offs), 308962306a36Sopenharmony_ci (char *)header2 + le16_to_cpu(entry2->e_value_offs), 309062306a36Sopenharmony_ci le32_to_cpu(entry1->e_value_size))) 309162306a36Sopenharmony_ci return 1; 309262306a36Sopenharmony_ci 309362306a36Sopenharmony_ci entry1 = EXT4_XATTR_NEXT(entry1); 309462306a36Sopenharmony_ci entry2 = EXT4_XATTR_NEXT(entry2); 309562306a36Sopenharmony_ci } 309662306a36Sopenharmony_ci if (!IS_LAST_ENTRY(entry2)) 309762306a36Sopenharmony_ci return 1; 309862306a36Sopenharmony_ci return 0; 309962306a36Sopenharmony_ci} 310062306a36Sopenharmony_ci 310162306a36Sopenharmony_ci/* 310262306a36Sopenharmony_ci * ext4_xattr_block_cache_find() 310362306a36Sopenharmony_ci * 310462306a36Sopenharmony_ci * Find an identical extended attribute block. 310562306a36Sopenharmony_ci * 310662306a36Sopenharmony_ci * Returns a pointer to the block found, or NULL if such a block was 310762306a36Sopenharmony_ci * not found or an error occurred. 310862306a36Sopenharmony_ci */ 310962306a36Sopenharmony_cistatic struct buffer_head * 311062306a36Sopenharmony_ciext4_xattr_block_cache_find(struct inode *inode, 311162306a36Sopenharmony_ci struct ext4_xattr_header *header, 311262306a36Sopenharmony_ci struct mb_cache_entry **pce) 311362306a36Sopenharmony_ci{ 311462306a36Sopenharmony_ci __u32 hash = le32_to_cpu(header->h_hash); 311562306a36Sopenharmony_ci struct mb_cache_entry *ce; 311662306a36Sopenharmony_ci struct mb_cache *ea_block_cache = EA_BLOCK_CACHE(inode); 311762306a36Sopenharmony_ci 311862306a36Sopenharmony_ci if (!ea_block_cache) 311962306a36Sopenharmony_ci return NULL; 312062306a36Sopenharmony_ci if (!header->h_hash) 312162306a36Sopenharmony_ci return NULL; /* never share */ 312262306a36Sopenharmony_ci ea_idebug(inode, "looking for cached blocks [%x]", (int)hash); 312362306a36Sopenharmony_ci ce = mb_cache_entry_find_first(ea_block_cache, hash); 312462306a36Sopenharmony_ci while (ce) { 312562306a36Sopenharmony_ci struct buffer_head *bh; 312662306a36Sopenharmony_ci 312762306a36Sopenharmony_ci bh = ext4_sb_bread(inode->i_sb, ce->e_value, REQ_PRIO); 312862306a36Sopenharmony_ci if (IS_ERR(bh)) { 312962306a36Sopenharmony_ci if (PTR_ERR(bh) == -ENOMEM) 313062306a36Sopenharmony_ci return NULL; 313162306a36Sopenharmony_ci bh = NULL; 313262306a36Sopenharmony_ci EXT4_ERROR_INODE(inode, "block %lu read error", 313362306a36Sopenharmony_ci (unsigned long)ce->e_value); 313462306a36Sopenharmony_ci } else if (ext4_xattr_cmp(header, BHDR(bh)) == 0) { 313562306a36Sopenharmony_ci *pce = ce; 313662306a36Sopenharmony_ci return bh; 313762306a36Sopenharmony_ci } 313862306a36Sopenharmony_ci brelse(bh); 313962306a36Sopenharmony_ci ce = mb_cache_entry_find_next(ea_block_cache, ce); 314062306a36Sopenharmony_ci } 314162306a36Sopenharmony_ci return NULL; 314262306a36Sopenharmony_ci} 314362306a36Sopenharmony_ci 314462306a36Sopenharmony_ci#define NAME_HASH_SHIFT 5 314562306a36Sopenharmony_ci#define VALUE_HASH_SHIFT 16 314662306a36Sopenharmony_ci 314762306a36Sopenharmony_ci/* 314862306a36Sopenharmony_ci * ext4_xattr_hash_entry() 314962306a36Sopenharmony_ci * 315062306a36Sopenharmony_ci * Compute the hash of an extended attribute. 315162306a36Sopenharmony_ci */ 315262306a36Sopenharmony_cistatic __le32 ext4_xattr_hash_entry(char *name, size_t name_len, __le32 *value, 315362306a36Sopenharmony_ci size_t value_count) 315462306a36Sopenharmony_ci{ 315562306a36Sopenharmony_ci __u32 hash = 0; 315662306a36Sopenharmony_ci 315762306a36Sopenharmony_ci while (name_len--) { 315862306a36Sopenharmony_ci hash = (hash << NAME_HASH_SHIFT) ^ 315962306a36Sopenharmony_ci (hash >> (8*sizeof(hash) - NAME_HASH_SHIFT)) ^ 316062306a36Sopenharmony_ci (unsigned char)*name++; 316162306a36Sopenharmony_ci } 316262306a36Sopenharmony_ci while (value_count--) { 316362306a36Sopenharmony_ci hash = (hash << VALUE_HASH_SHIFT) ^ 316462306a36Sopenharmony_ci (hash >> (8*sizeof(hash) - VALUE_HASH_SHIFT)) ^ 316562306a36Sopenharmony_ci le32_to_cpu(*value++); 316662306a36Sopenharmony_ci } 316762306a36Sopenharmony_ci return cpu_to_le32(hash); 316862306a36Sopenharmony_ci} 316962306a36Sopenharmony_ci 317062306a36Sopenharmony_ci/* 317162306a36Sopenharmony_ci * ext4_xattr_hash_entry_signed() 317262306a36Sopenharmony_ci * 317362306a36Sopenharmony_ci * Compute the hash of an extended attribute incorrectly. 317462306a36Sopenharmony_ci */ 317562306a36Sopenharmony_cistatic __le32 ext4_xattr_hash_entry_signed(char *name, size_t name_len, __le32 *value, size_t value_count) 317662306a36Sopenharmony_ci{ 317762306a36Sopenharmony_ci __u32 hash = 0; 317862306a36Sopenharmony_ci 317962306a36Sopenharmony_ci while (name_len--) { 318062306a36Sopenharmony_ci hash = (hash << NAME_HASH_SHIFT) ^ 318162306a36Sopenharmony_ci (hash >> (8*sizeof(hash) - NAME_HASH_SHIFT)) ^ 318262306a36Sopenharmony_ci (signed char)*name++; 318362306a36Sopenharmony_ci } 318462306a36Sopenharmony_ci while (value_count--) { 318562306a36Sopenharmony_ci hash = (hash << VALUE_HASH_SHIFT) ^ 318662306a36Sopenharmony_ci (hash >> (8*sizeof(hash) - VALUE_HASH_SHIFT)) ^ 318762306a36Sopenharmony_ci le32_to_cpu(*value++); 318862306a36Sopenharmony_ci } 318962306a36Sopenharmony_ci return cpu_to_le32(hash); 319062306a36Sopenharmony_ci} 319162306a36Sopenharmony_ci 319262306a36Sopenharmony_ci#undef NAME_HASH_SHIFT 319362306a36Sopenharmony_ci#undef VALUE_HASH_SHIFT 319462306a36Sopenharmony_ci 319562306a36Sopenharmony_ci#define BLOCK_HASH_SHIFT 16 319662306a36Sopenharmony_ci 319762306a36Sopenharmony_ci/* 319862306a36Sopenharmony_ci * ext4_xattr_rehash() 319962306a36Sopenharmony_ci * 320062306a36Sopenharmony_ci * Re-compute the extended attribute hash value after an entry has changed. 320162306a36Sopenharmony_ci */ 320262306a36Sopenharmony_cistatic void ext4_xattr_rehash(struct ext4_xattr_header *header) 320362306a36Sopenharmony_ci{ 320462306a36Sopenharmony_ci struct ext4_xattr_entry *here; 320562306a36Sopenharmony_ci __u32 hash = 0; 320662306a36Sopenharmony_ci 320762306a36Sopenharmony_ci here = ENTRY(header+1); 320862306a36Sopenharmony_ci while (!IS_LAST_ENTRY(here)) { 320962306a36Sopenharmony_ci if (!here->e_hash) { 321062306a36Sopenharmony_ci /* Block is not shared if an entry's hash value == 0 */ 321162306a36Sopenharmony_ci hash = 0; 321262306a36Sopenharmony_ci break; 321362306a36Sopenharmony_ci } 321462306a36Sopenharmony_ci hash = (hash << BLOCK_HASH_SHIFT) ^ 321562306a36Sopenharmony_ci (hash >> (8*sizeof(hash) - BLOCK_HASH_SHIFT)) ^ 321662306a36Sopenharmony_ci le32_to_cpu(here->e_hash); 321762306a36Sopenharmony_ci here = EXT4_XATTR_NEXT(here); 321862306a36Sopenharmony_ci } 321962306a36Sopenharmony_ci header->h_hash = cpu_to_le32(hash); 322062306a36Sopenharmony_ci} 322162306a36Sopenharmony_ci 322262306a36Sopenharmony_ci#undef BLOCK_HASH_SHIFT 322362306a36Sopenharmony_ci 322462306a36Sopenharmony_ci#define HASH_BUCKET_BITS 10 322562306a36Sopenharmony_ci 322662306a36Sopenharmony_cistruct mb_cache * 322762306a36Sopenharmony_ciext4_xattr_create_cache(void) 322862306a36Sopenharmony_ci{ 322962306a36Sopenharmony_ci return mb_cache_create(HASH_BUCKET_BITS); 323062306a36Sopenharmony_ci} 323162306a36Sopenharmony_ci 323262306a36Sopenharmony_civoid ext4_xattr_destroy_cache(struct mb_cache *cache) 323362306a36Sopenharmony_ci{ 323462306a36Sopenharmony_ci if (cache) 323562306a36Sopenharmony_ci mb_cache_destroy(cache); 323662306a36Sopenharmony_ci} 323762306a36Sopenharmony_ci 3238