Skip to content

Commit 0a46ef2

Browse files
jankaratytso
authored andcommitted
ext4: do not create EA inode under buffer lock
ext4_xattr_set_entry() creates new EA inodes while holding buffer lock on the external xattr block. This is problematic as it nests all the allocation locking (which acquires locks on other buffers) under the buffer lock. This can even deadlock when the filesystem is corrupted and e.g. quota file is setup to contain xattr block as data block. Move the allocation of EA inode out of ext4_xattr_set_entry() into the callers. Reported-by: [email protected] Signed-off-by: Jan Kara <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Theodore Ts'o <[email protected]>
1 parent 4f3e6db commit 0a46ef2

File tree

1 file changed

+53
-60
lines changed

1 file changed

+53
-60
lines changed

fs/ext4/xattr.c

Lines changed: 53 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1619,14 +1619,14 @@ static struct inode *ext4_xattr_inode_lookup_create(handle_t *handle,
16191619
static int ext4_xattr_set_entry(struct ext4_xattr_info *i,
16201620
struct ext4_xattr_search *s,
16211621
handle_t *handle, struct inode *inode,
1622+
struct inode *new_ea_inode,
16221623
bool is_block)
16231624
{
16241625
struct ext4_xattr_entry *last, *next;
16251626
struct ext4_xattr_entry *here = s->here;
16261627
size_t min_offs = s->end - s->base, name_len = strlen(i->name);
16271628
int in_inode = i->in_inode;
16281629
struct inode *old_ea_inode = NULL;
1629-
struct inode *new_ea_inode = NULL;
16301630
size_t old_size, new_size;
16311631
int ret;
16321632

@@ -1711,38 +1711,11 @@ static int ext4_xattr_set_entry(struct ext4_xattr_info *i,
17111711
old_ea_inode = NULL;
17121712
goto out;
17131713
}
1714-
}
1715-
if (i->value && in_inode) {
1716-
WARN_ON_ONCE(!i->value_len);
1717-
1718-
new_ea_inode = ext4_xattr_inode_lookup_create(handle, inode,
1719-
i->value, i->value_len);
1720-
if (IS_ERR(new_ea_inode)) {
1721-
ret = PTR_ERR(new_ea_inode);
1722-
new_ea_inode = NULL;
1723-
goto out;
1724-
}
1725-
}
17261714

1727-
if (old_ea_inode) {
17281715
/* We are ready to release ref count on the old_ea_inode. */
17291716
ret = ext4_xattr_inode_dec_ref(handle, old_ea_inode);
1730-
if (ret) {
1731-
/* Release newly required ref count on new_ea_inode. */
1732-
if (new_ea_inode) {
1733-
int err;
1734-
1735-
err = ext4_xattr_inode_dec_ref(handle,
1736-
new_ea_inode);
1737-
if (err)
1738-
ext4_warning_inode(new_ea_inode,
1739-
"dec ref new_ea_inode err=%d",
1740-
err);
1741-
ext4_xattr_inode_free_quota(inode, new_ea_inode,
1742-
i->value_len);
1743-
}
1717+
if (ret)
17441718
goto out;
1745-
}
17461719

17471720
ext4_xattr_inode_free_quota(inode, old_ea_inode,
17481721
le32_to_cpu(here->e_value_size));
@@ -1866,7 +1839,6 @@ static int ext4_xattr_set_entry(struct ext4_xattr_info *i,
18661839
ret = 0;
18671840
out:
18681841
iput(old_ea_inode);
1869-
iput(new_ea_inode);
18701842
return ret;
18711843
}
18721844

@@ -1929,9 +1901,21 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode,
19291901
size_t old_ea_inode_quota = 0;
19301902
unsigned int ea_ino;
19311903

1932-
19331904
#define header(x) ((struct ext4_xattr_header *)(x))
19341905

1906+
/* If we need EA inode, prepare it before locking the buffer */
1907+
if (i->value && i->in_inode) {
1908+
WARN_ON_ONCE(!i->value_len);
1909+
1910+
ea_inode = ext4_xattr_inode_lookup_create(handle, inode,
1911+
i->value, i->value_len);
1912+
if (IS_ERR(ea_inode)) {
1913+
error = PTR_ERR(ea_inode);
1914+
ea_inode = NULL;
1915+
goto cleanup;
1916+
}
1917+
}
1918+
19351919
if (s->base) {
19361920
int offset = (char *)s->here - bs->bh->b_data;
19371921

@@ -1940,6 +1924,7 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode,
19401924
EXT4_JTR_NONE);
19411925
if (error)
19421926
goto cleanup;
1927+
19431928
lock_buffer(bs->bh);
19441929

19451930
if (header(s->base)->h_refcount == cpu_to_le32(1)) {
@@ -1966,7 +1951,7 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode,
19661951
}
19671952
ea_bdebug(bs->bh, "modifying in-place");
19681953
error = ext4_xattr_set_entry(i, s, handle, inode,
1969-
true /* is_block */);
1954+
ea_inode, true /* is_block */);
19701955
ext4_xattr_block_csum_set(inode, bs->bh);
19711956
unlock_buffer(bs->bh);
19721957
if (error == -EFSCORRUPTED)
@@ -2034,29 +2019,13 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode,
20342019
s->end = s->base + sb->s_blocksize;
20352020
}
20362021

