Skip to content

Commit ae54870

Browse files
committed
ext3: Fix lock inversion in ext3_symlink()
ext3_symlink() cannot call __page_symlink() with transaction open. __page_symlink() calls ext3_write_begin() which gets page lock which ranks above transaction start (thus lock ordering is violated) and and also ext3_write_begin() waits for a transaction commit when we run out of space which never happens if we hold transaction open. Fix the problem by stopping a transaction before calling __page_symlink() (we have to be careful and put inode to orphan list so that it gets deleted in case of crash) and starting another one after __page_symlink() returns for addition of symlink into a directory. Signed-off-by: Jan Kara <[email protected]>
1 parent fafc992 commit ae54870

File tree

1 file changed

+56
-11
lines changed

1 file changed

+56
-11
lines changed

fs/ext3/namei.c

Lines changed: 56 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2189,17 +2189,34 @@ static int ext3_symlink (struct inode * dir,
21892189
handle_t *handle;
21902190
struct inode * inode;
21912191
int l, err, retries = 0;
2192+
int credits;
21922193

21932194
l = strlen(symname)+1;
21942195
if (l > dir->i_sb->s_blocksize)
21952196
return -ENAMETOOLONG;
21962197

21972198
dquot_initialize(dir);
21982199

2200+
if (l > EXT3_N_BLOCKS * 4) {
2201+
/*
2202+
* For non-fast symlinks, we just allocate inode and put it on
2203+
* orphan list in the first transaction => we need bitmap,
2204+
* group descriptor, sb, inode block, quota blocks.
2205+
*/
2206+
credits = 4 + EXT3_MAXQUOTAS_INIT_BLOCKS(dir->i_sb);
2207+
} else {
2208+
/*
2209+
* Fast symlink. We have to add entry to directory
2210+
* (EXT3_DATA_TRANS_BLOCKS + EXT3_INDEX_EXTRA_TRANS_BLOCKS),
2211+
* allocate new inode (bitmap, group descriptor, inode block,
2212+
* quota blocks, sb is already counted in previous macros).
2213+
*/
2214+
credits = EXT3_DATA_TRANS_BLOCKS(dir->i_sb) +
2215+
EXT3_INDEX_EXTRA_TRANS_BLOCKS + 3 +
2216+
EXT3_MAXQUOTAS_INIT_BLOCKS(dir->i_sb);
2217+
}
21992218
retry:
2200-
handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS(dir->i_sb) +
2201-
EXT3_INDEX_EXTRA_TRANS_BLOCKS + 5 +
2202-
EXT3_MAXQUOTAS_INIT_BLOCKS(dir->i_sb));
2219+
handle = ext3_journal_start(dir, credits);
22032220
if (IS_ERR(handle))
22042221
return PTR_ERR(handle);
22052222

@@ -2211,21 +2228,45 @@ static int ext3_symlink (struct inode * dir,
22112228
if (IS_ERR(inode))
22122229
goto out_stop;
22132230

2214-
if (l > sizeof (EXT3_I(inode)->i_data)) {
2231+
if (l > EXT3_N_BLOCKS * 4) {
22152232
inode->i_op = &ext3_symlink_inode_operations;
22162233
ext3_set_aops(inode);
22172234
/*
2218-
* page_symlink() calls into ext3_prepare/commit_write.
2219-
* We have a transaction open. All is sweetness. It also sets
2220-
* i_size in generic_commit_write().
2235+
* We cannot call page_symlink() with transaction started
2236+
* because it calls into ext3_write_begin() which acquires page
2237+
* lock which ranks below transaction start (and it can also
2238+
* wait for journal commit if we are running out of space). So
2239+
* we have to stop transaction now and restart it when symlink
2240+
* contents is written.
2241+
*
2242+
* To keep fs consistent in case of crash, we have to put inode
2243+
* to orphan list in the mean time.
22212244
*/
2245+
drop_nlink(inode);
2246+
err = ext3_orphan_add(handle, inode);
2247+
ext3_journal_stop(handle);
2248+
if (err)
2249+
goto err_drop_inode;
22222250
err = __page_symlink(inode, symname, l, 1);
2251+
if (err)
2252+
goto err_drop_inode;
2253+
/*
2254+
* Now inode is being linked into dir (EXT3_DATA_TRANS_BLOCKS
2255+
* + EXT3_INDEX_EXTRA_TRANS_BLOCKS), inode is also modified
2256+
*/
2257+
handle = ext3_journal_start(dir,
2258+
EXT3_DATA_TRANS_BLOCKS(dir->i_sb) +
2259+
EXT3_INDEX_EXTRA_TRANS_BLOCKS + 1);
2260+
if (IS_ERR(handle)) {
2261+
err = PTR_ERR(handle);
2262+
goto err_drop_inode;
2263+
}
2264+
inc_nlink(inode);
2265+
err = ext3_orphan_del(handle, inode);
22232266
if (err) {
2267+
ext3_journal_stop(handle);
22242268
drop_nlink(inode);
2225-
unlock_new_inode(inode);
2226-
ext3_mark_inode_dirty(handle, inode);
2227-
iput (inode);
2228-
goto out_stop;
2269+
goto err_drop_inode;
22292270
}
22302271
} else {
22312272
inode->i_op = &ext3_fast_symlink_inode_operations;
@@ -2239,6 +2280,10 @@ static int ext3_symlink (struct inode * dir,
22392280
if (err == -ENOSPC && ext3_should_retry_alloc(dir->i_sb, &retries))
22402281
goto retry;
22412282
return err;
2283+
err_drop_inode:
2284+
unlock_new_inode(inode);
2285+
iput (inode);
2286+
return err;
22422287
}
22432288

22442289
static int ext3_link (struct dentry * old_dentry,

0 commit comments

Comments
 (0)