Skip to content

Commit ca3cef4

Browse files
committed
Merge tag 'ext4_for_linus_stable' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4
Pull ext4 fixes from Ted Ts'o: "Fix a number of ext4 bugs in fast_commit, inline data, and delayed allocation. Also fix error handling code paths in ext4_dx_readdir() and ext4_fill_super(). Finally, avoid a grabbing a journal head in the delayed allocation write in the common cases where we are overwriting a pre-existing block or appending to an inode" * tag 'ext4_for_linus_stable' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4: ext4: recheck buffer uptodate bit under buffer lock ext4: fix potential infinite loop in ext4_dx_readdir() ext4: flush s_error_work before journal destroy in ext4_fill_super ext4: fix loff_t overflow in ext4_max_bitmap_size() ext4: fix reserved space counter leakage ext4: limit the number of blocks in one ADD_RANGE TLV ext4: enforce buffer head state assertion in ext4_da_map_blocks ext4: remove extent cache entries when truncating inline data ext4: drop unnecessary journal handle in delalloc write ext4: factor out write end code of inline file ext4: correct the error path of ext4_write_inline_data_end() ext4: check and update i_disksize properly ext4: add error checking to ext4_ext_replay_set_iblocks()
2 parents 7fab1c1 + f2c7797 commit ca3cef4

File tree

7 files changed

+182
-199
lines changed

7 files changed

+182
-199
lines changed

fs/ext4/dir.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -551,7 +551,7 @@ static int ext4_dx_readdir(struct file *file, struct dir_context *ctx)
551551
struct dir_private_info *info = file->private_data;
552552
struct inode *inode = file_inode(file);
553553
struct fname *fname;
554-
int ret;
554+
int ret = 0;
555555

556556
if (!info) {
557557
info = ext4_htree_create_dir_info(file, ctx->pos);
@@ -599,7 +599,7 @@ static int ext4_dx_readdir(struct file *file, struct dir_context *ctx)
599599
info->curr_minor_hash,
600600
&info->next_hash);
601601
if (ret < 0)
602-
return ret;
602+
goto finished;
603603
if (ret == 0) {
604604
ctx->pos = ext4_get_htree_eof(file);
605605
break;
@@ -630,7 +630,7 @@ static int ext4_dx_readdir(struct file *file, struct dir_context *ctx)
630630
}
631631
finished:
632632
info->last_pos = ctx->pos;
633-
return 0;
633+
return ret < 0 ? ret : 0;
634634
}
635635

636636
static int ext4_release_dir(struct inode *inode, struct file *filp)

fs/ext4/ext4.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3593,9 +3593,6 @@ extern int ext4_da_write_inline_data_begin(struct address_space *mapping,
35933593
unsigned flags,
35943594
struct page **pagep,
35953595
void **fsdata);
3596-
extern int ext4_da_write_inline_data_end(struct inode *inode, loff_t pos,
3597-
unsigned len, unsigned copied,
3598-
struct page *page);
35993596
extern int ext4_try_add_inline_entry(handle_t *handle,
36003597
struct ext4_filename *fname,
36013598
struct inode *dir, struct inode *inode);

fs/ext4/extents.c

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5916,7 +5916,7 @@ void ext4_ext_replay_shrink_inode(struct inode *inode, ext4_lblk_t end)
59165916
}
59175917

59185918
/* Check if *cur is a hole and if it is, skip it */
5919-
static void skip_hole(struct inode *inode, ext4_lblk_t *cur)
5919+
static int skip_hole(struct inode *inode, ext4_lblk_t *cur)
59205920
{
59215921
int ret;
59225922
struct ext4_map_blocks map;
@@ -5925,9 +5925,12 @@ static void skip_hole(struct inode *inode, ext4_lblk_t *cur)
59255925
map.m_len = ((inode->i_size) >> inode->i_sb->s_blocksize_bits) - *cur;
59265926

59275927
ret = ext4_map_blocks(NULL, inode, &map, 0);
5928+
if (ret < 0)
5929+
return ret;
59285930
if (ret != 0)
5929-
return;
5931+
return 0;
59305932
*cur = *cur + map.m_len;
5933+
return 0;
59315934
}
59325935