2037-
error = ext4_xattr_set_entry(i, s, handle, inode, true /* is_block */);
2022+
error = ext4_xattr_set_entry(i, s, handle, inode, ea_inode,
2023+
true /* is_block */);
20382024
if (error == -EFSCORRUPTED)
20392025
goto bad_block;
20402026
if (error)
20412027
goto cleanup;
20422028

2043-
if (i->value && s->here->e_value_inum) {
2044-
/*
2045-
* A ref count on ea_inode has been taken as part of the call to
2046-
* ext4_xattr_set_entry() above. We would like to drop this
2047-
* extra ref but we have to wait until the xattr block is
2048-
* initialized and has its own ref count on the ea_inode.
2049-
*/
2050-
ea_ino = le32_to_cpu(s->here->e_value_inum);
2051-
error = ext4_xattr_inode_iget(inode, ea_ino,
2052-
le32_to_cpu(s->here->e_hash),
2053-
&ea_inode);
2054-
if (error) {
2055-
ea_inode = NULL;
2056-
goto cleanup;
2057-
}
2058-
}
2059-
20602029
inserted:
20612030
if (!IS_LAST_ENTRY(s->first)) {
20622031
new_bh = ext4_xattr_block_cache_find(inode, header(s->base),
@@ -2209,17 +2178,16 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode,
22092178

22102179
cleanup:
22112180
if (ea_inode) {
2212-
int error2;
2213-
2214-
error2 = ext4_xattr_inode_dec_ref(handle, ea_inode);
2215-
if (error2)
2216-
ext4_warning_inode(ea_inode, "dec ref error=%d",
2217-
error2);
2181+
if (error) {
2182+
int error2;
22182183

2219-
/* If there was an error, revert the quota charge. */
2220-
if (error)
2184+
error2 = ext4_xattr_inode_dec_ref(handle, ea_inode);
2185+
if (error2)
2186+
ext4_warning_inode(ea_inode, "dec ref error=%d",
2187+
error2);
22212188
ext4_xattr_inode_free_quota(inode, ea_inode,
22222189
i_size_read(ea_inode));
2190+
}
22232191
iput(ea_inode);
22242192
}
22252193
if (ce)
@@ -2277,14 +2245,38 @@ int ext4_xattr_ibody_set(handle_t *handle, struct inode *inode,
22772245
{
22782246
struct ext4_xattr_ibody_header *header;
22792247
struct ext4_xattr_search *s = &is->s;
2248+
struct inode *ea_inode = NULL;
22802249
int error;
22812250

22822251
if (!EXT4_INODE_HAS_XATTR_SPACE(inode))
22832252
return -ENOSPC;
22842253

2285-
error = ext4_xattr_set_entry(i, s, handle, inode, false /* is_block */);
2286-
if (error)
2254+
/* If we need EA inode, prepare it before locking the buffer */
2255+
if (i->value && i->in_inode) {
2256+
WARN_ON_ONCE(!i->value_len);
2257+
2258+
ea_inode = ext4_xattr_inode_lookup_create(handle, inode,
2259+
i->value, i->value_len);
2260+
if (IS_ERR(ea_inode))
2261+
return PTR_ERR(ea_inode);
2262+
}
2263+
error = ext4_xattr_set_entry(i, s, handle, inode, ea_inode,
2264+
false /* is_block */);
2265+
if (error) {
2266+
if (ea_inode) {
2267+
int error2;
2268+
2269+
error2 = ext4_xattr_inode_dec_ref(handle, ea_inode);
2270+
if (error2)
2271+
ext4_warning_inode(ea_inode, "dec ref error=%d",
2272+
error2);
2273+
2274+
ext4_xattr_inode_free_quota(inode, ea_inode,
2275+
i_size_read(ea_inode));
2276+
iput(ea_inode);
2277+
}
22872278
return error;
2279+
}
22882280
header = IHDR(inode, ext4_raw_inode(&is->iloc));
22892281
if (!IS_LAST_ENTRY(s->first)) {
22902282
header->h_magic = cpu_to_le32(EXT4_XATTR_MAGIC);
@@ -2293,6 +2285,7 @@ int ext4_xattr_ibody_set(handle_t *handle, struct inode *inode,
22932285
header->h_magic = cpu_to_le32(0);
22942286
ext4_clear_inode_state(inode, EXT4_STATE_XATTR);
22952287
}
2288+
iput(ea_inode);
22962289
return 0;
22972290
}
22982291

0 commit comments

Comments
 (0)