xattr.c revision 8c52ab42c11b5a7fb44bb84c954d09968e90e9e7
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * linux/fs/ext2/xattr.c 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2001-2003 Andreas Gruenbacher <agruen@suse.de> 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Fix by Harrison Xing <harrison@mountainviewdata.com>. 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Extended attributes for symlinks and special files added per 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * suggestion of Luka Renko <luka.renko@hermes.si>. 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * xattr consolidation Copyright (c) 2004 James Morris <jmorris@redhat.com>, 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Red Hat Inc. 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Extended attributes are stored on disk blocks allocated outside of 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * any inode. The i_file_acl field is then made to point to this allocated 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * block. If all extended attributes of an inode are identical, these 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * inodes may share the same extended attribute block. Such situations 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * are automatically detected by keeping a cache of recent attribute block 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * numbers and hashes over the block's contents in memory. 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Extended attribute block layout: 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * +------------------+ 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * | header | 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * | entry 1 | | 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * | entry 2 | | growing downwards 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * | entry 3 | v 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * | four null bytes | 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * | . . . | 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * | value 1 | ^ 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * | value 3 | | growing upwards 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * | value 2 | | 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * +------------------+ 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The block header is followed by multiple entry descriptors. These entry 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * descriptors are variable in size, and alligned to EXT2_XATTR_PAD 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * byte boundaries. The entry descriptors are sorted by attribute name, 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * so that two extended attribute blocks can be compared efficiently. 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Attribute values are aligned to the end of the block, stored in 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * no specific order. They are also padded to EXT2_XATTR_PAD byte 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * boundaries. No additional gaps are left between them. 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Locking strategy 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ---------------- 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * EXT2_I(inode)->i_file_acl is protected by EXT2_I(inode)->xattr_sem. 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * EA blocks are only changed if they are exclusive to an inode, so 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * holding xattr_sem also means that nothing but the EA block's reference 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * count will change. Multiple writers to an EA block are synchronized 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * by the bh lock. No more than a single bh lock is held at any time 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to avoid deadlocks. 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/buffer_head.h> 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h> 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mbcache.h> 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/quotaops.h> 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/rwsem.h> 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "ext2.h" 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "xattr.h" 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "acl.h" 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define HDR(bh) ((struct ext2_xattr_header *)((bh)->b_data)) 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ENTRY(ptr) ((struct ext2_xattr_entry *)(ptr)) 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define FIRST_ENTRY(bh) ENTRY(HDR(bh)+1) 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IS_LAST_ENTRY(entry) (*(__u32 *)(entry) == 0) 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef EXT2_XATTR_DEBUG 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds# define ea_idebug(inode, f...) do { \ 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_DEBUG "inode %s:%ld: ", \ 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds inode->i_sb->s_id, inode->i_ino); \ 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(f); \ 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("\n"); \ 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } while (0) 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds# define ea_bdebug(bh, f...) do { \ 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char b[BDEVNAME_SIZE]; \ 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_DEBUG "block %s:%lu: ", \ 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bdevname(bh->b_bdev, b), \ 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (unsigned long) bh->b_blocknr); \ 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(f); \ 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("\n"); \ 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } while (0) 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds# define ea_idebug(f...) 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds# define ea_bdebug(f...) 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ext2_xattr_set2(struct inode *, struct buffer_head *, 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ext2_xattr_header *); 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ext2_xattr_cache_insert(struct buffer_head *); 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct buffer_head *ext2_xattr_cache_find(struct inode *, 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ext2_xattr_header *); 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ext2_xattr_rehash(struct ext2_xattr_header *, 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ext2_xattr_entry *); 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct mb_cache *ext2_xattr_cache; 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct xattr_handler *ext2_xattr_handler_map[] = { 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds [EXT2_XATTR_INDEX_USER] = &ext2_xattr_user_handler, 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_EXT2_FS_POSIX_ACL 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds [EXT2_XATTR_INDEX_POSIX_ACL_ACCESS] = &ext2_xattr_acl_access_handler, 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds [EXT2_XATTR_INDEX_POSIX_ACL_DEFAULT] = &ext2_xattr_acl_default_handler, 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds [EXT2_XATTR_INDEX_TRUSTED] = &ext2_xattr_trusted_handler, 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_EXT2_FS_SECURITY 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds [EXT2_XATTR_INDEX_SECURITY] = &ext2_xattr_security_handler, 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct xattr_handler *ext2_xattr_handlers[] = { 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &ext2_xattr_user_handler, 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &ext2_xattr_trusted_handler, 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_EXT2_FS_POSIX_ACL 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &ext2_xattr_acl_access_handler, 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &ext2_xattr_acl_default_handler, 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_EXT2_FS_SECURITY 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &ext2_xattr_security_handler, 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds NULL 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline struct xattr_handler * 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsext2_xattr_handler(int name_index) 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct xattr_handler *handler = NULL; 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (name_index > 0 && name_index < ARRAY_SIZE(ext2_xattr_handler_map)) 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds handler = ext2_xattr_handler_map[name_index]; 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return handler; 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ext2_xattr_get() 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copy an extended attribute into the buffer 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * provided, or compute the buffer size required. 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Buffer is NULL to compute the size of the buffer required. 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Returns a negative error number on failure, or the number of bytes 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * used / required on success. 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsext2_xattr_get(struct inode *inode, int name_index, const char *name, 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void *buffer, size_t buffer_size) 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct buffer_head *bh = NULL; 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ext2_xattr_entry *entry; 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size_t name_len, size; 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *end; 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int error; 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ea_idebug(inode, "name=%d.%s, buffer=%p, buffer_size=%ld", 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds name_index, name, buffer, (long)buffer_size); 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (name == NULL) 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds down_read(&EXT2_I(inode)->xattr_sem); 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error = -ENODATA; 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!EXT2_I(inode)->i_file_acl) 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto cleanup; 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ea_idebug(inode, "reading block %d", EXT2_I(inode)->i_file_acl); 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh = sb_bread(inode->i_sb, EXT2_I(inode)->i_file_acl); 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error = -EIO; 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!bh) 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto cleanup; 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ea_bdebug(bh, "b_count=%d, refcount=%d", 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atomic_read(&(bh->b_count)), le32_to_cpu(HDR(bh)->h_refcount)); 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds end = bh->b_data + bh->b_size; 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (HDR(bh)->h_magic != cpu_to_le32(EXT2_XATTR_MAGIC) || 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HDR(bh)->h_blocks != cpu_to_le32(1)) { 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsbad_block: ext2_error(inode->i_sb, "ext2_xattr_get", 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "inode %ld: bad block %d", inode->i_ino, 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds EXT2_I(inode)->i_file_acl); 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error = -EIO; 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto cleanup; 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* find named attribute */ 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds name_len = strlen(name); 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error = -ERANGE; 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (name_len > 255) 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto cleanup; 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds entry = FIRST_ENTRY(bh); 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (!IS_LAST_ENTRY(entry)) { 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ext2_xattr_entry *next = 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds EXT2_XATTR_NEXT(entry); 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((char *)next >= end) 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto bad_block; 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (name_index == entry->e_name_index && 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds name_len == entry->e_name_len && 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcmp(name, entry->e_name, name_len) == 0) 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto found; 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds entry = next; 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Check the remaining name entries */ 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (!IS_LAST_ENTRY(entry)) { 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ext2_xattr_entry *next = 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds EXT2_XATTR_NEXT(entry); 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((char *)next >= end) 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto bad_block; 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds entry = next; 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ext2_xattr_cache_insert(bh)) 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ea_idebug(inode, "cache insert failed"); 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error = -ENODATA; 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto cleanup; 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfound: 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* check the buffer size */ 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (entry->e_value_block != 0) 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto bad_block; 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size = le32_to_cpu(entry->e_value_size); 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (size > inode->i_sb->s_blocksize || 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds le16_to_cpu(entry->e_value_offs) + size > inode->i_sb->s_blocksize) 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto bad_block; 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ext2_xattr_cache_insert(bh)) 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ea_idebug(inode, "cache insert failed"); 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (buffer) { 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error = -ERANGE; 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (size > buffer_size) 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto cleanup; 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* return value of attribute */ 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(buffer, bh->b_data + le16_to_cpu(entry->e_value_offs), 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size); 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error = size; 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldscleanup: 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds brelse(bh); 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up_read(&EXT2_I(inode)->xattr_sem); 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return error; 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ext2_xattr_list() 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copy a list of attribute names into the buffer 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * provided, or compute the buffer size required. 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Buffer is NULL to compute the size of the buffer required. 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Returns a negative error number on failure, or the number of bytes 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * used / required on success. 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsext2_xattr_list(struct inode *inode, char *buffer, size_t buffer_size) 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct buffer_head *bh = NULL; 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ext2_xattr_entry *entry; 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *end; 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size_t rest = buffer_size; 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int error; 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ea_idebug(inode, "buffer=%p, buffer_size=%ld", 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buffer, (long)buffer_size); 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds down_read(&EXT2_I(inode)->xattr_sem); 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error = 0; 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!EXT2_I(inode)->i_file_acl) 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto cleanup; 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ea_idebug(inode, "reading block %d", EXT2_I(inode)->i_file_acl); 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh = sb_bread(inode->i_sb, EXT2_I(inode)->i_file_acl); 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error = -EIO; 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!bh) 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto cleanup; 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ea_bdebug(bh, "b_count=%d, refcount=%d", 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atomic_read(&(bh->b_count)), le32_to_cpu(HDR(bh)->h_refcount)); 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds end = bh->b_data + bh->b_size; 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (HDR(bh)->h_magic != cpu_to_le32(EXT2_XATTR_MAGIC) || 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HDR(bh)->h_blocks != cpu_to_le32(1)) { 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsbad_block: ext2_error(inode->i_sb, "ext2_xattr_list", 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "inode %ld: bad block %d", inode->i_ino, 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds EXT2_I(inode)->i_file_acl); 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error = -EIO; 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto cleanup; 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* check the on-disk data structure */ 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds entry = FIRST_ENTRY(bh); 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (!IS_LAST_ENTRY(entry)) { 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ext2_xattr_entry *next = EXT2_XATTR_NEXT(entry); 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((char *)next >= end) 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto bad_block; 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds entry = next; 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ext2_xattr_cache_insert(bh)) 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ea_idebug(inode, "cache insert failed"); 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* list the attribute names */ 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (entry = FIRST_ENTRY(bh); !IS_LAST_ENTRY(entry); 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds entry = EXT2_XATTR_NEXT(entry)) { 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct xattr_handler *handler = 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ext2_xattr_handler(entry->e_name_index); 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (handler) { 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size_t size = handler->list(inode, buffer, rest, 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds entry->e_name, 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds entry->e_name_len); 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (buffer) { 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (size > rest) { 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error = -ERANGE; 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto cleanup; 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buffer += size; 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rest -= size; 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error = buffer_size - rest; /* total size */ 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldscleanup: 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds brelse(bh); 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up_read(&EXT2_I(inode)->xattr_sem); 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return error; 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Inode operation listxattr() 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * dentry->d_inode->i_sem: don't care 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsssize_t 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsext2_listxattr(struct dentry *dentry, char *buffer, size_t size) 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ext2_xattr_list(dentry->d_inode, buffer, size); 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If the EXT2_FEATURE_COMPAT_EXT_ATTR feature of this file system is 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * not set, set it. 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ext2_xattr_update_super_block(struct super_block *sb) 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (EXT2_HAS_COMPAT_FEATURE(sb, EXT2_FEATURE_COMPAT_EXT_ATTR)) 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lock_super(sb); 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds EXT2_SB(sb)->s_es->s_feature_compat |= 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cpu_to_le32(EXT2_FEATURE_COMPAT_EXT_ATTR); 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sb->s_dirt = 1; 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mark_buffer_dirty(EXT2_SB(sb)->s_sbh); 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unlock_super(sb); 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ext2_xattr_set() 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Create, replace or remove an extended attribute for this inode. Buffer 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * is NULL to remove an existing extended attribute, and non-NULL to 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * either replace an existing extended attribute, or create a new extended 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * attribute. The flags XATTR_REPLACE and XATTR_CREATE 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * specify that an extended attribute must exist and must not exist 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * previous to the call, respectively. 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Returns 0, or a negative error number on failure. 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsext2_xattr_set(struct inode *inode, int name_index, const char *name, 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const void *value, size_t value_len, int flags) 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct super_block *sb = inode->i_sb; 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct buffer_head *bh = NULL; 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ext2_xattr_header *header = NULL; 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ext2_xattr_entry *here, *last; 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size_t name_len, free, min_offs = sb->s_blocksize; 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int not_found = 1, error; 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *end; 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * header -- Points either into bh, or to a temporarily 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * allocated buffer. 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * here -- The named entry found, or the place for inserting, within 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the block pointed to by header. 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * last -- Points right after the last named entry within the block 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * pointed to by header. 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * min_offs -- The offset of the first value (values are aligned 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * towards the end of the block). 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * end -- Points right after the block pointed to by header. 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ea_idebug(inode, "name=%d.%s, value=%p, value_len=%ld", 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds name_index, name, value, (long)value_len); 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (IS_RDONLY(inode)) 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EROFS; 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EPERM; 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (value == NULL) 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds value_len = 0; 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (name == NULL) 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds name_len = strlen(name); 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (name_len > 255 || value_len > sb->s_blocksize) 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ERANGE; 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds down_write(&EXT2_I(inode)->xattr_sem); 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (EXT2_I(inode)->i_file_acl) { 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* The inode already has an extended attribute block. */ 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh = sb_bread(sb, EXT2_I(inode)->i_file_acl); 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error = -EIO; 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!bh) 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto cleanup; 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ea_bdebug(bh, "b_count=%d, refcount=%d", 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atomic_read(&(bh->b_count)), 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds le32_to_cpu(HDR(bh)->h_refcount)); 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds header = HDR(bh); 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds end = bh->b_data + bh->b_size; 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (header->h_magic != cpu_to_le32(EXT2_XATTR_MAGIC) || 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds header->h_blocks != cpu_to_le32(1)) { 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsbad_block: ext2_error(sb, "ext2_xattr_set", 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "inode %ld: bad block %d", inode->i_ino, 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds EXT2_I(inode)->i_file_acl); 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error = -EIO; 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto cleanup; 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Find the named attribute. */ 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds here = FIRST_ENTRY(bh); 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (!IS_LAST_ENTRY(here)) { 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ext2_xattr_entry *next = EXT2_XATTR_NEXT(here); 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((char *)next >= end) 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto bad_block; 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!here->e_value_block && here->e_value_size) { 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size_t offs = le16_to_cpu(here->e_value_offs); 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (offs < min_offs) 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds min_offs = offs; 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds not_found = name_index - here->e_name_index; 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!not_found) 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds not_found = name_len - here->e_name_len; 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!not_found) 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds not_found = memcmp(name, here->e_name,name_len); 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (not_found <= 0) 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds here = next; 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds last = here; 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* We still need to compute min_offs and last. */ 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (!IS_LAST_ENTRY(last)) { 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ext2_xattr_entry *next = EXT2_XATTR_NEXT(last); 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((char *)next >= end) 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto bad_block; 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!last->e_value_block && last->e_value_size) { 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size_t offs = le16_to_cpu(last->e_value_offs); 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (offs < min_offs) 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds min_offs = offs; 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds last = next; 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Check whether we have enough space left. */ 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free = min_offs - ((char*)last - (char*)header) - sizeof(__u32); 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* We will use a new extended attribute block. */ 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free = sb->s_blocksize - 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sizeof(struct ext2_xattr_header) - sizeof(__u32); 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds here = last = NULL; /* avoid gcc uninitialized warning. */ 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (not_found) { 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Request to remove a nonexistent attribute? */ 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error = -ENODATA; 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (flags & XATTR_REPLACE) 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto cleanup; 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error = 0; 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (value == NULL) 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto cleanup; 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Request to create an existing attribute? */ 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error = -EEXIST; 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (flags & XATTR_CREATE) 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto cleanup; 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!here->e_value_block && here->e_value_size) { 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size_t size = le32_to_cpu(here->e_value_size); 4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (le16_to_cpu(here->e_value_offs) + size > 4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sb->s_blocksize || size > sb->s_blocksize) 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto bad_block; 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free += EXT2_XATTR_SIZE(size); 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free += EXT2_XATTR_LEN(name_len); 4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error = -ENOSPC; 4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (free < EXT2_XATTR_LEN(name_len) + EXT2_XATTR_SIZE(value_len)) 4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto cleanup; 4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Here we know that we can set the new attribute. */ 4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (header) { 4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mb_cache_entry *ce; 4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* assert(header == HDR(bh)); */ 4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ce = mb_cache_entry_get(ext2_xattr_cache, bh->b_bdev, 5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh->b_blocknr); 5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lock_buffer(bh); 5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (header->h_refcount == cpu_to_le32(1)) { 5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ea_bdebug(bh, "modifying in-place"); 5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ce) 5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mb_cache_entry_free(ce); 5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* keep the buffer locked while modifying it. */ 5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int offset; 5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ce) 5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mb_cache_entry_release(ce); 5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unlock_buffer(bh); 5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ea_bdebug(bh, "cloning"); 5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds header = kmalloc(bh->b_size, GFP_KERNEL); 5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error = -ENOMEM; 5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (header == NULL) 5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto cleanup; 5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(header, HDR(bh), bh->b_size); 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds header->h_refcount = cpu_to_le32(1); 5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds offset = (char *)here - bh->b_data; 5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds here = ENTRY((char *)header + offset); 5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds offset = (char *)last - bh->b_data; 5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds last = ENTRY((char *)header + offset); 5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Allocate a buffer where we construct the new block. */ 5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds header = kmalloc(sb->s_blocksize, GFP_KERNEL); 5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error = -ENOMEM; 5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (header == NULL) 5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto cleanup; 5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(header, 0, sb->s_blocksize); 5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds end = (char *)header + sb->s_blocksize; 5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds header->h_magic = cpu_to_le32(EXT2_XATTR_MAGIC); 5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds header->h_blocks = header->h_refcount = cpu_to_le32(1); 5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds last = here = ENTRY(header+1); 5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Iff we are modifying the block in-place, bh is locked here. */ 5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (not_found) { 5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Insert the new name. */ 5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size_t size = EXT2_XATTR_LEN(name_len); 5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size_t rest = (char *)last - (char *)here; 5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memmove((char *)here + size, here, rest); 5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(here, 0, size); 5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds here->e_name_index = name_index; 5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds here->e_name_len = name_len; 5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(here->e_name, name, name_len); 5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!here->e_value_block && here->e_value_size) { 5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *first_val = (char *)header + min_offs; 5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size_t offs = le16_to_cpu(here->e_value_offs); 5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *val = (char *)header + offs; 5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size_t size = EXT2_XATTR_SIZE( 5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds le32_to_cpu(here->e_value_size)); 5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (size == EXT2_XATTR_SIZE(value_len)) { 5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* The old and the new value have the same 5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size. Just replace. */ 5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds here->e_value_size = cpu_to_le32(value_len); 5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(val + size - EXT2_XATTR_PAD, 0, 5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds EXT2_XATTR_PAD); /* Clear pad bytes. */ 5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(val, value, value_len); 5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto skip_replace; 5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Remove the old value. */ 5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memmove(first_val + size, first_val, val - first_val); 5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(first_val, 0, size); 5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds here->e_value_offs = 0; 5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds min_offs += size; 5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Adjust all value offsets. */ 5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds last = ENTRY(header+1); 5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (!IS_LAST_ENTRY(last)) { 5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size_t o = le16_to_cpu(last->e_value_offs); 5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!last->e_value_block && o < offs) 5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds last->e_value_offs = 5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cpu_to_le16(o + size); 5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds last = EXT2_XATTR_NEXT(last); 5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (value == NULL) { 5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Remove the old name. */ 5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size_t size = EXT2_XATTR_LEN(name_len); 5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds last = ENTRY((char *)last - size); 5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memmove(here, (char*)here + size, 5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (char*)last - (char*)here); 5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(last, 0, size); 5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (value != NULL) { 5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Insert the new value. */ 5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds here->e_value_size = cpu_to_le32(value_len); 5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (value_len) { 5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size_t size = EXT2_XATTR_SIZE(value_len); 5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *val = (char *)header + min_offs - size; 6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds here->e_value_offs = 6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cpu_to_le16((char *)val - (char *)header); 6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(val + size - EXT2_XATTR_PAD, 0, 6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds EXT2_XATTR_PAD); /* Clear the pad bytes. */ 6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(val, value, value_len); 6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsskip_replace: 6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (IS_LAST_ENTRY(ENTRY(header+1))) { 6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* This block is now empty. */ 6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bh && header == HDR(bh)) 6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unlock_buffer(bh); /* we were modifying in-place. */ 6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error = ext2_xattr_set2(inode, bh, NULL); 6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ext2_xattr_rehash(header, here); 6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bh && header == HDR(bh)) 6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unlock_buffer(bh); /* we were modifying in-place. */ 6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error = ext2_xattr_set2(inode, bh, header); 6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldscleanup: 6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds brelse(bh); 6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(bh && header == HDR(bh))) 6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(header); 6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up_write(&EXT2_I(inode)->xattr_sem); 6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return error; 6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Second half of ext2_xattr_set(): Update the file system. 6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsext2_xattr_set2(struct inode *inode, struct buffer_head *old_bh, 6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ext2_xattr_header *header) 6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct super_block *sb = inode->i_sb; 6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct buffer_head *new_bh = NULL; 6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int error; 6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (header) { 6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds new_bh = ext2_xattr_cache_find(inode, header); 6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (new_bh) { 6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* We found an identical block in the cache. */ 6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (new_bh == old_bh) { 6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ea_bdebug(new_bh, "keeping this block"); 6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* The old block is released after updating 6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds the inode. */ 6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ea_bdebug(new_bh, "reusing block"); 6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error = -EDQUOT; 6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (DQUOT_ALLOC_BLOCK(inode, 1)) { 6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unlock_buffer(new_bh); 6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto cleanup; 6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HDR(new_bh)->h_refcount = cpu_to_le32(1 + 6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds le32_to_cpu(HDR(new_bh)->h_refcount)); 6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ea_bdebug(new_bh, "refcount now=%d", 6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds le32_to_cpu(HDR(new_bh)->h_refcount)); 6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unlock_buffer(new_bh); 6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (old_bh && header == HDR(old_bh)) { 6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Keep this block. No need to lock the block as we 6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds don't need to change the reference count. */ 6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds new_bh = old_bh; 6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds get_bh(new_bh); 6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ext2_xattr_cache_insert(new_bh); 6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* We need to allocate a new block */ 6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int goal = le32_to_cpu(EXT2_SB(sb)->s_es-> 6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s_first_data_block) + 6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds EXT2_I(inode)->i_block_group * 6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds EXT2_BLOCKS_PER_GROUP(sb); 6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int block = ext2_new_block(inode, goal, 6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds NULL, NULL, &error); 6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (error) 6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto cleanup; 6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ea_idebug(inode, "creating block %d", block); 6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds new_bh = sb_getblk(sb, block); 6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!new_bh) { 6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ext2_free_blocks(inode, block, 1); 6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error = -EIO; 6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto cleanup; 6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lock_buffer(new_bh); 6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(new_bh->b_data, header, new_bh->b_size); 6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_buffer_uptodate(new_bh); 6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unlock_buffer(new_bh); 6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ext2_xattr_cache_insert(new_bh); 6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ext2_xattr_update_super_block(sb); 6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mark_buffer_dirty(new_bh); 6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (IS_SYNC(inode)) { 6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sync_dirty_buffer(new_bh); 6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error = -EIO; 6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (buffer_req(new_bh) && !buffer_uptodate(new_bh)) 7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto cleanup; 7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Update the inode. */ 7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds EXT2_I(inode)->i_file_acl = new_bh ? new_bh->b_blocknr : 0; 7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds inode->i_ctime = CURRENT_TIME_SEC; 7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (IS_SYNC(inode)) { 7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error = ext2_sync_inode (inode); 7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* In case sync failed due to ENOSPC the inode was actually 7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * written (only some dirty data were not) so we just proceed 7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * as if nothing happened and cleanup the unused block */ 7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (error && error != -ENOSPC) { 7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (new_bh && new_bh != old_bh) 7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DQUOT_FREE_BLOCK(inode, 1); 7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto cleanup; 7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mark_inode_dirty(inode); 7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error = 0; 7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (old_bh && old_bh != new_bh) { 7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mb_cache_entry *ce; 7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If there was an old block and we are no longer using it, 7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * release the old block. 7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ce = mb_cache_entry_get(ext2_xattr_cache, old_bh->b_bdev, 7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds old_bh->b_blocknr); 7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lock_buffer(old_bh); 7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (HDR(old_bh)->h_refcount == cpu_to_le32(1)) { 7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Free the old block. */ 7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ce) 7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mb_cache_entry_free(ce); 7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ea_bdebug(old_bh, "freeing"); 7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ext2_free_blocks(inode, old_bh->b_blocknr, 1); 7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* We let our caller release old_bh, so we 7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * need to duplicate the buffer before. */ 7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds get_bh(old_bh); 7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bforget(old_bh); 7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Decrement the refcount only. */ 7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HDR(old_bh)->h_refcount = cpu_to_le32( 7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds le32_to_cpu(HDR(old_bh)->h_refcount) - 1); 7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ce) 7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mb_cache_entry_release(ce); 7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DQUOT_FREE_BLOCK(inode, 1); 7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mark_buffer_dirty(old_bh); 7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ea_bdebug(old_bh, "refcount now=%d", 7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds le32_to_cpu(HDR(old_bh)->h_refcount)); 7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unlock_buffer(old_bh); 7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldscleanup: 7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds brelse(new_bh); 7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return error; 7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ext2_xattr_delete_inode() 7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Free extended attribute resources associated with this inode. This 7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * is called immediately before an inode is freed. 7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid 7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsext2_xattr_delete_inode(struct inode *inode) 7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct buffer_head *bh = NULL; 7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mb_cache_entry *ce; 7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds down_write(&EXT2_I(inode)->xattr_sem); 7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!EXT2_I(inode)->i_file_acl) 7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto cleanup; 7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh = sb_bread(inode->i_sb, EXT2_I(inode)->i_file_acl); 7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!bh) { 7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ext2_error(inode->i_sb, "ext2_xattr_delete_inode", 7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "inode %ld: block %d read error", inode->i_ino, 7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds EXT2_I(inode)->i_file_acl); 7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto cleanup; 7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ea_bdebug(bh, "b_count=%d", atomic_read(&(bh->b_count))); 7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (HDR(bh)->h_magic != cpu_to_le32(EXT2_XATTR_MAGIC) || 7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HDR(bh)->h_blocks != cpu_to_le32(1)) { 7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ext2_error(inode->i_sb, "ext2_xattr_delete_inode", 7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "inode %ld: bad block %d", inode->i_ino, 7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds EXT2_I(inode)->i_file_acl); 7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto cleanup; 7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ce = mb_cache_entry_get(ext2_xattr_cache, bh->b_bdev, bh->b_blocknr); 7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lock_buffer(bh); 7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (HDR(bh)->h_refcount == cpu_to_le32(1)) { 7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ce) 7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mb_cache_entry_free(ce); 7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ext2_free_blocks(inode, EXT2_I(inode)->i_file_acl, 1); 7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds get_bh(bh); 7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bforget(bh); 7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HDR(bh)->h_refcount = cpu_to_le32( 8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds le32_to_cpu(HDR(bh)->h_refcount) - 1); 8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ce) 8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mb_cache_entry_release(ce); 8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mark_buffer_dirty(bh); 8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (IS_SYNC(inode)) 8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sync_dirty_buffer(bh); 8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DQUOT_FREE_BLOCK(inode, 1); 8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ea_bdebug(bh, "refcount now=%d", le32_to_cpu(HDR(bh)->h_refcount) - 1); 8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unlock_buffer(bh); 8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds EXT2_I(inode)->i_file_acl = 0; 8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldscleanup: 8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds brelse(bh); 8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up_write(&EXT2_I(inode)->xattr_sem); 8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ext2_xattr_put_super() 8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This is called when a file system is unmounted. 8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid 8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsext2_xattr_put_super(struct super_block *sb) 8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8268c52ab42c11b5a7fb44bb84c954d09968e90e9e7Andreas Gruenbacher mb_cache_shrink(sb->s_bdev); 8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ext2_xattr_cache_insert() 8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Create a new entry in the extended attribute cache, and insert 8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it unless such an entry is already in the cache. 8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Returns 0, or a negative error number on failure. 8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsext2_xattr_cache_insert(struct buffer_head *bh) 8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __u32 hash = le32_to_cpu(HDR(bh)->h_hash); 8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mb_cache_entry *ce; 8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int error; 8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ce = mb_cache_entry_alloc(ext2_xattr_cache); 8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!ce) 8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error = mb_cache_entry_insert(ce, bh->b_bdev, bh->b_blocknr, &hash); 8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (error) { 8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mb_cache_entry_free(ce); 8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (error == -EBUSY) { 8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ea_bdebug(bh, "already in cache (%d cache entries)", 8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atomic_read(&ext2_xattr_cache->c_entry_count)); 8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error = 0; 8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ea_bdebug(bh, "inserting [%x] (%d cache entries)", (int)hash, 8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atomic_read(&ext2_xattr_cache->c_entry_count)); 8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mb_cache_entry_release(ce); 8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return error; 8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ext2_xattr_cmp() 8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Compare two extended attribute blocks for equality. 8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Returns 0 if the blocks are equal, 1 if they differ, and 8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * a negative error number on errors. 8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsext2_xattr_cmp(struct ext2_xattr_header *header1, 8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ext2_xattr_header *header2) 8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ext2_xattr_entry *entry1, *entry2; 8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds entry1 = ENTRY(header1+1); 8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds entry2 = ENTRY(header2+1); 8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (!IS_LAST_ENTRY(entry1)) { 8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (IS_LAST_ENTRY(entry2)) 8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; 8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (entry1->e_hash != entry2->e_hash || 8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds entry1->e_name_index != entry2->e_name_index || 8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds entry1->e_name_len != entry2->e_name_len || 8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds entry1->e_value_size != entry2->e_value_size || 8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcmp(entry1->e_name, entry2->e_name, entry1->e_name_len)) 8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; 8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (entry1->e_value_block != 0 || entry2->e_value_block != 0) 8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; 8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (memcmp((char *)header1 + le16_to_cpu(entry1->e_value_offs), 8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (char *)header2 + le16_to_cpu(entry2->e_value_offs), 8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds le32_to_cpu(entry1->e_value_size))) 8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; 8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds entry1 = EXT2_XATTR_NEXT(entry1); 8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds entry2 = EXT2_XATTR_NEXT(entry2); 8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!IS_LAST_ENTRY(entry2)) 9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; 9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ext2_xattr_cache_find() 9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Find an identical extended attribute block. 9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Returns a locked buffer head to the block found, or NULL if such 9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * a block was not found or an error occurred. 9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct buffer_head * 9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsext2_xattr_cache_find(struct inode *inode, struct ext2_xattr_header *header) 9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __u32 hash = le32_to_cpu(header->h_hash); 9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mb_cache_entry *ce; 9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!header->h_hash) 9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; /* never share */ 9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ea_idebug(inode, "looking for cached blocks [%x]", (int)hash); 9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsagain: 9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ce = mb_cache_entry_find_first(ext2_xattr_cache, 0, 9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds inode->i_sb->s_bdev, hash); 9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (ce) { 9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct buffer_head *bh; 9261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (IS_ERR(ce)) { 9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (PTR_ERR(ce) == -EAGAIN) 9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto again; 9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh = sb_bread(inode->i_sb, ce->e_block); 9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!bh) { 9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ext2_error(inode->i_sb, "ext2_xattr_cache_find", 9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "inode %ld: block %ld read error", 9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds inode->i_ino, (unsigned long) ce->e_block); 9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lock_buffer(bh); 9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (le32_to_cpu(HDR(bh)->h_refcount) > 9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds EXT2_XATTR_REFCOUNT_MAX) { 9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ea_idebug(inode, "block %ld refcount %d>%d", 9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (unsigned long) ce->e_block, 9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds le32_to_cpu(HDR(bh)->h_refcount), 9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds EXT2_XATTR_REFCOUNT_MAX); 9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (!ext2_xattr_cmp(header, HDR(bh))) { 9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ea_bdebug(bh, "b_count=%d", 9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atomic_read(&(bh->b_count))); 9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mb_cache_entry_release(ce); 9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return bh; 9511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unlock_buffer(bh); 9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds brelse(bh); 9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ce = mb_cache_entry_find_next(ce, 0, inode->i_sb->s_bdev, hash); 9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define NAME_HASH_SHIFT 5 9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VALUE_HASH_SHIFT 16 9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 9641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ext2_xattr_hash_entry() 9651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 9661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Compute the hash of an extended attribute. 9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 9681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void ext2_xattr_hash_entry(struct ext2_xattr_header *header, 9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ext2_xattr_entry *entry) 9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __u32 hash = 0; 9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *name = entry->e_name; 9731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int n; 9741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (n=0; n < entry->e_name_len; n++) { 9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hash = (hash << NAME_HASH_SHIFT) ^ 9771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (hash >> (8*sizeof(hash) - NAME_HASH_SHIFT)) ^ 9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *name++; 9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (entry->e_value_block == 0 && entry->e_value_size != 0) { 9821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __le32 *value = (__le32 *)((char *)header + 9831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds le16_to_cpu(entry->e_value_offs)); 9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (n = (le32_to_cpu(entry->e_value_size) + 9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds EXT2_XATTR_ROUND) >> EXT2_XATTR_PAD_BITS; n; n--) { 9861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hash = (hash << VALUE_HASH_SHIFT) ^ 9871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (hash >> (8*sizeof(hash) - VALUE_HASH_SHIFT)) ^ 9881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds le32_to_cpu(*value++); 9891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds entry->e_hash = cpu_to_le32(hash); 9921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef NAME_HASH_SHIFT 9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef VALUE_HASH_SHIFT 9961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BLOCK_HASH_SHIFT 16 9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 10001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ext2_xattr_rehash() 10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Re-compute the extended attribute hash value after an entry has changed. 10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ext2_xattr_rehash(struct ext2_xattr_header *header, 10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ext2_xattr_entry *entry) 10061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ext2_xattr_entry *here; 10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __u32 hash = 0; 10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ext2_xattr_hash_entry(header, entry); 10111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds here = ENTRY(header+1); 10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (!IS_LAST_ENTRY(here)) { 10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!here->e_hash) { 10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Block is not shared if an entry's hash value == 0 */ 10151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hash = 0; 10161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hash = (hash << BLOCK_HASH_SHIFT) ^ 10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (hash >> (8*sizeof(hash) - BLOCK_HASH_SHIFT)) ^ 10201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds le32_to_cpu(here->e_hash); 10211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds here = EXT2_XATTR_NEXT(here); 10221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds header->h_hash = cpu_to_le32(hash); 10241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef BLOCK_HASH_SHIFT 10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint __init 10291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsinit_ext2_xattr(void) 10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 10311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ext2_xattr_cache = mb_cache_create("ext2_xattr", NULL, 10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sizeof(struct mb_cache_entry) + 10331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sizeof(((struct mb_cache_entry *) 0)->e_indexes[0]), 1, 6); 10341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!ext2_xattr_cache) 10351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 10361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 10371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid 10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsexit_ext2_xattr(void) 10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mb_cache_destroy(ext2_xattr_cache); 10431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1044