59335936
/* Count number of blocks used by this inode and update i_blocks */
@@ -5976,7 +5979,9 @@ int ext4_ext_replay_set_iblocks(struct inode *inode)
59765979
* iblocks by total number of differences found.
59775980
*/
59785981
cur = 0;
5979-
skip_hole(inode, &cur);
5982+
ret = skip_hole(inode, &cur);
5983+
if (ret < 0)
5984+
goto out;
59805985
path = ext4_find_extent(inode, cur, NULL, 0);
59815986
if (IS_ERR(path))
59825987
goto out;
@@ -5995,8 +6000,12 @@ int ext4_ext_replay_set_iblocks(struct inode *inode)
59956000
}
59966001
cur = max(cur + 1, le32_to_cpu(ex->ee_block) +
59976002
ext4_ext_get_actual_len(ex));
5998-
skip_hole(inode, &cur);
5999-
6003+
ret = skip_hole(inode, &cur);
6004+
if (ret < 0) {
6005+
ext4_ext_drop_refs(path);
6006+
kfree(path);
6007+
break;
6008+
}
60006009
path2 = ext4_find_extent(inode, cur, NULL, 0);
60016010
if (IS_ERR(path2)) {
60026011
ext4_ext_drop_refs(path);

fs/ext4/fast_commit.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -892,6 +892,12 @@ static int ext4_fc_write_inode_data(struct inode *inode, u32 *crc)
892892
sizeof(lrange), (u8 *)&lrange, crc))
893893
return -ENOSPC;
894894
} else {
895+
unsigned int max = (map.m_flags & EXT4_MAP_UNWRITTEN) ?
896+
EXT_UNWRITTEN_MAX_LEN : EXT_INIT_MAX_LEN;
897+
898+
/* Limit the number of blocks in one extent */
899+
map.m_len = min(max, map.m_len);
900+
895901
fc_ext.fc_ino = cpu_to_le32(inode->i_ino);
896902
ex = (struct ext4_extent *)&fc_ext.fc_ex;
897903
ex->ee_block = cpu_to_le32(map.m_lblk);

fs/ext4/inline.c

Lines changed: 85 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <linux/iomap.h>
88
#include <linux/fiemap.h>
99
#include <linux/iversion.h>
10+
#include <linux/backing-dev.h>
1011

1112
#include "ext4_jbd2.h"
1213
#include "ext4.h"
@@ -733,45 +734,83 @@ int ext4_try_to_write_inline_data(struct address_space *mapping,
733734
int ext4_write_inline_data_end(struct inode *inode, loff_t pos, unsigned len,
734735
unsigned copied, struct page *page)
735736
{
736-
int ret, no_expand;
737+
handle_t *handle = ext4_journal_current_handle();
738+
int no_expand;
737739
void *kaddr;
738740
struct ext4_iloc iloc;
741+
int ret = 0, ret2;
742+
743+
if (unlikely(copied < len) && !PageUptodate(page))
744+
copied = 0;
739745

740-
if (unlikely(copied < len)) {
741-
if (!PageUptodate(page)) {
742-
copied = 0;
746+
if (likely(copied)) {
747+
ret = ext4_get_inode_loc(inode, &iloc);
748+
if (ret) {
749+
unlock_page(page);
750+
put_page(page);
751+
ext4_std_error(inode->i_sb, ret);
743752
goto out;
744753
}
745-
}
754+
ext4_write_lock_xattr(inode, &no_expand);
755+
BUG_ON(!ext4_has_inline_data(inode));
746756

747-
ret = ext4_get_inode_loc(inode, &iloc);
748-
if (ret) {
749-
ext4_std_error(inode->i_sb, ret);
750-
copied = 0;
751-
goto out;
752-
}
757+
/*
758+
* ei->i_inline_off may have changed since
759+
* ext4_write_begin() called
760+
* ext4_try_to_write_inline_data()
761+
*/
762+
(void) ext4_find_inline_data_nolock(inode);
753763

754-
ext4_write_lock_xattr(inode, &no_expand);
755-
BUG_ON(!ext4_has_inline_data(inode));
764+
kaddr = kmap_atomic(page);
765+
ext4_write_inline_data(inode, &iloc, kaddr, pos, copied);
766+
kunmap_atomic(kaddr);
767+
SetPageUptodate(page);
768+
/* clear page dirty so that writepages wouldn't work for us. */
769+
ClearPageDirty(page);
756770

757-
/*
758-
* ei->i_inline_off may have changed since ext4_write_begin()
759-
* called ext4_try_to_write_inline_data()
760-
*/
761-
(void) ext4_find_inline_data_nolock(inode);
771+
ext4_write_unlock_xattr(inode, &no_expand);
772+
brelse(iloc.bh);
762773

763-
kaddr = kmap_atomic(page);
764-
ext4_write_inline_data(inode, &iloc, kaddr, pos, len);
765-
kunmap_atomic(kaddr);
766-
SetPageUptodate(page);
767-
/* clear page dirty so that writepages wouldn't work for us. */
768-
ClearPageDirty(page);
774+
/*
775+
* It's important to update i_size while still holding page
776+
* lock: page writeout could otherwise come in and zero
777+
* beyond i_size.
778+
*/
779+
ext4_update_inode_size(inode, pos + copied);
780+
}
781+
unlock_page(page);
782+
put_page(page);
769783

770-
ext4_write_unlock_xattr(inode, &no_expand);
771-
brelse(iloc.bh);
772-
mark_inode_dirty(inode);
784+
/*
785+
* Don't mark the inode dirty under page lock. First, it unnecessarily
786+
* makes the holding time of page lock longer. Second, it forces lock
787+
* ordering of page lock and transaction start for journaling
788+
* filesystems.
789+
*/
790+
if (likely(copied))
791+
mark_inode_dirty(inode);
773792
out:
774-
return copied;
793+
/*
794+
* If we didn't copy as much data as expected, we need to trim back
795+
* size of xattr containing inline data.
796+
*/
797+
if (pos + len > inode->i_size && ext4_can_truncate(inode))
798+
ext4_orphan_add(handle, inode);
799+
800+
ret2 = ext4_journal_stop(handle);
801+
if (!ret)
802+
ret = ret2;
803+
if (pos + len > inode->i_size) {
804+
ext4_truncate_failed_write(inode);
805+
/*
806+
* If truncate failed early the inode might still be
807+
* on the orphan list; we need to make sure the inode
808+
* is removed from the orphan list in that case.
809+
*/
810+
if (inode->i_nlink)
811+
ext4_orphan_del(NULL, inode);
812+
}
813+
return ret ? ret : copied;
775814
}
776815

777816
struct buffer_head *
@@ -953,43 +992,6 @@ int ext4_da_write_inline_data_begin(struct address_space *mapping,
953992
return ret;
954993
}
955994

956-
int ext4_da_write_inline_data_end(struct inode *inode, loff_t pos,
957-
unsigned len, unsigned copied,
958-
struct page *page)
959-
{
960-
int ret;
961-
962-
ret = ext4_write_inline_data_end(inode, pos, len, copied, page);
963-
if (ret < 0) {
964-
unlock_page(page);
965-
put_page(page);
966-
return ret;
967-
}
968-
copied = ret;
969-
970-
/*
971-
* No need to use i_size_read() here, the i_size
972-
* cannot change under us because we hold i_mutex.
973-
*
974-
* But it's important to update i_size while still holding page lock:
975-
* page writeout could otherwise come in and zero beyond i_size.
976-
*/
977-
if (pos+copied > inode->i_size)
978-
i_size_write(inode, pos+copied);
979-
unlock_page(page);
980-
put_page(page);
981-
982-
/*
983-
* Don't mark the inode dirty under page lock. First, it unnecessarily
984-
* makes the holding time of page lock longer. Second, it forces lock
985-
* ordering of page lock and transaction start for journaling
986-
* filesystems.
987-
*/
988-
mark_inode_dirty(inode);
989-
990-
return copied;
991-
}
992-
993995
#ifdef INLINE_DIR_DEBUG
994996
void ext4_show_inline_dir(struct inode *dir, struct buffer_head *bh,
995997
void *inline_start, int inline_size)
@@ -1917,6 +1919,24 @@ int ext4_inline_data_truncate(struct inode *inode, int *has_inline)
19171919
EXT4_I(inode)->i_disksize = i_size;
19181920

19191921
if (i_size < inline_size) {
1922+
/*
1923+
* if there's inline data to truncate and this file was
1924+
* converted to extents after that inline data was written,
1925+
* the extent status cache must be cleared to avoid leaving
1926+
* behind stale delayed allocated extent entries
1927+
*/
1928+
if (!ext4_test_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA)) {
1929+
retry:
1930+
err = ext4_es_remove_extent(inode, 0, EXT_MAX_BLOCKS);
1931+
if (err == -ENOMEM) {
1932+
cond_resched();
1933+
congestion_wait(BLK_RW_ASYNC, HZ/50);
1934+
goto retry;
1935+
}
1936+
if (err)
1937+
goto out_error;
1938+
}
1939+
19201940
/* Clear the content in the xattr space. */
19211941
if (inline_size > EXT4_MIN_INLINE_DATA_SIZE) {
19221942
if ((err = ext4_xattr_ibody_find(inode, &i, &is)) != 0)

0 commit comments

Comments
 (0)