Release 4.10 fs/ext4/xattr.c
/*
* linux/fs/ext4/xattr.c
*
* Copyright (C) 2001-2003 Andreas Gruenbacher, <agruen@suse.de>
*
* Fix by Harrison Xing <harrison@mountainviewdata.com>.
* Ext4 code with a lot of help from Eric Jarman <ejarman@acm.org>.
* Extended attributes for symlinks and special files added per
* suggestion of Luka Renko <luka.renko@hermes.si>.
* xattr consolidation Copyright (c) 2004 James Morris <jmorris@redhat.com>,
* Red Hat Inc.
* ea-in-inode support by Alex Tomas <alex@clusterfs.com> aka bzzz
* and Andreas Gruenbacher <agruen@suse.de>.
*/
/*
* Extended attributes are stored directly in inodes (on file systems with
* inodes bigger than 128 bytes) and on additional disk blocks. The i_file_acl
* field contains the block number if an inode uses an additional block. All
* attributes must fit in the inode and one additional block. Blocks that
* contain the identical set of attributes may be shared among several inodes.
* Identical blocks are detected by keeping a cache of blocks that have
* recently been accessed.
*
* The attributes in inodes and on blocks have a different header; the entries
* are stored in the same format:
*
* +------------------+
* | header |
* | entry 1 | |
* | entry 2 | | growing downwards
* | entry 3 | v
* | four null bytes |
* | . . . |
* | value 1 | ^
* | value 3 | | growing upwards
* | value 2 | |
* +------------------+
*
* The header is followed by multiple entry descriptors. In disk blocks, the
* entry descriptors are kept sorted. In inodes, they are unsorted. The
* attribute values are aligned to the end of the block in no specific order.
*
* Locking strategy
* ----------------
* EXT4_I(inode)->i_file_acl is protected by EXT4_I(inode)->xattr_sem.
* EA blocks are only changed if they are exclusive to an inode, so
* holding xattr_sem also means that nothing but the EA block's reference
* count can change. Multiple writers to the same block are synchronized
* by the buffer lock.
*/
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/mbcache.h>
#include <linux/quotaops.h>
#include "ext4_jbd2.h"
#include "ext4.h"
#include "xattr.h"
#include "acl.h"
#ifdef EXT4_XATTR_DEBUG
# define ea_idebug(inode, fmt, ...) \
printk(KERN_DEBUG "inode %s:%lu: " fmt "\n", \
inode->i_sb->s_id, inode->i_ino, ##__VA_ARGS__)
# define ea_bdebug(bh, fmt, ...) \
printk(KERN_DEBUG "block %pg:%lu: " fmt "\n", \
bh->b_bdev, (unsigned long)bh->b_blocknr, ##__VA_ARGS__)
#else
# define ea_idebug(inode, fmt, ...) no_printk(fmt, ##__VA_ARGS__)
# define ea_bdebug(bh, fmt, ...) no_printk(fmt, ##__VA_ARGS__)
#endif
static void ext4_xattr_cache_insert(struct mb_cache *, struct buffer_head *);
static struct buffer_head *ext4_xattr_cache_find(struct inode *,
struct ext4_xattr_header *,
struct mb_cache_entry **);
static void ext4_xattr_rehash(struct ext4_xattr_header *,
struct ext4_xattr_entry *);
static int ext4_xattr_list(struct dentry *dentry, char *buffer,
size_t buffer_size);
static const struct xattr_handler *ext4_xattr_handler_map[] = {
[EXT4_XATTR_INDEX_USER] = &ext4_xattr_user_handler,
#ifdef CONFIG_EXT4_FS_POSIX_ACL
[EXT4_XATTR_INDEX_POSIX_ACL_ACCESS] = &posix_acl_access_xattr_handler,
[EXT4_XATTR_INDEX_POSIX_ACL_DEFAULT] = &posix_acl_default_xattr_handler,
#endif
[EXT4_XATTR_INDEX_TRUSTED] = &ext4_xattr_trusted_handler,
#ifdef CONFIG_EXT4_FS_SECURITY
[EXT4_XATTR_INDEX_SECURITY] = &ext4_xattr_security_handler,
#endif
};
const struct xattr_handler *ext4_xattr_handlers[] = {
&ext4_xattr_user_handler,
&ext4_xattr_trusted_handler,
#ifdef CONFIG_EXT4_FS_POSIX_ACL
&posix_acl_access_xattr_handler,
&posix_acl_default_xattr_handler,
#endif
#ifdef CONFIG_EXT4_FS_SECURITY
&ext4_xattr_security_handler,
#endif
NULL
};
#define EXT4_GET_MB_CACHE(inode) (((struct ext4_sb_info *) \
inode->i_sb->s_fs_info)->s_mb_cache)
static __le32 ext4_xattr_block_csum(struct inode *inode,
sector_t block_nr,
struct ext4_xattr_header *hdr)
{
struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
__u32 csum;
__le64 dsk_block_nr = cpu_to_le64(block_nr);
__u32 dummy_csum = 0;
int offset = offsetof(struct ext4_xattr_header, h_checksum);
csum = ext4_chksum(sbi, sbi->s_csum_seed, (__u8 *)&dsk_block_nr,
sizeof(dsk_block_nr));
csum = ext4_chksum(sbi, csum, (__u8 *)hdr, offset);
csum = ext4_chksum(sbi, csum, (__u8 *)&dummy_csum, sizeof(dummy_csum));
offset += sizeof(dummy_csum);
csum = ext4_chksum(sbi, csum, (__u8 *)hdr + offset,
EXT4_BLOCK_SIZE(inode->i_sb) - offset);
return cpu_to_le32(csum);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
darrick j. wong | darrick j. wong | 84 | 53.16% | 1 | 33.33% |
daeho jeong | daeho jeong | 64 | 40.51% | 1 | 33.33% |
theodore tso | theodore tso | 10 | 6.33% | 1 | 33.33% |
| Total | 158 | 100.00% | 3 | 100.00% |
static int ext4_xattr_block_csum_verify(struct inode *inode,
sector_t block_nr,
struct ext4_xattr_header *hdr)
{
if (ext4_has_metadata_csum(inode->i_sb) &&
(hdr->h_checksum != ext4_xattr_block_csum(inode, block_nr, hdr)))
return 0;
return 1;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
darrick j. wong | darrick j. wong | 48 | 97.96% | 1 | 50.00% |
dmitriy monakhov | dmitriy monakhov | 1 | 2.04% | 1 | 50.00% |
| Total | 49 | 100.00% | 2 | 100.00% |
static void ext4_xattr_block_csum_set(struct inode *inode,
sector_t block_nr,
struct ext4_xattr_header *hdr)
{
if (!ext4_has_metadata_csum(inode->i_sb))
return;
hdr->h_checksum = ext4_xattr_block_csum(inode, block_nr, hdr);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
darrick j. wong | darrick j. wong | 42 | 97.67% | 1 | 50.00% |
dmitriy monakhov | dmitriy monakhov | 1 | 2.33% | 1 | 50.00% |
| Total | 43 | 100.00% | 2 | 100.00% |
static inline int ext4_handle_dirty_xattr_block(handle_t *handle,
struct inode *inode,
struct buffer_head *bh)
{
ext4_xattr_block_csum_set(inode, bh->b_blocknr, BHDR(bh));
return ext4_handle_dirty_metadata(handle, inode, bh);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
darrick j. wong | darrick j. wong | 45 | 100.00% | 1 | 100.00% |
| Total | 45 | 100.00% | 1 | 100.00% |
static inline const struct xattr_handler *
ext4_xattr_handler(int name_index)
{
const struct xattr_handler *handler = NULL;
if (name_index > 0 && name_index < ARRAY_SIZE(ext4_xattr_handler_map))
handler = ext4_xattr_handler_map[name_index];
return handler;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
dave kleikamp | dave kleikamp | 39 | 88.64% | 1 | 33.33% |
mingming cao | mingming cao | 3 | 6.82% | 1 | 33.33% |
stephen hemminger | stephen hemminger | 2 | 4.55% | 1 | 33.33% |
| Total | 44 | 100.00% | 3 | 100.00% |
/*
* Inode operation listxattr()
*
* d_inode(dentry)->i_mutex: don't care
*/
ssize_t
ext4_listxattr(struct dentry *dentry, char *buffer, size_t size)
{
return ext4_xattr_list(dentry, buffer, size);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
dave kleikamp | dave kleikamp | 25 | 92.59% | 1 | 50.00% |
mingming cao | mingming cao | 2 | 7.41% | 1 | 50.00% |
| Total | 27 | 100.00% | 2 | 100.00% |
static int
ext4_xattr_check_names(struct ext4_xattr_entry *entry, void *end,
void *value_start)
{
struct ext4_xattr_entry *e = entry;
/* Find the end of the names list */
while (!IS_LAST_ENTRY(e)) {
struct ext4_xattr_entry *next = EXT4_XATTR_NEXT(e);
if ((void *)next >= end)
return -EFSCORRUPTED;
e = next;
}
/* Check the values */
while (!IS_LAST_ENTRY(entry)) {
if (entry->e_value_block != 0)
return -EFSCORRUPTED;
if (entry->e_value_size != 0) {
u16 offs = le16_to_cpu(entry->e_value_offs);
u32 size = le32_to_cpu(entry->e_value_size);
void *value;
/*
* The value cannot overlap the names, and the value
* with padding cannot extend beyond 'end'. Check both
* the padded and unpadded sizes, since the size may
* overflow to 0 when adding padding.
*/
if (offs > end - value_start)
return -EFSCORRUPTED;
value = value_start + offs;
if (value < (void *)e + sizeof(u32) ||
size > end - value ||
EXT4_XATTR_SIZE(size) > end - value)
return -EFSCORRUPTED;
}
entry = EXT4_XATTR_NEXT(entry);
}
return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
darrick j. wong | darrick j. wong | 65 | 35.14% | 2 | 33.33% |
eric biggers | eric biggers | 56 | 30.27% | 1 | 16.67% |
dave kleikamp | dave kleikamp | 48 | 25.95% | 1 | 16.67% |
jan kara | jan kara | 12 | 6.49% | 1 | 16.67% |
mingming cao | mingming cao | 4 | 2.16% | 1 | 16.67% |
| Total | 185 | 100.00% | 6 | 100.00% |
static inline int
ext4_xattr_check_block(struct inode *inode, struct buffer_head *bh)
{
int error;
if (buffer_verified(bh))
return 0;
if (BHDR(bh)->h_magic != cpu_to_le32(EXT4_XATTR_MAGIC) ||
BHDR(bh)->h_blocks != cpu_to_le32(1))
return -EFSCORRUPTED;
if (!ext4_xattr_block_csum_verify(inode, bh->b_blocknr, BHDR(bh)))
return -EFSBADCRC;
error = ext4_xattr_check_names(BFIRST(bh), bh->b_data + bh->b_size,
bh->b_data);
if (!error)
set_buffer_verified(bh);
return error;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
darrick j. wong | darrick j. wong | 58 | 50.00% | 3 | 50.00% |
dave kleikamp | dave kleikamp | 54 | 46.55% | 1 | 16.67% |
mingming cao | mingming cao | 3 | 2.59% | 1 | 16.67% |
zheng liu | zheng liu | 1 | 0.86% | 1 | 16.67% |
| Total | 116 | 100.00% | 6 | 100.00% |
static int
__xattr_check_inode(struct inode *inode, struct ext4_xattr_ibody_header *header,
void *end, const char *function, unsigned int line)
{
int error = -EFSCORRUPTED;
if (end - (void *)header < sizeof(*header) + sizeof(u32) ||
(header->h_magic != cpu_to_le32(EXT4_XATTR_MAGIC)))
goto errout;
error = ext4_xattr_check_names(IFIRST(header), end, IFIRST(header));
errout:
if (error)
__ext4_error_inode(inode, function, line, 0,
"corrupted in-inode xattr");
return error;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
theodore tso | theodore tso | 86 | 78.90% | 1 | 25.00% |
eric biggers | eric biggers | 22 | 20.18% | 2 | 50.00% |
dave kleikamp | dave kleikamp | 1 | 0.92% | 1 | 25.00% |
| Total | 109 | 100.00% | 4 | 100.00% |
#define xattr_check_inode(inode, header, end) \
__xattr_check_inode((inode), (header), (end), __func__, __LINE__)
static inline int
ext4_xattr_check_entry(struct ext4_xattr_entry *entry, size_t size)
{
size_t value_size = le32_to_cpu(entry->e_value_size);
if (entry->e_value_block != 0 || value_size > size ||
le16_to_cpu(entry->e_value_offs) + value_size > size)
return -EFSCORRUPTED;
return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
dave kleikamp | dave kleikamp | 51 | 92.73% | 1 | 25.00% |
mingming cao | mingming cao | 2 | 3.64% | 1 | 25.00% |
theodore tso | theodore tso | 1 | 1.82% | 1 | 25.00% |
darrick j. wong | darrick j. wong | 1 | 1.82% | 1 | 25.00% |
| Total | 55 | 100.00% | 4 | 100.00% |
static int
ext4_xattr_find_entry(struct ext4_xattr_entry **pentry, int name_index,
const char *name, size_t size, int sorted)
{
struct ext4_xattr_entry *entry;
size_t name_len;
int cmp = 1;
if (name == NULL)
return -EINVAL;
name_len = strlen(name);
entry = *pentry;
for (; !IS_LAST_ENTRY(entry); entry = EXT4_XATTR_NEXT(entry)) {
cmp = name_index - entry->e_name_index;
if (!cmp)
cmp = name_len - entry->e_name_len;
if (!cmp)
cmp = memcmp(name, entry->e_name, name_len);
if (cmp <= 0 && (sorted || cmp == 0))
break;
}
*pentry = entry;
if (!cmp && ext4_xattr_check_entry(entry, size))
return -EFSCORRUPTED;
return cmp ? -ENODATA : 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
dave kleikamp | dave kleikamp | 156 | 96.30% | 1 | 33.33% |
mingming cao | mingming cao | 5 | 3.09% | 1 | 33.33% |
darrick j. wong | darrick j. wong | 1 | 0.62% | 1 | 33.33% |
| Total | 162 | 100.00% | 3 | 100.00% |
static int
ext4_xattr_block_get(struct inode *inode, int name_index, const char *name,
void *buffer, size_t buffer_size)
{
struct buffer_head *bh = NULL;
struct ext4_xattr_entry *entry;
size_t size;
int error;
struct mb_cache *ext4_mb_cache = EXT4_GET_MB_CACHE(inode);
ea_idebug(inode, "name=%d.%s, buffer=%p, buffer_size=%ld",
name_index, name, buffer, (long)buffer_size);
error = -ENODATA;
if (!EXT4_I(inode)->i_file_acl)
goto cleanup;
ea_idebug(inode, "reading block %llu",
(unsigned long long)EXT4_I(inode)->i_file_acl);
bh = sb_bread(inode->i_sb, EXT4_I(inode)->i_file_acl);
if (!bh)
goto cleanup;
ea_bdebug(bh, "b_count=%d, refcount=%d",
atomic_read(&(bh->b_count)), le32_to_cpu(BHDR(bh)->h_refcount));
if (ext4_xattr_check_block(inode, bh)) {
bad_block:
EXT4_ERROR_INODE(inode, "bad block %llu",
EXT4_I(inode)->i_file_acl);
error = -EFSCORRUPTED;
goto cleanup;
}
ext4_xattr_cache_insert(ext4_mb_cache, bh);
entry = BFIRST(bh);
error = ext4_xattr_find_entry(&entry, name_index, name, bh->b_size, 1);
if (error == -EFSCORRUPTED)
goto bad_block;
if (error)
goto cleanup;
size = le32_to_cpu(entry->e_value_size);
if (buffer) {
error = -ERANGE;
if (size > buffer_size)
goto cleanup;
memcpy(buffer, bh->b_data + le16_to_cpu(entry->e_value_offs),
size);
}
error = size;
cleanup:
brelse(bh);
return error;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
dave kleikamp | dave kleikamp | 272 | 89.18% | 1 | 12.50% |
t makphaibulchoke | t makphaibulchoke | 11 | 3.61% | 1 | 12.50% |
mingming cao | mingming cao | 9 | 2.95% | 1 | 12.50% |
joe perches | joe perches | 6 | 1.97% | 1 | 12.50% |
darrick j. wong | darrick j. wong | 4 | 1.31% | 2 | 25.00% |
theodore tso | theodore tso | 2 | 0.66% | 1 | 12.50% |
jan kara | jan kara | 1 | 0.33% | 1 | 12.50% |
| Total | 305 | 100.00% | 8 | 100.00% |
int
ext4_xattr_ibody_get(struct inode *inode, int name_index, const char *name,
void *buffer, size_t buffer_size)
{
struct ext4_xattr_ibody_header *header;
struct ext4_xattr_entry *entry;
struct ext4_inode *raw_inode;
struct ext4_iloc iloc;
size_t size;
void *end;
int error;
if (!ext4_test_inode_state(inode, EXT4_STATE_XATTR))
return -ENODATA;
error = ext4_get_inode_loc(inode, &iloc);
if (error)
return error;
raw_inode = ext4_raw_inode(&iloc);
header = IHDR(inode, raw_inode);
entry = IFIRST(header);
end = (void *)raw_inode + EXT4_SB(inode->i_sb)->s_inode_size;
error = xattr_check_inode(inode, header, end);
if (error)
goto cleanup;
error = ext4_xattr_find_entry(&entry, name_index, name,
end - (void *)entry, 0);
if (error)
goto cleanup;
size = le32_to_cpu(entry->e_value_size);
if (buffer) {
error = -ERANGE;
if (size > buffer_size)
goto cleanup;
memcpy(buffer, (void *)IFIRST(header) +
le16_to_cpu(entry->e_value_offs), size);
}
error = size;
cleanup:
brelse(iloc.bh);
return error;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
dave kleikamp | dave kleikamp | 223 | 92.53% | 1 | 20.00% |
mingming cao | mingming cao | 10 | 4.15% | 1 | 20.00% |
theodore tso | theodore tso | 7 | 2.90% | 2 | 40.00% |
darrick j. wong | darrick j. wong | 1 | 0.41% | 1 | 20.00% |
| Total | 241 | 100.00% | 5 | 100.00% |
/*
* ext4_xattr_get()
*
* Copy an extended attribute into the buffer
* provided, or compute the buffer size required.
* Buffer is NULL to compute the size of the buffer required.
*
* Returns a negative error number on failure, or the number of bytes
* used / required on success.
*/
int
ext4_xattr_get(struct inode *inode, int name_index, const char *name,
void *buffer, size_t buffer_size)
{
int error;
if (strlen(name) > 255)
return -ERANGE;
down_read(&EXT4_I(inode)->xattr_sem);
error = ext4_xattr_ibody_get(inode, name_index, name, buffer,
buffer_size);
if (error == -ENODATA)
error = ext4_xattr_block_get(inode, name_index, name, buffer,
buffer_size);
up_read(&EXT4_I(inode)->xattr_sem);
return error;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
dave kleikamp | dave kleikamp | 85 | 82.52% | 1 | 33.33% |
zhang zhen | zhang zhen | 13 | 12.62% | 1 | 33.33% |
mingming cao | mingming cao | 5 | 4.85% | 1 | 33.33% |
| Total | 103 | 100.00% | 3 | 100.00% |
static int
ext4_xattr_list_entries(struct dentry *dentry, struct ext4_xattr_entry *entry,
char *buffer, size_t buffer_size)
{
size_t rest = buffer_size;
for (; !IS_LAST_ENTRY(entry); entry = EXT4_XATTR_NEXT(entry)) {
const struct xattr_handler *handler =
ext4_xattr_handler(entry->e_name_index);
if (handler && (!handler->list || handler->list(dentry))) {
const char *prefix = handler->prefix ?: handler->name;
size_t prefix_len = strlen(prefix);
size_t size = prefix_len + entry->e_name_len + 1;
if (buffer) {
if (size > rest)
return -ERANGE;
memcpy(buffer, prefix, prefix_len);
buffer += prefix_len;
memcpy(buffer, entry->e_name, entry->e_name_len);
buffer += entry->e_name_len;
*buffer++ = 0;
}
rest -= size;
}
}
return buffer_size - rest; /* total size */
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
dave kleikamp | dave kleikamp | 94 | 53.41% | 1 | 16.67% |
andreas gruenbacher | andreas gruenbacher | 75 | 42.61% | 2 | 33.33% |
mingming cao | mingming cao | 4 | 2.27% | 1 | 16.67% |
christoph hellwig | christoph hellwig | 2 | 1.14% | 1 | 16.67% |
stephen hemminger | stephen hemminger | 1 | 0.57% | 1 | 16.67% |
| Total | 176 | 100.00% | 6 | 100.00% |
static int
ext4_xattr_block_list(struct dentry *dentry, char *buffer, size_t buffer_size)
{
struct inode *inode = d_inode(dentry);
struct buffer_head *bh = NULL;
int error;
struct mb_cache *ext4_mb_cache = EXT4_GET_MB_CACHE(inode);
ea_idebug(inode, "buffer=%p, buffer_size=%ld",
buffer, (long)buffer_size);
error = 0;
if (!EXT4_I(inode)->i_file_acl)
goto cleanup;
ea_idebug(inode, "reading block %llu",
(unsigned long long)EXT4_I(inode)->i_file_acl);
bh = sb_bread(inode->i_sb, EXT4_I(inode)->i_file_acl);
error = -EIO;
if (!bh)
goto cleanup;
ea_bdebug(bh, "b_count=%d, refcount=%d",
atomic_read(&(bh->b_count)), le32_to_cpu(BHDR(bh)->h_refcount));
if (ext4_xattr_check_block(inode, bh)) {
EXT4_ERROR_INODE(inode, "bad block %llu",
EXT4_I(inode)->i_file_acl);
error = -EFSCORRUPTED;
goto cleanup;
}
ext4_xattr_cache_insert(ext4_mb_cache, bh);
error = ext4_xattr_list_entries(dentry, BFIRST(bh), buffer, buffer_size);
cleanup:
brelse(bh);
return error;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
dave kleikamp | dave kleikamp | 176 | 80.00% | 1 | 10.00% |
t makphaibulchoke | t makphaibulchoke | 11 | 5.00% | 1 | 10.00% |
christoph hellwig | christoph hellwig | 10 | 4.55% | 1 | 10.00% |
mingming cao | mingming cao | 8 | 3.64% | 1 | 10.00% |
joe perches | joe perches | 6 | 2.73% | 1 | 10.00% |
david howells | david howells | 3 | 1.36% | 1 | 10.00% |
darrick j. wong | darrick j. wong | 3 | 1.36% | 2 | 20.00% |
theodore tso | theodore tso | 2 | 0.91% | 1 | 10.00% |
jan kara | jan kara | 1 | 0.45% | 1 | 10.00% |
| Total | 220 | 100.00% | 10 | 100.00% |
static int
ext4_xattr_ibody_list(struct dentry *dentry, char *buffer, size_t buffer_size)
{
struct inode *inode = d_inode(dentry);
struct ext4_xattr_ibody_header *header;
struct ext4_inode *raw_inode;
struct ext4_iloc iloc;
void *end;
int error;
if (!ext4_test_inode_state(inode, EXT4_STATE_XATTR))
return 0;
error = ext4_get_inode_loc(inode, &iloc);
if (error)
return error;
raw_inode = ext4_raw_inode(&iloc);
header = IHDR(inode, raw_inode);
end = (void *)raw_inode + EXT4_SB(inode->i_sb)->s_inode_size;
error = xattr_check_inode(inode, header, end);
if (error)
goto cleanup;
error = ext4_xattr_list_entries(dentry, IFIRST(header),
buffer, buffer_size);
cleanup:
brelse(iloc.bh);
return error;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
dave kleikamp | dave kleikamp | 131 | 82.39% | 1 | 16.67% |
christoph hellwig | christoph hellwig | 10 | 6.29% | 1 | 16.67% |
mingming cao | mingming cao | 9 | 5.66% | 1 | 16.67% |
theodore tso | theodore tso | 6 | 3.77% | 2 | 33.33% |
david howells | david howells | 3 | 1.89% | 1 | 16.67% |
| Total | 159 | 100.00% | 6 | 100.00% |
/*
* ext4_xattr_list()
*
* Copy a list of attribute names into the buffer
* provided, or compute the buffer size required.
* Buffer is NULL to compute the size of the buffer required.
*
* Returns a negative error number on failure, or the number of bytes
* used / required on success.
*/
static int
ext4_xattr_list(struct dentry *dentry, char *buffer, size_t buffer_size)
{
int ret, ret2;
down_read(&EXT4_I(d_inode(dentry))->xattr_sem);
ret = ret2 = ext4_xattr_ibody_list(dentry, buffer, buffer_size);
if (ret < 0)
goto errout;
if (buffer) {
buffer += ret;
buffer_size -= ret;
}
ret = ext4_xattr_block_list(dentry, buffer, buffer_size);
if (ret < 0)
goto errout;
ret += ret2;
errout:
up_read(&EXT4_I(d_inode(dentry))->xattr_sem);
return ret;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
dave kleikamp | dave kleikamp | 76 | 65.52% | 1 | 16.67% |
theodore tso | theodore tso | 22 | 18.97% | 1 | 16.67% |
david howells | david howells | 6 | 5.17% | 1 | 16.67% |
christoph hellwig | christoph hellwig | 6 | 5.17% | 1 | 16.67% |
mingming cao | mingming cao | 6 | 5.17% | 2 | 33.33% |
| Total | 116 | 100.00% | 6 | 100.00% |
/*
* If the EXT4_FEATURE_COMPAT_EXT_ATTR feature of this file system is
* not set, set it.
*/
static void ext4_xattr_update_super_block(handle_t *handle,
struct super_block *sb)
{
if (ext4_has_feature_xattr(sb))
return;
BUFFER_TRACE(EXT4_SB(sb)->s_sbh, "get_write_access");
if (ext4_journal_get_write_access(handle, EXT4_SB(sb)->s_sbh) == 0) {
ext4_set_feature_xattr(sb);
ext4_handle_dirty_super(handle, sb);
}
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
dave kleikamp | dave kleikamp | 47 | 72.31% | 1 | 20.00% |
liang xie | liang xie | 12 | 18.46% | 1 | 20.00% |
mingming cao | mingming cao | 3 | 4.62% | 1 | 20.00% |
darrick j. wong | darrick j. wong | 2 | 3.08% | 1 | 20.00% |
theodore tso | theodore tso | 1 | 1.54% | 1 | 20.00% |
| Total | 65 | 100.00% | 5 | 100.00% |
/*
* Release the xattr block BH: If the reference count is > 1, decrement it;
* otherwise free the block.
*/
static void
ext4_xattr_release_block(handle_t *handle, struct inode *inode,
struct buffer_head *bh)
{
struct mb_cache *ext4_mb_cache = EXT4_GET_MB_CACHE(inode);
u32 hash, ref;
int error = 0;
BUFFER_TRACE(bh, "get_write_access");
error = ext4_journal_get_write_access(handle, bh);
if (error)
goto out;
lock_buffer(bh);
hash = le32_to_cpu(BHDR(bh)->h_hash);
ref = le32_to_cpu(BHDR(bh)->h_refcount);
if (ref == 1) {
ea_bdebug(bh, "refcount now=0; freeing");
/*
* This must happen under buffer lock for
* ext4_xattr_block_set() to reliably detect freed block
*/
mb_cache_entry_delete_block(ext4_mb_cache, hash, bh->b_blocknr);
get_bh(bh);
unlock_buffer(bh);
ext4_free_blocks(handle, inode, bh, 0, 1,
EXT4_FREE_BLOCKS_METADATA |
EXT4_FREE_BLOCKS_FORGET);
} else {
ref--;
BHDR(bh)->h_refcount = cpu_to_le32(ref);
if (ref == EXT4_XATTR_REFCOUNT_MAX - 1) {
struct mb_cache_entry *ce;
ce = mb_cache_entry_get(ext4_mb_cache, hash,
bh->b_blocknr);
if (ce) {
ce->e_reusable = 1;
mb_cache_entry_put(ext4_mb_cache, ce);
}
}
/*
* Beware of this ugliness: Releasing of xattr block references
* from different inodes can race and so we have to protect
* from a race where someone else frees the block (and releases
* its journal_head) before we are done dirtying the buffer. In
* nojournal mode this race is harmless and we actually cannot
* call ext4_handle_dirty_xattr_block() with locked buffer as
* that function can call sync_dirty_buffer() so for that case
* we handle the dirtying after unlocking the buffer.
*/
if (ext4_handle_valid(handle))
error