1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 21da177e4SLinus Torvalds /* 31da177e4SLinus Torvalds * linux/fs/ext2/xattr.c 41da177e4SLinus Torvalds * 51da177e4SLinus Torvalds * Copyright (C) 2001-2003 Andreas Gruenbacher <agruen@suse.de> 61da177e4SLinus Torvalds * 71da177e4SLinus Torvalds * Fix by Harrison Xing <harrison@mountainviewdata.com>. 81da177e4SLinus Torvalds * Extended attributes for symlinks and special files added per 91da177e4SLinus Torvalds * suggestion of Luka Renko <luka.renko@hermes.si>. 101da177e4SLinus Torvalds * xattr consolidation Copyright (c) 2004 James Morris <jmorris@redhat.com>, 111da177e4SLinus Torvalds * Red Hat Inc. 121da177e4SLinus Torvalds * 131da177e4SLinus Torvalds */ 141da177e4SLinus Torvalds 151da177e4SLinus Torvalds /* 161da177e4SLinus Torvalds * Extended attributes are stored on disk blocks allocated outside of 171da177e4SLinus Torvalds * any inode. The i_file_acl field is then made to point to this allocated 181da177e4SLinus Torvalds * block. If all extended attributes of an inode are identical, these 191da177e4SLinus Torvalds * inodes may share the same extended attribute block. Such situations 201da177e4SLinus Torvalds * are automatically detected by keeping a cache of recent attribute block 211da177e4SLinus Torvalds * numbers and hashes over the block's contents in memory. 221da177e4SLinus Torvalds * 231da177e4SLinus Torvalds * 241da177e4SLinus Torvalds * Extended attribute block layout: 251da177e4SLinus Torvalds * 261da177e4SLinus Torvalds * +------------------+ 271da177e4SLinus Torvalds * | header | 281da177e4SLinus Torvalds * | entry 1 | | 291da177e4SLinus Torvalds * | entry 2 | | growing downwards 301da177e4SLinus Torvalds * | entry 3 | v 311da177e4SLinus Torvalds * | four null bytes | 321da177e4SLinus Torvalds * | . . . | 331da177e4SLinus Torvalds * | value 1 | ^ 341da177e4SLinus Torvalds * | value 3 | | growing upwards 351da177e4SLinus Torvalds * | value 2 | | 361da177e4SLinus Torvalds * +------------------+ 371da177e4SLinus Torvalds * 381da177e4SLinus Torvalds * The block header is followed by multiple entry descriptors. These entry 3925985edcSLucas De Marchi * descriptors are variable in size, and aligned to EXT2_XATTR_PAD 401da177e4SLinus Torvalds * byte boundaries. The entry descriptors are sorted by attribute name, 411da177e4SLinus Torvalds * so that two extended attribute blocks can be compared efficiently. 421da177e4SLinus Torvalds * 431da177e4SLinus Torvalds * Attribute values are aligned to the end of the block, stored in 441da177e4SLinus Torvalds * no specific order. They are also padded to EXT2_XATTR_PAD byte 451da177e4SLinus Torvalds * boundaries. No additional gaps are left between them. 461da177e4SLinus Torvalds * 471da177e4SLinus Torvalds * Locking strategy 481da177e4SLinus Torvalds * ---------------- 491da177e4SLinus Torvalds * EXT2_I(inode)->i_file_acl is protected by EXT2_I(inode)->xattr_sem. 501da177e4SLinus Torvalds * EA blocks are only changed if they are exclusive to an inode, so 511da177e4SLinus Torvalds * holding xattr_sem also means that nothing but the EA block's reference 521da177e4SLinus Torvalds * count will change. Multiple writers to an EA block are synchronized 531da177e4SLinus Torvalds * by the bh lock. No more than a single bh lock is held at any time 541da177e4SLinus Torvalds * to avoid deadlocks. 551da177e4SLinus Torvalds */ 561da177e4SLinus Torvalds 571da177e4SLinus Torvalds #include <linux/buffer_head.h> 581da177e4SLinus Torvalds #include <linux/init.h> 5944a52022SRandy Dunlap #include <linux/printk.h> 601da177e4SLinus Torvalds #include <linux/slab.h> 617a2508e1SJan Kara #include <linux/mbcache.h> 621da177e4SLinus Torvalds #include <linux/quotaops.h> 631da177e4SLinus Torvalds #include <linux/rwsem.h> 64431547b3SChristoph Hellwig #include <linux/security.h> 651da177e4SLinus Torvalds #include "ext2.h" 661da177e4SLinus Torvalds #include "xattr.h" 671da177e4SLinus Torvalds #include "acl.h" 681da177e4SLinus Torvalds 691da177e4SLinus Torvalds #define HDR(bh) ((struct ext2_xattr_header *)((bh)->b_data)) 701da177e4SLinus Torvalds #define ENTRY(ptr) ((struct ext2_xattr_entry *)(ptr)) 711da177e4SLinus Torvalds #define FIRST_ENTRY(bh) ENTRY(HDR(bh)+1) 721da177e4SLinus Torvalds #define IS_LAST_ENTRY(entry) (*(__u32 *)(entry) == 0) 731da177e4SLinus Torvalds 741da177e4SLinus Torvalds #ifdef EXT2_XATTR_DEBUG 751da177e4SLinus Torvalds # define ea_idebug(inode, f...) do { \ 761da177e4SLinus Torvalds printk(KERN_DEBUG "inode %s:%ld: ", \ 771da177e4SLinus Torvalds inode->i_sb->s_id, inode->i_ino); \ 781da177e4SLinus Torvalds printk(f); \ 791da177e4SLinus Torvalds printk("\n"); \ 801da177e4SLinus Torvalds } while (0) 811da177e4SLinus Torvalds # define ea_bdebug(bh, f...) do { \ 82a1c6f057SDmitry Monakhov printk(KERN_DEBUG "block %pg:%lu: ", \ 83a1c6f057SDmitry Monakhov bh->b_bdev, (unsigned long) bh->b_blocknr); \ 841da177e4SLinus Torvalds printk(f); \ 851da177e4SLinus Torvalds printk("\n"); \ 861da177e4SLinus Torvalds } while (0) 871da177e4SLinus Torvalds #else 8844a52022SRandy Dunlap # define ea_idebug(inode, f...) no_printk(f) 8944a52022SRandy Dunlap # define ea_bdebug(bh, f...) no_printk(f) 901da177e4SLinus Torvalds #endif 911da177e4SLinus Torvalds 921da177e4SLinus Torvalds static int ext2_xattr_set2(struct inode *, struct buffer_head *, 931da177e4SLinus Torvalds struct ext2_xattr_header *); 941da177e4SLinus Torvalds 957a2508e1SJan Kara static int ext2_xattr_cache_insert(struct mb_cache *, struct buffer_head *); 961da177e4SLinus Torvalds static struct buffer_head *ext2_xattr_cache_find(struct inode *, 971da177e4SLinus Torvalds struct ext2_xattr_header *); 981da177e4SLinus Torvalds static void ext2_xattr_rehash(struct ext2_xattr_header *, 991da177e4SLinus Torvalds struct ext2_xattr_entry *); 1001da177e4SLinus Torvalds 101749c72efSStephen Hemminger static const struct xattr_handler *ext2_xattr_handler_map[] = { 1021da177e4SLinus Torvalds [EXT2_XATTR_INDEX_USER] = &ext2_xattr_user_handler, 1031da177e4SLinus Torvalds #ifdef CONFIG_EXT2_FS_POSIX_ACL 10464e178a7SChristoph Hellwig [EXT2_XATTR_INDEX_POSIX_ACL_ACCESS] = &posix_acl_access_xattr_handler, 10564e178a7SChristoph Hellwig [EXT2_XATTR_INDEX_POSIX_ACL_DEFAULT] = &posix_acl_default_xattr_handler, 1061da177e4SLinus Torvalds #endif 1071da177e4SLinus Torvalds [EXT2_XATTR_INDEX_TRUSTED] = &ext2_xattr_trusted_handler, 1081da177e4SLinus Torvalds #ifdef CONFIG_EXT2_FS_SECURITY 1091da177e4SLinus Torvalds [EXT2_XATTR_INDEX_SECURITY] = &ext2_xattr_security_handler, 1101da177e4SLinus Torvalds #endif 1111da177e4SLinus Torvalds }; 1121da177e4SLinus Torvalds 113749c72efSStephen Hemminger const struct xattr_handler *ext2_xattr_handlers[] = { 1141da177e4SLinus Torvalds &ext2_xattr_user_handler, 1151da177e4SLinus Torvalds &ext2_xattr_trusted_handler, 1161da177e4SLinus Torvalds #ifdef CONFIG_EXT2_FS_POSIX_ACL 11764e178a7SChristoph Hellwig &posix_acl_access_xattr_handler, 11864e178a7SChristoph Hellwig &posix_acl_default_xattr_handler, 1191da177e4SLinus Torvalds #endif 1201da177e4SLinus Torvalds #ifdef CONFIG_EXT2_FS_SECURITY 1211da177e4SLinus Torvalds &ext2_xattr_security_handler, 1221da177e4SLinus Torvalds #endif 1231da177e4SLinus Torvalds NULL 1241da177e4SLinus Torvalds }; 1251da177e4SLinus Torvalds 12647387409STahsin Erdogan #define EA_BLOCK_CACHE(inode) (EXT2_SB(inode->i_sb)->s_ea_block_cache) 12747387409STahsin Erdogan 128749c72efSStephen Hemminger static inline const struct xattr_handler * 1291da177e4SLinus Torvalds ext2_xattr_handler(int name_index) 1301da177e4SLinus Torvalds { 131749c72efSStephen Hemminger const struct xattr_handler *handler = NULL; 1321da177e4SLinus Torvalds 1331da177e4SLinus Torvalds if (name_index > 0 && name_index < ARRAY_SIZE(ext2_xattr_handler_map)) 1341da177e4SLinus Torvalds handler = ext2_xattr_handler_map[name_index]; 1351da177e4SLinus Torvalds return handler; 1361da177e4SLinus Torvalds } 1371da177e4SLinus Torvalds 13802475de9SChengguang Xu static bool 13902475de9SChengguang Xu ext2_xattr_header_valid(struct ext2_xattr_header *header) 14002475de9SChengguang Xu { 14102475de9SChengguang Xu if (header->h_magic != cpu_to_le32(EXT2_XATTR_MAGIC) || 14202475de9SChengguang Xu header->h_blocks != cpu_to_le32(1)) 14302475de9SChengguang Xu return false; 14402475de9SChengguang Xu 14502475de9SChengguang Xu return true; 14602475de9SChengguang Xu } 14702475de9SChengguang Xu 148f4c3fb8cSChengguang Xu static bool 1499bb1d7a6SChengguang Xu ext2_xattr_entry_valid(struct ext2_xattr_entry *entry, 1509bb1d7a6SChengguang Xu char *end, size_t end_offs) 151f4c3fb8cSChengguang Xu { 1529bb1d7a6SChengguang Xu struct ext2_xattr_entry *next; 153f4c3fb8cSChengguang Xu size_t size; 154f4c3fb8cSChengguang Xu 1559bb1d7a6SChengguang Xu next = EXT2_XATTR_NEXT(entry); 1569bb1d7a6SChengguang Xu if ((char *)next >= end) 1579bb1d7a6SChengguang Xu return false; 1589bb1d7a6SChengguang Xu 159f4c3fb8cSChengguang Xu if (entry->e_value_block != 0) 160f4c3fb8cSChengguang Xu return false; 161f4c3fb8cSChengguang Xu 162f4c3fb8cSChengguang Xu size = le32_to_cpu(entry->e_value_size); 163f4c3fb8cSChengguang Xu if (size > end_offs || 164f4c3fb8cSChengguang Xu le16_to_cpu(entry->e_value_offs) + size > end_offs) 165f4c3fb8cSChengguang Xu return false; 166f4c3fb8cSChengguang Xu 167f4c3fb8cSChengguang Xu return true; 168f4c3fb8cSChengguang Xu } 169f4c3fb8cSChengguang Xu 170d561d4ddSChengguang Xu static int 171d561d4ddSChengguang Xu ext2_xattr_cmp_entry(int name_index, size_t name_len, const char *name, 172d561d4ddSChengguang Xu struct ext2_xattr_entry *entry) 173d561d4ddSChengguang Xu { 174d561d4ddSChengguang Xu int cmp; 175d561d4ddSChengguang Xu 176d561d4ddSChengguang Xu cmp = name_index - entry->e_name_index; 177d561d4ddSChengguang Xu if (!cmp) 178d561d4ddSChengguang Xu cmp = name_len - entry->e_name_len; 179d561d4ddSChengguang Xu if (!cmp) 180d561d4ddSChengguang Xu cmp = memcmp(name, entry->e_name, name_len); 181d561d4ddSChengguang Xu 182d561d4ddSChengguang Xu return cmp; 183d561d4ddSChengguang Xu } 184d561d4ddSChengguang Xu 1851da177e4SLinus Torvalds /* 1861da177e4SLinus Torvalds * ext2_xattr_get() 1871da177e4SLinus Torvalds * 1881da177e4SLinus Torvalds * Copy an extended attribute into the buffer 1891da177e4SLinus Torvalds * provided, or compute the buffer size required. 1901da177e4SLinus Torvalds * Buffer is NULL to compute the size of the buffer required. 1911da177e4SLinus Torvalds * 1921da177e4SLinus Torvalds * Returns a negative error number on failure, or the number of bytes 1931da177e4SLinus Torvalds * used / required on success. 1941da177e4SLinus Torvalds */ 1951da177e4SLinus Torvalds int 1961da177e4SLinus Torvalds ext2_xattr_get(struct inode *inode, int name_index, const char *name, 1971da177e4SLinus Torvalds void *buffer, size_t buffer_size) 1981da177e4SLinus Torvalds { 1991da177e4SLinus Torvalds struct buffer_head *bh = NULL; 2001da177e4SLinus Torvalds struct ext2_xattr_entry *entry; 2011da177e4SLinus Torvalds size_t name_len, size; 2021da177e4SLinus Torvalds char *end; 2031eaf5faaSChengguang Xu int error, not_found; 20447387409STahsin Erdogan struct mb_cache *ea_block_cache = EA_BLOCK_CACHE(inode); 2051da177e4SLinus Torvalds 2061da177e4SLinus Torvalds ea_idebug(inode, "name=%d.%s, buffer=%p, buffer_size=%ld", 2071da177e4SLinus Torvalds name_index, name, buffer, (long)buffer_size); 2081da177e4SLinus Torvalds 2091da177e4SLinus Torvalds if (name == NULL) 2101da177e4SLinus Torvalds return -EINVAL; 21103b5bb34SWang Sheng-Hui name_len = strlen(name); 21203b5bb34SWang Sheng-Hui if (name_len > 255) 21303b5bb34SWang Sheng-Hui return -ERANGE; 21403b5bb34SWang Sheng-Hui 2151da177e4SLinus Torvalds down_read(&EXT2_I(inode)->xattr_sem); 2161da177e4SLinus Torvalds error = -ENODATA; 2171da177e4SLinus Torvalds if (!EXT2_I(inode)->i_file_acl) 2181da177e4SLinus Torvalds goto cleanup; 2191da177e4SLinus Torvalds ea_idebug(inode, "reading block %d", EXT2_I(inode)->i_file_acl); 2201da177e4SLinus Torvalds bh = sb_bread(inode->i_sb, EXT2_I(inode)->i_file_acl); 2211da177e4SLinus Torvalds error = -EIO; 2221da177e4SLinus Torvalds if (!bh) 2231da177e4SLinus Torvalds goto cleanup; 2241da177e4SLinus Torvalds ea_bdebug(bh, "b_count=%d, refcount=%d", 2251da177e4SLinus Torvalds atomic_read(&(bh->b_count)), le32_to_cpu(HDR(bh)->h_refcount)); 2261da177e4SLinus Torvalds end = bh->b_data + bh->b_size; 22702475de9SChengguang Xu if (!ext2_xattr_header_valid(HDR(bh))) { 22802475de9SChengguang Xu bad_block: 22902475de9SChengguang Xu ext2_error(inode->i_sb, "ext2_xattr_get", 2301da177e4SLinus Torvalds "inode %ld: bad block %d", inode->i_ino, 2311da177e4SLinus Torvalds EXT2_I(inode)->i_file_acl); 2321da177e4SLinus Torvalds error = -EIO; 2331da177e4SLinus Torvalds goto cleanup; 2341da177e4SLinus Torvalds } 2351da177e4SLinus Torvalds 23603b5bb34SWang Sheng-Hui /* find named attribute */ 2371da177e4SLinus Torvalds entry = FIRST_ENTRY(bh); 2381da177e4SLinus Torvalds while (!IS_LAST_ENTRY(entry)) { 2399bb1d7a6SChengguang Xu if (!ext2_xattr_entry_valid(entry, end, 2409bb1d7a6SChengguang Xu inode->i_sb->s_blocksize)) 2416c71b489SJan Kara goto bad_block; 2421eaf5faaSChengguang Xu 2431eaf5faaSChengguang Xu not_found = ext2_xattr_cmp_entry(name_index, name_len, name, 2441eaf5faaSChengguang Xu entry); 2451eaf5faaSChengguang Xu if (!not_found) 2461da177e4SLinus Torvalds goto found; 2471eaf5faaSChengguang Xu if (not_found < 0) 2481eaf5faaSChengguang Xu break; 2491eaf5faaSChengguang Xu 2509bb1d7a6SChengguang Xu entry = EXT2_XATTR_NEXT(entry); 2511da177e4SLinus Torvalds } 25247387409STahsin Erdogan if (ext2_xattr_cache_insert(ea_block_cache, bh)) 2531da177e4SLinus Torvalds ea_idebug(inode, "cache insert failed"); 2541da177e4SLinus Torvalds error = -ENODATA; 2551da177e4SLinus Torvalds goto cleanup; 2561da177e4SLinus Torvalds found: 257f4c3fb8cSChengguang Xu size = le32_to_cpu(entry->e_value_size); 25847387409STahsin Erdogan if (ext2_xattr_cache_insert(ea_block_cache, bh)) 2591da177e4SLinus Torvalds ea_idebug(inode, "cache insert failed"); 2601da177e4SLinus Torvalds if (buffer) { 2611da177e4SLinus Torvalds error = -ERANGE; 2621da177e4SLinus Torvalds if (size > buffer_size) 2631da177e4SLinus Torvalds goto cleanup; 2641da177e4SLinus Torvalds /* return value of attribute */ 2651da177e4SLinus Torvalds memcpy(buffer, bh->b_data + le16_to_cpu(entry->e_value_offs), 2661da177e4SLinus Torvalds size); 2671da177e4SLinus Torvalds } 2681da177e4SLinus Torvalds error = size; 2691da177e4SLinus Torvalds 2701da177e4SLinus Torvalds cleanup: 2711da177e4SLinus Torvalds brelse(bh); 2721da177e4SLinus Torvalds up_read(&EXT2_I(inode)->xattr_sem); 2731da177e4SLinus Torvalds 2741da177e4SLinus Torvalds return error; 2751da177e4SLinus Torvalds } 2761da177e4SLinus Torvalds 2771da177e4SLinus Torvalds /* 2781da177e4SLinus Torvalds * ext2_xattr_list() 2791da177e4SLinus Torvalds * 2801da177e4SLinus Torvalds * Copy a list of attribute names into the buffer 2811da177e4SLinus Torvalds * provided, or compute the buffer size required. 2821da177e4SLinus Torvalds * Buffer is NULL to compute the size of the buffer required. 2831da177e4SLinus Torvalds * 2841da177e4SLinus Torvalds * Returns a negative error number on failure, or the number of bytes 2851da177e4SLinus Torvalds * used / required on success. 2861da177e4SLinus Torvalds */ 2871da177e4SLinus Torvalds static int 288431547b3SChristoph Hellwig ext2_xattr_list(struct dentry *dentry, char *buffer, size_t buffer_size) 2891da177e4SLinus Torvalds { 2902b0143b5SDavid Howells struct inode *inode = d_inode(dentry); 2911da177e4SLinus Torvalds struct buffer_head *bh = NULL; 2921da177e4SLinus Torvalds struct ext2_xattr_entry *entry; 2931da177e4SLinus Torvalds char *end; 2941da177e4SLinus Torvalds size_t rest = buffer_size; 2951da177e4SLinus Torvalds int error; 29647387409STahsin Erdogan struct mb_cache *ea_block_cache = EA_BLOCK_CACHE(inode); 2971da177e4SLinus Torvalds 2981da177e4SLinus Torvalds ea_idebug(inode, "buffer=%p, buffer_size=%ld", 2991da177e4SLinus Torvalds buffer, (long)buffer_size); 3001da177e4SLinus Torvalds 3011da177e4SLinus Torvalds down_read(&EXT2_I(inode)->xattr_sem); 3021da177e4SLinus Torvalds error = 0; 3031da177e4SLinus Torvalds if (!EXT2_I(inode)->i_file_acl) 3041da177e4SLinus Torvalds goto cleanup; 3051da177e4SLinus Torvalds ea_idebug(inode, "reading block %d", EXT2_I(inode)->i_file_acl); 3061da177e4SLinus Torvalds bh = sb_bread(inode->i_sb, EXT2_I(inode)->i_file_acl); 3071da177e4SLinus Torvalds error = -EIO; 3081da177e4SLinus Torvalds if (!bh) 3091da177e4SLinus Torvalds goto cleanup; 3101da177e4SLinus Torvalds ea_bdebug(bh, "b_count=%d, refcount=%d", 3111da177e4SLinus Torvalds atomic_read(&(bh->b_count)), le32_to_cpu(HDR(bh)->h_refcount)); 3121da177e4SLinus Torvalds end = bh->b_data + bh->b_size; 31302475de9SChengguang Xu if (!ext2_xattr_header_valid(HDR(bh))) { 31402475de9SChengguang Xu bad_block: 31502475de9SChengguang Xu ext2_error(inode->i_sb, "ext2_xattr_list", 3161da177e4SLinus Torvalds "inode %ld: bad block %d", inode->i_ino, 3171da177e4SLinus Torvalds EXT2_I(inode)->i_file_acl); 3181da177e4SLinus Torvalds error = -EIO; 3191da177e4SLinus Torvalds goto cleanup; 3201da177e4SLinus Torvalds } 3211da177e4SLinus Torvalds 3221da177e4SLinus Torvalds /* check the on-disk data structure */ 3231da177e4SLinus Torvalds entry = FIRST_ENTRY(bh); 3241da177e4SLinus Torvalds while (!IS_LAST_ENTRY(entry)) { 3259bb1d7a6SChengguang Xu if (!ext2_xattr_entry_valid(entry, end, 3269bb1d7a6SChengguang Xu inode->i_sb->s_blocksize)) 3271da177e4SLinus Torvalds goto bad_block; 3289bb1d7a6SChengguang Xu entry = EXT2_XATTR_NEXT(entry); 3291da177e4SLinus Torvalds } 33047387409STahsin Erdogan if (ext2_xattr_cache_insert(ea_block_cache, bh)) 3311da177e4SLinus Torvalds ea_idebug(inode, "cache insert failed"); 3321da177e4SLinus Torvalds 3331da177e4SLinus Torvalds /* list the attribute names */ 3341da177e4SLinus Torvalds for (entry = FIRST_ENTRY(bh); !IS_LAST_ENTRY(entry); 3351da177e4SLinus Torvalds entry = EXT2_XATTR_NEXT(entry)) { 336749c72efSStephen Hemminger const struct xattr_handler *handler = 3371da177e4SLinus Torvalds ext2_xattr_handler(entry->e_name_index); 3381da177e4SLinus Torvalds 339764a5c6bSAndreas Gruenbacher if (handler && (!handler->list || handler->list(dentry))) { 340764a5c6bSAndreas Gruenbacher const char *prefix = handler->prefix ?: handler->name; 341764a5c6bSAndreas Gruenbacher size_t prefix_len = strlen(prefix); 342764a5c6bSAndreas Gruenbacher size_t size = prefix_len + entry->e_name_len + 1; 343764a5c6bSAndreas Gruenbacher 3441da177e4SLinus Torvalds if (buffer) { 3451da177e4SLinus Torvalds if (size > rest) { 3461da177e4SLinus Torvalds error = -ERANGE; 3471da177e4SLinus Torvalds goto cleanup; 3481da177e4SLinus Torvalds } 349764a5c6bSAndreas Gruenbacher memcpy(buffer, prefix, prefix_len); 350764a5c6bSAndreas Gruenbacher buffer += prefix_len; 351764a5c6bSAndreas Gruenbacher memcpy(buffer, entry->e_name, entry->e_name_len); 352764a5c6bSAndreas Gruenbacher buffer += entry->e_name_len; 353764a5c6bSAndreas Gruenbacher *buffer++ = 0; 3541da177e4SLinus Torvalds } 3551da177e4SLinus Torvalds rest -= size; 3561da177e4SLinus Torvalds } 3571da177e4SLinus Torvalds } 3581da177e4SLinus Torvalds error = buffer_size - rest; /* total size */ 3591da177e4SLinus Torvalds 3601da177e4SLinus Torvalds cleanup: 3611da177e4SLinus Torvalds brelse(bh); 3621da177e4SLinus Torvalds up_read(&EXT2_I(inode)->xattr_sem); 3631da177e4SLinus Torvalds 3641da177e4SLinus Torvalds return error; 3651da177e4SLinus Torvalds } 3661da177e4SLinus Torvalds 3671da177e4SLinus Torvalds /* 3681da177e4SLinus Torvalds * Inode operation listxattr() 3691da177e4SLinus Torvalds * 3702b0143b5SDavid Howells * d_inode(dentry)->i_mutex: don't care 3711da177e4SLinus Torvalds */ 3721da177e4SLinus Torvalds ssize_t 3731da177e4SLinus Torvalds ext2_listxattr(struct dentry *dentry, char *buffer, size_t size) 3741da177e4SLinus Torvalds { 375431547b3SChristoph Hellwig return ext2_xattr_list(dentry, buffer, size); 3761da177e4SLinus Torvalds } 3771da177e4SLinus Torvalds 3781da177e4SLinus Torvalds /* 3791da177e4SLinus Torvalds * If the EXT2_FEATURE_COMPAT_EXT_ATTR feature of this file system is 3801da177e4SLinus Torvalds * not set, set it. 3811da177e4SLinus Torvalds */ 3821da177e4SLinus Torvalds static void ext2_xattr_update_super_block(struct super_block *sb) 3831da177e4SLinus Torvalds { 3841da177e4SLinus Torvalds if (EXT2_HAS_COMPAT_FEATURE(sb, EXT2_FEATURE_COMPAT_EXT_ATTR)) 3851da177e4SLinus Torvalds return; 3861da177e4SLinus Torvalds 387c15271f4SJan Blunck spin_lock(&EXT2_SB(sb)->s_lock); 388032cdc39SJan Kara ext2_update_dynamic_rev(sb); 389ed2908f3SAndreas Gruenbacher EXT2_SET_COMPAT_FEATURE(sb, EXT2_FEATURE_COMPAT_EXT_ATTR); 390c15271f4SJan Blunck spin_unlock(&EXT2_SB(sb)->s_lock); 3911da177e4SLinus Torvalds mark_buffer_dirty(EXT2_SB(sb)->s_sbh); 3921da177e4SLinus Torvalds } 3931da177e4SLinus Torvalds 3941da177e4SLinus Torvalds /* 3951da177e4SLinus Torvalds * ext2_xattr_set() 3961da177e4SLinus Torvalds * 3976e9510b0SWang Sheng-Hui * Create, replace or remove an extended attribute for this inode. Value 3981da177e4SLinus Torvalds * is NULL to remove an existing extended attribute, and non-NULL to 3991da177e4SLinus Torvalds * either replace an existing extended attribute, or create a new extended 4001da177e4SLinus Torvalds * attribute. The flags XATTR_REPLACE and XATTR_CREATE 4011da177e4SLinus Torvalds * specify that an extended attribute must exist and must not exist 4021da177e4SLinus Torvalds * previous to the call, respectively. 4031da177e4SLinus Torvalds * 4041da177e4SLinus Torvalds * Returns 0, or a negative error number on failure. 4051da177e4SLinus Torvalds */ 4061da177e4SLinus Torvalds int 4071da177e4SLinus Torvalds ext2_xattr_set(struct inode *inode, int name_index, const char *name, 4081da177e4SLinus Torvalds const void *value, size_t value_len, int flags) 4091da177e4SLinus Torvalds { 4101da177e4SLinus Torvalds struct super_block *sb = inode->i_sb; 4111da177e4SLinus Torvalds struct buffer_head *bh = NULL; 4121da177e4SLinus Torvalds struct ext2_xattr_header *header = NULL; 4139bb1d7a6SChengguang Xu struct ext2_xattr_entry *here = NULL, *last = NULL; 4141da177e4SLinus Torvalds size_t name_len, free, min_offs = sb->s_blocksize; 4151da177e4SLinus Torvalds int not_found = 1, error; 4161da177e4SLinus Torvalds char *end; 4171da177e4SLinus Torvalds 4181da177e4SLinus Torvalds /* 4191da177e4SLinus Torvalds * header -- Points either into bh, or to a temporarily 4201da177e4SLinus Torvalds * allocated buffer. 4211da177e4SLinus Torvalds * here -- The named entry found, or the place for inserting, within 4221da177e4SLinus Torvalds * the block pointed to by header. 4231da177e4SLinus Torvalds * last -- Points right after the last named entry within the block 4241da177e4SLinus Torvalds * pointed to by header. 4251da177e4SLinus Torvalds * min_offs -- The offset of the first value (values are aligned 4261da177e4SLinus Torvalds * towards the end of the block). 4271da177e4SLinus Torvalds * end -- Points right after the block pointed to by header. 4281da177e4SLinus Torvalds */ 4291da177e4SLinus Torvalds 4301da177e4SLinus Torvalds ea_idebug(inode, "name=%d.%s, value=%p, value_len=%ld", 4311da177e4SLinus Torvalds name_index, name, value, (long)value_len); 4321da177e4SLinus Torvalds 4331da177e4SLinus Torvalds if (value == NULL) 4341da177e4SLinus Torvalds value_len = 0; 4351da177e4SLinus Torvalds if (name == NULL) 4361da177e4SLinus Torvalds return -EINVAL; 4371da177e4SLinus Torvalds name_len = strlen(name); 4381da177e4SLinus Torvalds if (name_len > 255 || value_len > sb->s_blocksize) 4391da177e4SLinus Torvalds return -ERANGE; 4401da177e4SLinus Torvalds down_write(&EXT2_I(inode)->xattr_sem); 4411da177e4SLinus Torvalds if (EXT2_I(inode)->i_file_acl) { 4421da177e4SLinus Torvalds /* The inode already has an extended attribute block. */ 4431da177e4SLinus Torvalds bh = sb_bread(sb, EXT2_I(inode)->i_file_acl); 4441da177e4SLinus Torvalds error = -EIO; 4451da177e4SLinus Torvalds if (!bh) 4461da177e4SLinus Torvalds goto cleanup; 4471da177e4SLinus Torvalds ea_bdebug(bh, "b_count=%d, refcount=%d", 4481da177e4SLinus Torvalds atomic_read(&(bh->b_count)), 4491da177e4SLinus Torvalds le32_to_cpu(HDR(bh)->h_refcount)); 4501da177e4SLinus Torvalds header = HDR(bh); 4511da177e4SLinus Torvalds end = bh->b_data + bh->b_size; 45202475de9SChengguang Xu if (!ext2_xattr_header_valid(header)) { 45302475de9SChengguang Xu bad_block: 45402475de9SChengguang Xu ext2_error(sb, "ext2_xattr_set", 4551da177e4SLinus Torvalds "inode %ld: bad block %d", inode->i_ino, 4561da177e4SLinus Torvalds EXT2_I(inode)->i_file_acl); 4571da177e4SLinus Torvalds error = -EIO; 4581da177e4SLinus Torvalds goto cleanup; 4591da177e4SLinus Torvalds } 4608cd0f2baSJan Kara /* 4618cd0f2baSJan Kara * Find the named attribute. If not found, 'here' will point 4628cd0f2baSJan Kara * to entry where the new attribute should be inserted to 4638cd0f2baSJan Kara * maintain sorting. 4648cd0f2baSJan Kara */ 4658cd0f2baSJan Kara last = FIRST_ENTRY(bh); 4661da177e4SLinus Torvalds while (!IS_LAST_ENTRY(last)) { 4679bb1d7a6SChengguang Xu if (!ext2_xattr_entry_valid(last, end, sb->s_blocksize)) 4686c71b489SJan Kara goto bad_block; 4696c71b489SJan Kara if (last->e_value_size) { 4701da177e4SLinus Torvalds size_t offs = le16_to_cpu(last->e_value_offs); 4711da177e4SLinus Torvalds if (offs < min_offs) 4721da177e4SLinus Torvalds min_offs = offs; 4731da177e4SLinus Torvalds } 4748cd0f2baSJan Kara if (not_found > 0) { 475d561d4ddSChengguang Xu not_found = ext2_xattr_cmp_entry(name_index, 476d561d4ddSChengguang Xu name_len, 477d561d4ddSChengguang Xu name, last); 4788cd0f2baSJan Kara if (not_found <= 0) 4798cd0f2baSJan Kara here = last; 4808cd0f2baSJan Kara } 4819bb1d7a6SChengguang Xu last = EXT2_XATTR_NEXT(last); 4821da177e4SLinus Torvalds } 4838cd0f2baSJan Kara if (not_found > 0) 4848cd0f2baSJan Kara here = last; 4851da177e4SLinus Torvalds 4861da177e4SLinus Torvalds /* Check whether we have enough space left. */ 4871da177e4SLinus Torvalds free = min_offs - ((char*)last - (char*)header) - sizeof(__u32); 4881da177e4SLinus Torvalds } else { 4891da177e4SLinus Torvalds /* We will use a new extended attribute block. */ 4901da177e4SLinus Torvalds free = sb->s_blocksize - 4911da177e4SLinus Torvalds sizeof(struct ext2_xattr_header) - sizeof(__u32); 4921da177e4SLinus Torvalds } 4931da177e4SLinus Torvalds 4941da177e4SLinus Torvalds if (not_found) { 4951da177e4SLinus Torvalds /* Request to remove a nonexistent attribute? */ 4961da177e4SLinus Torvalds error = -ENODATA; 4971da177e4SLinus Torvalds if (flags & XATTR_REPLACE) 4981da177e4SLinus Torvalds goto cleanup; 4991da177e4SLinus Torvalds error = 0; 5001da177e4SLinus Torvalds if (value == NULL) 5011da177e4SLinus Torvalds goto cleanup; 5021da177e4SLinus Torvalds } else { 5031da177e4SLinus Torvalds /* Request to create an existing attribute? */ 5041da177e4SLinus Torvalds error = -EEXIST; 5051da177e4SLinus Torvalds if (flags & XATTR_CREATE) 5061da177e4SLinus Torvalds goto cleanup; 5076c71b489SJan Kara free += EXT2_XATTR_SIZE(le32_to_cpu(here->e_value_size)); 5081da177e4SLinus Torvalds free += EXT2_XATTR_LEN(name_len); 5091da177e4SLinus Torvalds } 5101da177e4SLinus Torvalds error = -ENOSPC; 5111da177e4SLinus Torvalds if (free < EXT2_XATTR_LEN(name_len) + EXT2_XATTR_SIZE(value_len)) 5121da177e4SLinus Torvalds goto cleanup; 5131da177e4SLinus Torvalds 5141da177e4SLinus Torvalds /* Here we know that we can set the new attribute. */ 5151da177e4SLinus Torvalds 5161da177e4SLinus Torvalds if (header) { 5171da177e4SLinus Torvalds /* assert(header == HDR(bh)); */ 5181da177e4SLinus Torvalds lock_buffer(bh); 5191da177e4SLinus Torvalds if (header->h_refcount == cpu_to_le32(1)) { 520be0726d3SJan Kara __u32 hash = le32_to_cpu(header->h_hash); 521be0726d3SJan Kara 5221da177e4SLinus Torvalds ea_bdebug(bh, "modifying in-place"); 523be0726d3SJan Kara /* 524be0726d3SJan Kara * This must happen under buffer lock for 525be0726d3SJan Kara * ext2_xattr_set2() to reliably detect modified block 526be0726d3SJan Kara */ 52747387409STahsin Erdogan mb_cache_entry_delete(EA_BLOCK_CACHE(inode), hash, 528c07dfcb4STahsin Erdogan bh->b_blocknr); 529be0726d3SJan Kara 5301da177e4SLinus Torvalds /* keep the buffer locked while modifying it. */ 5311da177e4SLinus Torvalds } else { 5321da177e4SLinus Torvalds int offset; 5331da177e4SLinus Torvalds 5341da177e4SLinus Torvalds unlock_buffer(bh); 5351da177e4SLinus Torvalds ea_bdebug(bh, "cloning"); 53690f15ac9SFuqian Huang header = kmemdup(HDR(bh), bh->b_size, GFP_KERNEL); 5371da177e4SLinus Torvalds error = -ENOMEM; 5381da177e4SLinus Torvalds if (header == NULL) 5391da177e4SLinus Torvalds goto cleanup; 5401da177e4SLinus Torvalds header->h_refcount = cpu_to_le32(1); 5411da177e4SLinus Torvalds 5421da177e4SLinus Torvalds offset = (char *)here - bh->b_data; 5431da177e4SLinus Torvalds here = ENTRY((char *)header + offset); 5441da177e4SLinus Torvalds offset = (char *)last - bh->b_data; 5451da177e4SLinus Torvalds last = ENTRY((char *)header + offset); 5461da177e4SLinus Torvalds } 5471da177e4SLinus Torvalds } else { 5481da177e4SLinus Torvalds /* Allocate a buffer where we construct the new block. */ 549f8314dc6SPanagiotis Issaris header = kzalloc(sb->s_blocksize, GFP_KERNEL); 5501da177e4SLinus Torvalds error = -ENOMEM; 5511da177e4SLinus Torvalds if (header == NULL) 5521da177e4SLinus Torvalds goto cleanup; 5531da177e4SLinus Torvalds end = (char *)header + sb->s_blocksize; 5541da177e4SLinus Torvalds header->h_magic = cpu_to_le32(EXT2_XATTR_MAGIC); 5551da177e4SLinus Torvalds header->h_blocks = header->h_refcount = cpu_to_le32(1); 5561da177e4SLinus Torvalds last = here = ENTRY(header+1); 5571da177e4SLinus Torvalds } 5581da177e4SLinus Torvalds 5591da177e4SLinus Torvalds /* Iff we are modifying the block in-place, bh is locked here. */ 5601da177e4SLinus Torvalds 5611da177e4SLinus Torvalds if (not_found) { 5621da177e4SLinus Torvalds /* Insert the new name. */ 5631da177e4SLinus Torvalds size_t size = EXT2_XATTR_LEN(name_len); 5641da177e4SLinus Torvalds size_t rest = (char *)last - (char *)here; 5651da177e4SLinus Torvalds memmove((char *)here + size, here, rest); 5661da177e4SLinus Torvalds memset(here, 0, size); 5671da177e4SLinus Torvalds here->e_name_index = name_index; 5681da177e4SLinus Torvalds here->e_name_len = name_len; 5691da177e4SLinus Torvalds memcpy(here->e_name, name, name_len); 5701da177e4SLinus Torvalds } else { 5716c71b489SJan Kara if (here->e_value_size) { 5721da177e4SLinus Torvalds char *first_val = (char *)header + min_offs; 5731da177e4SLinus Torvalds size_t offs = le16_to_cpu(here->e_value_offs); 5741da177e4SLinus Torvalds char *val = (char *)header + offs; 5751da177e4SLinus Torvalds size_t size = EXT2_XATTR_SIZE( 5761da177e4SLinus Torvalds le32_to_cpu(here->e_value_size)); 5771da177e4SLinus Torvalds 5781da177e4SLinus Torvalds if (size == EXT2_XATTR_SIZE(value_len)) { 5791da177e4SLinus Torvalds /* The old and the new value have the same 5801da177e4SLinus Torvalds size. Just replace. */ 5811da177e4SLinus Torvalds here->e_value_size = cpu_to_le32(value_len); 5821da177e4SLinus Torvalds memset(val + size - EXT2_XATTR_PAD, 0, 5831da177e4SLinus Torvalds EXT2_XATTR_PAD); /* Clear pad bytes. */ 5841da177e4SLinus Torvalds memcpy(val, value, value_len); 5851da177e4SLinus Torvalds goto skip_replace; 5861da177e4SLinus Torvalds } 5871da177e4SLinus Torvalds 5881da177e4SLinus Torvalds /* Remove the old value. */ 5891da177e4SLinus Torvalds memmove(first_val + size, first_val, val - first_val); 5901da177e4SLinus Torvalds memset(first_val, 0, size); 5911da177e4SLinus Torvalds min_offs += size; 5921da177e4SLinus Torvalds 5931da177e4SLinus Torvalds /* Adjust all value offsets. */ 5941da177e4SLinus Torvalds last = ENTRY(header+1); 5951da177e4SLinus Torvalds while (!IS_LAST_ENTRY(last)) { 5961da177e4SLinus Torvalds size_t o = le16_to_cpu(last->e_value_offs); 5976c71b489SJan Kara if (o < offs) 5981da177e4SLinus Torvalds last->e_value_offs = 5991da177e4SLinus Torvalds cpu_to_le16(o + size); 6001da177e4SLinus Torvalds last = EXT2_XATTR_NEXT(last); 6011da177e4SLinus Torvalds } 6021fcbcf06SChengguang Xu 6031fcbcf06SChengguang Xu here->e_value_offs = 0; 6041da177e4SLinus Torvalds } 6051da177e4SLinus Torvalds if (value == NULL) { 6061da177e4SLinus Torvalds /* Remove the old name. */ 6071da177e4SLinus Torvalds size_t size = EXT2_XATTR_LEN(name_len); 6081da177e4SLinus Torvalds last = ENTRY((char *)last - size); 6091da177e4SLinus Torvalds memmove(here, (char*)here + size, 6101da177e4SLinus Torvalds (char*)last - (char*)here); 6111da177e4SLinus Torvalds memset(last, 0, size); 6121da177e4SLinus Torvalds } 6131da177e4SLinus Torvalds } 6141da177e4SLinus Torvalds 6151da177e4SLinus Torvalds if (value != NULL) { 6161da177e4SLinus Torvalds /* Insert the new value. */ 6171da177e4SLinus Torvalds here->e_value_size = cpu_to_le32(value_len); 6181da177e4SLinus Torvalds if (value_len) { 6191da177e4SLinus Torvalds size_t size = EXT2_XATTR_SIZE(value_len); 6201da177e4SLinus Torvalds char *val = (char *)header + min_offs - size; 6211da177e4SLinus Torvalds here->e_value_offs = 6221da177e4SLinus Torvalds cpu_to_le16((char *)val - (char *)header); 6231da177e4SLinus Torvalds memset(val + size - EXT2_XATTR_PAD, 0, 6241da177e4SLinus Torvalds EXT2_XATTR_PAD); /* Clear the pad bytes. */ 6251da177e4SLinus Torvalds memcpy(val, value, value_len); 6261da177e4SLinus Torvalds } 6271da177e4SLinus Torvalds } 6281da177e4SLinus Torvalds 6291da177e4SLinus Torvalds skip_replace: 6301da177e4SLinus Torvalds if (IS_LAST_ENTRY(ENTRY(header+1))) { 6311da177e4SLinus Torvalds /* This block is now empty. */ 6321da177e4SLinus Torvalds if (bh && header == HDR(bh)) 6331da177e4SLinus Torvalds unlock_buffer(bh); /* we were modifying in-place. */ 6341da177e4SLinus Torvalds error = ext2_xattr_set2(inode, bh, NULL); 6351da177e4SLinus Torvalds } else { 6361da177e4SLinus Torvalds ext2_xattr_rehash(header, here); 6371da177e4SLinus Torvalds if (bh && header == HDR(bh)) 6381da177e4SLinus Torvalds unlock_buffer(bh); /* we were modifying in-place. */ 6391da177e4SLinus Torvalds error = ext2_xattr_set2(inode, bh, header); 6401da177e4SLinus Torvalds } 6411da177e4SLinus Torvalds 6421da177e4SLinus Torvalds cleanup: 6431da177e4SLinus Torvalds if (!(bh && header == HDR(bh))) 6441da177e4SLinus Torvalds kfree(header); 645ecebf55dSPan Bian brelse(bh); 6461da177e4SLinus Torvalds up_write(&EXT2_I(inode)->xattr_sem); 6471da177e4SLinus Torvalds 6481da177e4SLinus Torvalds return error; 6491da177e4SLinus Torvalds } 6501da177e4SLinus Torvalds 6511da177e4SLinus Torvalds /* 6521da177e4SLinus Torvalds * Second half of ext2_xattr_set(): Update the file system. 6531da177e4SLinus Torvalds */ 6541da177e4SLinus Torvalds static int 6551da177e4SLinus Torvalds ext2_xattr_set2(struct inode *inode, struct buffer_head *old_bh, 6561da177e4SLinus Torvalds struct ext2_xattr_header *header) 6571da177e4SLinus Torvalds { 6581da177e4SLinus Torvalds struct super_block *sb = inode->i_sb; 6591da177e4SLinus Torvalds struct buffer_head *new_bh = NULL; 6601da177e4SLinus Torvalds int error; 66147387409STahsin Erdogan struct mb_cache *ea_block_cache = EA_BLOCK_CACHE(inode); 6621da177e4SLinus Torvalds 6631da177e4SLinus Torvalds if (header) { 6641da177e4SLinus Torvalds new_bh = ext2_xattr_cache_find(inode, header); 6651da177e4SLinus Torvalds if (new_bh) { 6661da177e4SLinus Torvalds /* We found an identical block in the cache. */ 6671da177e4SLinus Torvalds if (new_bh == old_bh) { 6681da177e4SLinus Torvalds ea_bdebug(new_bh, "keeping this block"); 6691da177e4SLinus Torvalds } else { 6701da177e4SLinus Torvalds /* The old block is released after updating 6711da177e4SLinus Torvalds the inode. */ 6721da177e4SLinus Torvalds ea_bdebug(new_bh, "reusing block"); 6731da177e4SLinus Torvalds 6745dd4056dSChristoph Hellwig error = dquot_alloc_block(inode, 1); 6755dd4056dSChristoph Hellwig if (error) { 6761da177e4SLinus Torvalds unlock_buffer(new_bh); 6771da177e4SLinus Torvalds goto cleanup; 6781da177e4SLinus Torvalds } 679fba4d399SMarcin Slusarz le32_add_cpu(&HDR(new_bh)->h_refcount, 1); 6801da177e4SLinus Torvalds ea_bdebug(new_bh, "refcount now=%d", 6811da177e4SLinus Torvalds le32_to_cpu(HDR(new_bh)->h_refcount)); 6821da177e4SLinus Torvalds } 6831da177e4SLinus Torvalds unlock_buffer(new_bh); 6841da177e4SLinus Torvalds } else if (old_bh && header == HDR(old_bh)) { 6851da177e4SLinus Torvalds /* Keep this block. No need to lock the block as we 6861da177e4SLinus Torvalds don't need to change the reference count. */ 6871da177e4SLinus Torvalds new_bh = old_bh; 6881da177e4SLinus Torvalds get_bh(new_bh); 68947387409STahsin Erdogan ext2_xattr_cache_insert(ea_block_cache, new_bh); 6901da177e4SLinus Torvalds } else { 6911da177e4SLinus Torvalds /* We need to allocate a new block */ 69224097d12SAkinobu Mita ext2_fsblk_t goal = ext2_group_first_block_no(sb, 69324097d12SAkinobu Mita EXT2_I(inode)->i_block_group); 694a686cd89SMartin J. Bligh int block = ext2_new_block(inode, goal, &error); 6951da177e4SLinus Torvalds if (error) 6961da177e4SLinus Torvalds goto cleanup; 6971da177e4SLinus Torvalds ea_idebug(inode, "creating block %d", block); 6981da177e4SLinus Torvalds 6991da177e4SLinus Torvalds new_bh = sb_getblk(sb, block); 7002b0542a4SWang Shilong if (unlikely(!new_bh)) { 7011da177e4SLinus Torvalds ext2_free_blocks(inode, block, 1); 702addacc7dSAl Viro mark_inode_dirty(inode); 703ab6a773dSWang Shilong error = -ENOMEM; 7041da177e4SLinus Torvalds goto cleanup; 7051da177e4SLinus Torvalds } 7061da177e4SLinus Torvalds lock_buffer(new_bh); 7071da177e4SLinus Torvalds memcpy(new_bh->b_data, header, new_bh->b_size); 7081da177e4SLinus Torvalds set_buffer_uptodate(new_bh); 7091da177e4SLinus Torvalds unlock_buffer(new_bh); 71047387409STahsin Erdogan ext2_xattr_cache_insert(ea_block_cache, new_bh); 7111da177e4SLinus Torvalds 7121da177e4SLinus Torvalds ext2_xattr_update_super_block(sb); 7131da177e4SLinus Torvalds } 7141da177e4SLinus Torvalds mark_buffer_dirty(new_bh); 7151da177e4SLinus Torvalds if (IS_SYNC(inode)) { 7161da177e4SLinus Torvalds sync_dirty_buffer(new_bh); 7171da177e4SLinus Torvalds error = -EIO; 7181da177e4SLinus Torvalds if (buffer_req(new_bh) && !buffer_uptodate(new_bh)) 7191da177e4SLinus Torvalds goto cleanup; 7201da177e4SLinus Torvalds } 7211da177e4SLinus Torvalds } 7221da177e4SLinus Torvalds 7231da177e4SLinus Torvalds /* Update the inode. */ 7241da177e4SLinus Torvalds EXT2_I(inode)->i_file_acl = new_bh ? new_bh->b_blocknr : 0; 72502027d42SDeepa Dinamani inode->i_ctime = current_time(inode); 7261da177e4SLinus Torvalds if (IS_SYNC(inode)) { 727c3765016SChristoph Hellwig error = sync_inode_metadata(inode, 1); 7281da177e4SLinus Torvalds /* In case sync failed due to ENOSPC the inode was actually 7291da177e4SLinus Torvalds * written (only some dirty data were not) so we just proceed 7301da177e4SLinus Torvalds * as if nothing happened and cleanup the unused block */ 7311da177e4SLinus Torvalds if (error && error != -ENOSPC) { 7323889717dSAl Viro if (new_bh && new_bh != old_bh) { 7333889717dSAl Viro dquot_free_block_nodirty(inode, 1); 7343889717dSAl Viro mark_inode_dirty(inode); 7353889717dSAl Viro } 7361da177e4SLinus Torvalds goto cleanup; 7371da177e4SLinus Torvalds } 7381da177e4SLinus Torvalds } else 7391da177e4SLinus Torvalds mark_inode_dirty(inode); 7401da177e4SLinus Torvalds 7411da177e4SLinus Torvalds error = 0; 7421da177e4SLinus Torvalds if (old_bh && old_bh != new_bh) { 7431da177e4SLinus Torvalds /* 7441da177e4SLinus Torvalds * If there was an old block and we are no longer using it, 7451da177e4SLinus Torvalds * release the old block. 7461da177e4SLinus Torvalds */ 7471da177e4SLinus Torvalds lock_buffer(old_bh); 7481da177e4SLinus Torvalds if (HDR(old_bh)->h_refcount == cpu_to_le32(1)) { 749be0726d3SJan Kara __u32 hash = le32_to_cpu(HDR(old_bh)->h_hash); 750be0726d3SJan Kara 751be0726d3SJan Kara /* 752be0726d3SJan Kara * This must happen under buffer lock for 753be0726d3SJan Kara * ext2_xattr_set2() to reliably detect freed block 754be0726d3SJan Kara */ 75547387409STahsin Erdogan mb_cache_entry_delete(ea_block_cache, hash, 756c07dfcb4STahsin Erdogan old_bh->b_blocknr); 7571da177e4SLinus Torvalds /* Free the old block. */ 7581da177e4SLinus Torvalds ea_bdebug(old_bh, "freeing"); 7591da177e4SLinus Torvalds ext2_free_blocks(inode, old_bh->b_blocknr, 1); 760addacc7dSAl Viro mark_inode_dirty(inode); 7611da177e4SLinus Torvalds /* We let our caller release old_bh, so we 7621da177e4SLinus Torvalds * need to duplicate the buffer before. */ 7631da177e4SLinus Torvalds get_bh(old_bh); 7641da177e4SLinus Torvalds bforget(old_bh); 7651da177e4SLinus Torvalds } else { 7661da177e4SLinus Torvalds /* Decrement the refcount only. */ 767fba4d399SMarcin Slusarz le32_add_cpu(&HDR(old_bh)->h_refcount, -1); 7683889717dSAl Viro dquot_free_block_nodirty(inode, 1); 7693889717dSAl Viro mark_inode_dirty(inode); 7701da177e4SLinus Torvalds mark_buffer_dirty(old_bh); 7711da177e4SLinus Torvalds ea_bdebug(old_bh, "refcount now=%d", 7721da177e4SLinus Torvalds le32_to_cpu(HDR(old_bh)->h_refcount)); 7731da177e4SLinus Torvalds } 7741da177e4SLinus Torvalds unlock_buffer(old_bh); 7751da177e4SLinus Torvalds } 7761da177e4SLinus Torvalds 7771da177e4SLinus Torvalds cleanup: 7781da177e4SLinus Torvalds brelse(new_bh); 7791da177e4SLinus Torvalds 7801da177e4SLinus Torvalds return error; 7811da177e4SLinus Torvalds } 7821da177e4SLinus Torvalds 7831da177e4SLinus Torvalds /* 7841da177e4SLinus Torvalds * ext2_xattr_delete_inode() 7851da177e4SLinus Torvalds * 7861da177e4SLinus Torvalds * Free extended attribute resources associated with this inode. This 7871da177e4SLinus Torvalds * is called immediately before an inode is freed. 7881da177e4SLinus Torvalds */ 7891da177e4SLinus Torvalds void 7901da177e4SLinus Torvalds ext2_xattr_delete_inode(struct inode *inode) 7911da177e4SLinus Torvalds { 7921da177e4SLinus Torvalds struct buffer_head *bh = NULL; 793ff0031d8SCarlos Maiolino struct ext2_sb_info *sbi = EXT2_SB(inode->i_sb); 7941da177e4SLinus Torvalds 795bc36dfffSJan Kara /* 796bc36dfffSJan Kara * We are the only ones holding inode reference. The xattr_sem should 797bc36dfffSJan Kara * better be unlocked! We could as well just not acquire xattr_sem at 798bc36dfffSJan Kara * all but this makes the code more futureproof. OTOH we need trylock 799bc36dfffSJan Kara * here to avoid false-positive warning from lockdep about reclaim 800bc36dfffSJan Kara * circular dependency. 801bc36dfffSJan Kara */ 802bc36dfffSJan Kara if (WARN_ON_ONCE(!down_write_trylock(&EXT2_I(inode)->xattr_sem))) 803bc36dfffSJan Kara return; 8041da177e4SLinus Torvalds if (!EXT2_I(inode)->i_file_acl) 8051da177e4SLinus Torvalds goto cleanup; 806ff0031d8SCarlos Maiolino 807e5d39597SChengguang Xu if (!ext2_data_block_valid(sbi, EXT2_I(inode)->i_file_acl, 1)) { 808ff0031d8SCarlos Maiolino ext2_error(inode->i_sb, "ext2_xattr_delete_inode", 809ff0031d8SCarlos Maiolino "inode %ld: xattr block %d is out of data blocks range", 810ff0031d8SCarlos Maiolino inode->i_ino, EXT2_I(inode)->i_file_acl); 811ff0031d8SCarlos Maiolino goto cleanup; 812ff0031d8SCarlos Maiolino } 813ff0031d8SCarlos Maiolino 8141da177e4SLinus Torvalds bh = sb_bread(inode->i_sb, EXT2_I(inode)->i_file_acl); 8151da177e4SLinus Torvalds if (!bh) { 8161da177e4SLinus Torvalds ext2_error(inode->i_sb, "ext2_xattr_delete_inode", 8171da177e4SLinus Torvalds "inode %ld: block %d read error", inode->i_ino, 8181da177e4SLinus Torvalds EXT2_I(inode)->i_file_acl); 8191da177e4SLinus Torvalds goto cleanup; 8201da177e4SLinus Torvalds } 8211da177e4SLinus Torvalds ea_bdebug(bh, "b_count=%d", atomic_read(&(bh->b_count))); 82202475de9SChengguang Xu if (!ext2_xattr_header_valid(HDR(bh))) { 8231da177e4SLinus Torvalds ext2_error(inode->i_sb, "ext2_xattr_delete_inode", 8241da177e4SLinus Torvalds "inode %ld: bad block %d", inode->i_ino, 8251da177e4SLinus Torvalds EXT2_I(inode)->i_file_acl); 8261da177e4SLinus Torvalds goto cleanup; 8271da177e4SLinus Torvalds } 8281da177e4SLinus Torvalds lock_buffer(bh); 8291da177e4SLinus Torvalds if (HDR(bh)->h_refcount == cpu_to_le32(1)) { 830be0726d3SJan Kara __u32 hash = le32_to_cpu(HDR(bh)->h_hash); 831be0726d3SJan Kara 832be0726d3SJan Kara /* 833be0726d3SJan Kara * This must happen under buffer lock for ext2_xattr_set2() to 834be0726d3SJan Kara * reliably detect freed block 835be0726d3SJan Kara */ 83647387409STahsin Erdogan mb_cache_entry_delete(EA_BLOCK_CACHE(inode), hash, 837c07dfcb4STahsin Erdogan bh->b_blocknr); 8381da177e4SLinus Torvalds ext2_free_blocks(inode, EXT2_I(inode)->i_file_acl, 1); 8391da177e4SLinus Torvalds get_bh(bh); 8401da177e4SLinus Torvalds bforget(bh); 841b2f49033SPeter Staubach unlock_buffer(bh); 8421da177e4SLinus Torvalds } else { 843fba4d399SMarcin Slusarz le32_add_cpu(&HDR(bh)->h_refcount, -1); 844b2f49033SPeter Staubach ea_bdebug(bh, "refcount now=%d", 845b2f49033SPeter Staubach le32_to_cpu(HDR(bh)->h_refcount)); 846b2f49033SPeter Staubach unlock_buffer(bh); 8471da177e4SLinus Torvalds mark_buffer_dirty(bh); 8481da177e4SLinus Torvalds if (IS_SYNC(inode)) 8491da177e4SLinus Torvalds sync_dirty_buffer(bh); 8503889717dSAl Viro dquot_free_block_nodirty(inode, 1); 8511da177e4SLinus Torvalds } 8521da177e4SLinus Torvalds EXT2_I(inode)->i_file_acl = 0; 8531da177e4SLinus Torvalds 8541da177e4SLinus Torvalds cleanup: 8551da177e4SLinus Torvalds brelse(bh); 8561da177e4SLinus Torvalds up_write(&EXT2_I(inode)->xattr_sem); 8571da177e4SLinus Torvalds } 8581da177e4SLinus Torvalds 8591da177e4SLinus Torvalds /* 8601da177e4SLinus Torvalds * ext2_xattr_cache_insert() 8611da177e4SLinus Torvalds * 8621da177e4SLinus Torvalds * Create a new entry in the extended attribute cache, and insert 8631da177e4SLinus Torvalds * it unless such an entry is already in the cache. 8641da177e4SLinus Torvalds * 8651da177e4SLinus Torvalds * Returns 0, or a negative error number on failure. 8661da177e4SLinus Torvalds */ 8671da177e4SLinus Torvalds static int 8687a2508e1SJan Kara ext2_xattr_cache_insert(struct mb_cache *cache, struct buffer_head *bh) 8691da177e4SLinus Torvalds { 8701da177e4SLinus Torvalds __u32 hash = le32_to_cpu(HDR(bh)->h_hash); 8711da177e4SLinus Torvalds int error; 8721da177e4SLinus Torvalds 8733e159b95SChengguang Xu error = mb_cache_entry_create(cache, GFP_NOFS, hash, bh->b_blocknr, 8743e159b95SChengguang Xu true); 8751da177e4SLinus Torvalds if (error) { 8761da177e4SLinus Torvalds if (error == -EBUSY) { 87732302085SJan Kara ea_bdebug(bh, "already in cache"); 8781da177e4SLinus Torvalds error = 0; 8791da177e4SLinus Torvalds } 880be0726d3SJan Kara } else 881be0726d3SJan Kara ea_bdebug(bh, "inserting [%x]", (int)hash); 8821da177e4SLinus Torvalds return error; 8831da177e4SLinus Torvalds } 8841da177e4SLinus Torvalds 8851da177e4SLinus Torvalds /* 8861da177e4SLinus Torvalds * ext2_xattr_cmp() 8871da177e4SLinus Torvalds * 8881da177e4SLinus Torvalds * Compare two extended attribute blocks for equality. 8891da177e4SLinus Torvalds * 8901da177e4SLinus Torvalds * Returns 0 if the blocks are equal, 1 if they differ, and 8911da177e4SLinus Torvalds * a negative error number on errors. 8921da177e4SLinus Torvalds */ 8931da177e4SLinus Torvalds static int 8941da177e4SLinus Torvalds ext2_xattr_cmp(struct ext2_xattr_header *header1, 8951da177e4SLinus Torvalds struct ext2_xattr_header *header2) 8961da177e4SLinus Torvalds { 8971da177e4SLinus Torvalds struct ext2_xattr_entry *entry1, *entry2; 8981da177e4SLinus Torvalds 8991da177e4SLinus Torvalds entry1 = ENTRY(header1+1); 9001da177e4SLinus Torvalds entry2 = ENTRY(header2+1); 9011da177e4SLinus Torvalds while (!IS_LAST_ENTRY(entry1)) { 9021da177e4SLinus Torvalds if (IS_LAST_ENTRY(entry2)) 9031da177e4SLinus Torvalds return 1; 9041da177e4SLinus Torvalds if (entry1->e_hash != entry2->e_hash || 9051da177e4SLinus Torvalds entry1->e_name_index != entry2->e_name_index || 9061da177e4SLinus Torvalds entry1->e_name_len != entry2->e_name_len || 9071da177e4SLinus Torvalds entry1->e_value_size != entry2->e_value_size || 9081da177e4SLinus Torvalds memcmp(entry1->e_name, entry2->e_name, entry1->e_name_len)) 9091da177e4SLinus Torvalds return 1; 9101da177e4SLinus Torvalds if (entry1->e_value_block != 0 || entry2->e_value_block != 0) 9111da177e4SLinus Torvalds return -EIO; 9121da177e4SLinus Torvalds if (memcmp((char *)header1 + le16_to_cpu(entry1->e_value_offs), 9131da177e4SLinus Torvalds (char *)header2 + le16_to_cpu(entry2->e_value_offs), 9141da177e4SLinus Torvalds le32_to_cpu(entry1->e_value_size))) 9151da177e4SLinus Torvalds return 1; 9161da177e4SLinus Torvalds 9171da177e4SLinus Torvalds entry1 = EXT2_XATTR_NEXT(entry1); 9181da177e4SLinus Torvalds entry2 = EXT2_XATTR_NEXT(entry2); 9191da177e4SLinus Torvalds } 9201da177e4SLinus Torvalds if (!IS_LAST_ENTRY(entry2)) 9211da177e4SLinus Torvalds return 1; 9221da177e4SLinus Torvalds return 0; 9231da177e4SLinus Torvalds } 9241da177e4SLinus Torvalds 9251da177e4SLinus Torvalds /* 9261da177e4SLinus Torvalds * ext2_xattr_cache_find() 9271da177e4SLinus Torvalds * 9281da177e4SLinus Torvalds * Find an identical extended attribute block. 9291da177e4SLinus Torvalds * 9301da177e4SLinus Torvalds * Returns a locked buffer head to the block found, or NULL if such 9311da177e4SLinus Torvalds * a block was not found or an error occurred. 9321da177e4SLinus Torvalds */ 9331da177e4SLinus Torvalds static struct buffer_head * 9341da177e4SLinus Torvalds ext2_xattr_cache_find(struct inode *inode, struct ext2_xattr_header *header) 9351da177e4SLinus Torvalds { 9361da177e4SLinus Torvalds __u32 hash = le32_to_cpu(header->h_hash); 9377a2508e1SJan Kara struct mb_cache_entry *ce; 93847387409STahsin Erdogan struct mb_cache *ea_block_cache = EA_BLOCK_CACHE(inode); 9391da177e4SLinus Torvalds 9401da177e4SLinus Torvalds if (!header->h_hash) 9411da177e4SLinus Torvalds return NULL; /* never share */ 9421da177e4SLinus Torvalds ea_idebug(inode, "looking for cached blocks [%x]", (int)hash); 9431da177e4SLinus Torvalds again: 94447387409STahsin Erdogan ce = mb_cache_entry_find_first(ea_block_cache, hash); 9451da177e4SLinus Torvalds while (ce) { 9461da177e4SLinus Torvalds struct buffer_head *bh; 9471da177e4SLinus Torvalds 948c07dfcb4STahsin Erdogan bh = sb_bread(inode->i_sb, ce->e_value); 9491da177e4SLinus Torvalds if (!bh) { 9501da177e4SLinus Torvalds ext2_error(inode->i_sb, "ext2_xattr_cache_find", 9511da177e4SLinus Torvalds "inode %ld: block %ld read error", 952c07dfcb4STahsin Erdogan inode->i_ino, (unsigned long) ce->e_value); 9531da177e4SLinus Torvalds } else { 9541da177e4SLinus Torvalds lock_buffer(bh); 955be0726d3SJan Kara /* 956be0726d3SJan Kara * We have to be careful about races with freeing or 957be0726d3SJan Kara * rehashing of xattr block. Once we hold buffer lock 958be0726d3SJan Kara * xattr block's state is stable so we can check 959be0726d3SJan Kara * whether the block got freed / rehashed or not. 960be0726d3SJan Kara * Since we unhash mbcache entry under buffer lock when 961be0726d3SJan Kara * freeing / rehashing xattr block, checking whether 962be0726d3SJan Kara * entry is still hashed is reliable. 963be0726d3SJan Kara */ 964be0726d3SJan Kara if (hlist_bl_unhashed(&ce->e_hash_list)) { 96547387409STahsin Erdogan mb_cache_entry_put(ea_block_cache, ce); 966be0726d3SJan Kara unlock_buffer(bh); 967be0726d3SJan Kara brelse(bh); 968be0726d3SJan Kara goto again; 969be0726d3SJan Kara } else if (le32_to_cpu(HDR(bh)->h_refcount) > 9701da177e4SLinus Torvalds EXT2_XATTR_REFCOUNT_MAX) { 9711da177e4SLinus Torvalds ea_idebug(inode, "block %ld refcount %d>%d", 972c07dfcb4STahsin Erdogan (unsigned long) ce->e_value, 9731da177e4SLinus Torvalds le32_to_cpu(HDR(bh)->h_refcount), 9741da177e4SLinus Torvalds EXT2_XATTR_REFCOUNT_MAX); 9751da177e4SLinus Torvalds } else if (!ext2_xattr_cmp(header, HDR(bh))) { 9761da177e4SLinus Torvalds ea_bdebug(bh, "b_count=%d", 9771da177e4SLinus Torvalds atomic_read(&(bh->b_count))); 97847387409STahsin Erdogan mb_cache_entry_touch(ea_block_cache, ce); 97947387409STahsin Erdogan mb_cache_entry_put(ea_block_cache, ce); 9801da177e4SLinus Torvalds return bh; 9811da177e4SLinus Torvalds } 9821da177e4SLinus Torvalds unlock_buffer(bh); 9831da177e4SLinus Torvalds brelse(bh); 9841da177e4SLinus Torvalds } 98547387409STahsin Erdogan ce = mb_cache_entry_find_next(ea_block_cache, ce); 9861da177e4SLinus Torvalds } 9871da177e4SLinus Torvalds return NULL; 9881da177e4SLinus Torvalds } 9891da177e4SLinus Torvalds 9901da177e4SLinus Torvalds #define NAME_HASH_SHIFT 5 9911da177e4SLinus Torvalds #define VALUE_HASH_SHIFT 16 9921da177e4SLinus Torvalds 9931da177e4SLinus Torvalds /* 9941da177e4SLinus Torvalds * ext2_xattr_hash_entry() 9951da177e4SLinus Torvalds * 9961da177e4SLinus Torvalds * Compute the hash of an extended attribute. 9971da177e4SLinus Torvalds */ 9981da177e4SLinus Torvalds static inline void ext2_xattr_hash_entry(struct ext2_xattr_header *header, 9991da177e4SLinus Torvalds struct ext2_xattr_entry *entry) 10001da177e4SLinus Torvalds { 10011da177e4SLinus Torvalds __u32 hash = 0; 10021da177e4SLinus Torvalds char *name = entry->e_name; 10031da177e4SLinus Torvalds int n; 10041da177e4SLinus Torvalds 10051da177e4SLinus Torvalds for (n=0; n < entry->e_name_len; n++) { 10061da177e4SLinus Torvalds hash = (hash << NAME_HASH_SHIFT) ^ 10071da177e4SLinus Torvalds (hash >> (8*sizeof(hash) - NAME_HASH_SHIFT)) ^ 10081da177e4SLinus Torvalds *name++; 10091da177e4SLinus Torvalds } 10101da177e4SLinus Torvalds 10111da177e4SLinus Torvalds if (entry->e_value_block == 0 && entry->e_value_size != 0) { 10121da177e4SLinus Torvalds __le32 *value = (__le32 *)((char *)header + 10131da177e4SLinus Torvalds le16_to_cpu(entry->e_value_offs)); 10141da177e4SLinus Torvalds for (n = (le32_to_cpu(entry->e_value_size) + 10151da177e4SLinus Torvalds EXT2_XATTR_ROUND) >> EXT2_XATTR_PAD_BITS; n; n--) { 10161da177e4SLinus Torvalds hash = (hash << VALUE_HASH_SHIFT) ^ 10171da177e4SLinus Torvalds (hash >> (8*sizeof(hash) - VALUE_HASH_SHIFT)) ^ 10181da177e4SLinus Torvalds le32_to_cpu(*value++); 10191da177e4SLinus Torvalds } 10201da177e4SLinus Torvalds } 10211da177e4SLinus Torvalds entry->e_hash = cpu_to_le32(hash); 10221da177e4SLinus Torvalds } 10231da177e4SLinus Torvalds 10241da177e4SLinus Torvalds #undef NAME_HASH_SHIFT 10251da177e4SLinus Torvalds #undef VALUE_HASH_SHIFT 10261da177e4SLinus Torvalds 10271da177e4SLinus Torvalds #define BLOCK_HASH_SHIFT 16 10281da177e4SLinus Torvalds 10291da177e4SLinus Torvalds /* 10301da177e4SLinus Torvalds * ext2_xattr_rehash() 10311da177e4SLinus Torvalds * 10321da177e4SLinus Torvalds * Re-compute the extended attribute hash value after an entry has changed. 10331da177e4SLinus Torvalds */ 10341da177e4SLinus Torvalds static void ext2_xattr_rehash(struct ext2_xattr_header *header, 10351da177e4SLinus Torvalds struct ext2_xattr_entry *entry) 10361da177e4SLinus Torvalds { 10371da177e4SLinus Torvalds struct ext2_xattr_entry *here; 10381da177e4SLinus Torvalds __u32 hash = 0; 10391da177e4SLinus Torvalds 10401da177e4SLinus Torvalds ext2_xattr_hash_entry(header, entry); 10411da177e4SLinus Torvalds here = ENTRY(header+1); 10421da177e4SLinus Torvalds while (!IS_LAST_ENTRY(here)) { 10431da177e4SLinus Torvalds if (!here->e_hash) { 10441da177e4SLinus Torvalds /* Block is not shared if an entry's hash value == 0 */ 10451da177e4SLinus Torvalds hash = 0; 10461da177e4SLinus Torvalds break; 10471da177e4SLinus Torvalds } 10481da177e4SLinus Torvalds hash = (hash << BLOCK_HASH_SHIFT) ^ 10491da177e4SLinus Torvalds (hash >> (8*sizeof(hash) - BLOCK_HASH_SHIFT)) ^ 10501da177e4SLinus Torvalds le32_to_cpu(here->e_hash); 10511da177e4SLinus Torvalds here = EXT2_XATTR_NEXT(here); 10521da177e4SLinus Torvalds } 10531da177e4SLinus Torvalds header->h_hash = cpu_to_le32(hash); 10541da177e4SLinus Torvalds } 10551da177e4SLinus Torvalds 10561da177e4SLinus Torvalds #undef BLOCK_HASH_SHIFT 10571da177e4SLinus Torvalds 1058be0726d3SJan Kara #define HASH_BUCKET_BITS 10 1059be0726d3SJan Kara 10607a2508e1SJan Kara struct mb_cache *ext2_xattr_create_cache(void) 10611da177e4SLinus Torvalds { 10627a2508e1SJan Kara return mb_cache_create(HASH_BUCKET_BITS); 10631da177e4SLinus Torvalds } 10641da177e4SLinus Torvalds 10657a2508e1SJan Kara void ext2_xattr_destroy_cache(struct mb_cache *cache) 10661da177e4SLinus Torvalds { 1067be0726d3SJan Kara if (cache) 10687a2508e1SJan Kara mb_cache_destroy(cache); 10691da177e4SLinus Torvalds } 1070