Commit ca3cef46 authored by Linus Torvalds's avatar Linus Torvalds

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()
parents 7fab1c12 f2c77973
...@@ -551,7 +551,7 @@ static int ext4_dx_readdir(struct file *file, struct dir_context *ctx) ...@@ -551,7 +551,7 @@ static int ext4_dx_readdir(struct file *file, struct dir_context *ctx)
struct dir_private_info *info = file->private_data; struct dir_private_info *info = file->private_data;
struct inode *inode = file_inode(file); struct inode *inode = file_inode(file);
struct fname *fname; struct fname *fname;
int ret; int ret = 0;
if (!info) { if (!info) {
info = ext4_htree_create_dir_info(file, ctx->pos); 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) ...@@ -599,7 +599,7 @@ static int ext4_dx_readdir(struct file *file, struct dir_context *ctx)
info->curr_minor_hash, info->curr_minor_hash,
&info->next_hash); &info->next_hash);
if (ret < 0) if (ret < 0)
return ret; goto finished;
if (ret == 0) { if (ret == 0) {
ctx->pos = ext4_get_htree_eof(file); ctx->pos = ext4_get_htree_eof(file);
break; break;
...@@ -630,7 +630,7 @@ static int ext4_dx_readdir(struct file *file, struct dir_context *ctx) ...@@ -630,7 +630,7 @@ static int ext4_dx_readdir(struct file *file, struct dir_context *ctx)
} }
finished: finished:
info->last_pos = ctx->pos; info->last_pos = ctx->pos;
return 0; return ret < 0 ? ret : 0;
} }
static int ext4_release_dir(struct inode *inode, struct file *filp) static int ext4_release_dir(struct inode *inode, struct file *filp)
......
...@@ -3593,9 +3593,6 @@ extern int ext4_da_write_inline_data_begin(struct address_space *mapping, ...@@ -3593,9 +3593,6 @@ extern int ext4_da_write_inline_data_begin(struct address_space *mapping,
unsigned flags, unsigned flags,
struct page **pagep, struct page **pagep,
void **fsdata); void **fsdata);
extern int ext4_da_write_inline_data_end(struct inode *inode, loff_t pos,
unsigned len, unsigned copied,
struct page *page);
extern int ext4_try_add_inline_entry(handle_t *handle, extern int ext4_try_add_inline_entry(handle_t *handle,
struct ext4_filename *fname, struct ext4_filename *fname,
struct inode *dir, struct inode *inode); struct inode *dir, struct inode *inode);
......
...@@ -5916,7 +5916,7 @@ void ext4_ext_replay_shrink_inode(struct inode *inode, ext4_lblk_t end) ...@@ -5916,7 +5916,7 @@ void ext4_ext_replay_shrink_inode(struct inode *inode, ext4_lblk_t end)
} }
/* Check if *cur is a hole and if it is, skip it */ /* Check if *cur is a hole and if it is, skip it */
static void skip_hole(struct inode *inode, ext4_lblk_t *cur) static int skip_hole(struct inode *inode, ext4_lblk_t *cur)
{ {
int ret; int ret;
struct ext4_map_blocks map; struct ext4_map_blocks map;
...@@ -5925,9 +5925,12 @@ static void skip_hole(struct inode *inode, ext4_lblk_t *cur) ...@@ -5925,9 +5925,12 @@ static void skip_hole(struct inode *inode, ext4_lblk_t *cur)
map.m_len = ((inode->i_size) >> inode->i_sb->s_blocksize_bits) - *cur; map.m_len = ((inode->i_size) >> inode->i_sb->s_blocksize_bits) - *cur;
ret = ext4_map_blocks(NULL, inode, &map, 0); ret = ext4_map_blocks(NULL, inode, &map, 0);
if (ret < 0)
return ret;
if (ret != 0) if (ret != 0)
return; return 0;
*cur = *cur + map.m_len; *cur = *cur + map.m_len;
return 0;
} }
/* Count number of blocks used by this inode and update i_blocks */ /* 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) ...@@ -5976,7 +5979,9 @@ int ext4_ext_replay_set_iblocks(struct inode *inode)
* iblocks by total number of differences found. * iblocks by total number of differences found.
*/ */
cur = 0; cur = 0;
skip_hole(inode, &cur); ret = skip_hole(inode, &cur);
if (ret < 0)
goto out;
path = ext4_find_extent(inode, cur, NULL, 0); path = ext4_find_extent(inode, cur, NULL, 0);
if (IS_ERR(path)) if (IS_ERR(path))
goto out; goto out;
...@@ -5995,8 +6000,12 @@ int ext4_ext_replay_set_iblocks(struct inode *inode) ...@@ -5995,8 +6000,12 @@ int ext4_ext_replay_set_iblocks(struct inode *inode)
} }
cur = max(cur + 1, le32_to_cpu(ex->ee_block) + cur = max(cur + 1, le32_to_cpu(ex->ee_block) +
ext4_ext_get_actual_len(ex)); ext4_ext_get_actual_len(ex));
skip_hole(inode, &cur); ret = skip_hole(inode, &cur);
if (ret < 0) {
ext4_ext_drop_refs(path);
kfree(path);
break;
}
path2 = ext4_find_extent(inode, cur, NULL, 0); path2 = ext4_find_extent(inode, cur, NULL, 0);
if (IS_ERR(path2)) { if (IS_ERR(path2)) {
ext4_ext_drop_refs(path); ext4_ext_drop_refs(path);
......
...@@ -892,6 +892,12 @@ static int ext4_fc_write_inode_data(struct inode *inode, u32 *crc) ...@@ -892,6 +892,12 @@ static int ext4_fc_write_inode_data(struct inode *inode, u32 *crc)
sizeof(lrange), (u8 *)&lrange, crc)) sizeof(lrange), (u8 *)&lrange, crc))
return -ENOSPC; return -ENOSPC;
} else { } else {
unsigned int max = (map.m_flags & EXT4_MAP_UNWRITTEN) ?
EXT_UNWRITTEN_MAX_LEN : EXT_INIT_MAX_LEN;
/* Limit the number of blocks in one extent */
map.m_len = min(max, map.m_len);
fc_ext.fc_ino = cpu_to_le32(inode->i_ino); fc_ext.fc_ino = cpu_to_le32(inode->i_ino);
ex = (struct ext4_extent *)&fc_ext.fc_ex; ex = (struct ext4_extent *)&fc_ext.fc_ex;
ex->ee_block = cpu_to_le32(map.m_lblk); ex->ee_block = cpu_to_le32(map.m_lblk);
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include <linux/iomap.h> #include <linux/iomap.h>
#include <linux/fiemap.h> #include <linux/fiemap.h>
#include <linux/iversion.h> #include <linux/iversion.h>
#include <linux/backing-dev.h>
#include "ext4_jbd2.h" #include "ext4_jbd2.h"
#include "ext4.h" #include "ext4.h"
...@@ -733,45 +734,83 @@ int ext4_try_to_write_inline_data(struct address_space *mapping, ...@@ -733,45 +734,83 @@ int ext4_try_to_write_inline_data(struct address_space *mapping,
int ext4_write_inline_data_end(struct inode *inode, loff_t pos, unsigned len, int ext4_write_inline_data_end(struct inode *inode, loff_t pos, unsigned len,
unsigned copied, struct page *page) unsigned copied, struct page *page)
{ {
int ret, no_expand; handle_t *handle = ext4_journal_current_handle();
int no_expand;
void *kaddr; void *kaddr;
struct ext4_iloc iloc; struct ext4_iloc iloc;
int ret = 0, ret2;
if (unlikely(copied < len) && !PageUptodate(page))
copied = 0;
if (unlikely(copied < len)) { if (likely(copied)) {
if (!PageUptodate(page)) { ret = ext4_get_inode_loc(inode, &iloc);
copied = 0; if (ret) {
unlock_page(page);
put_page(page);
ext4_std_error(inode->i_sb, ret);
goto out; goto out;
} }
} ext4_write_lock_xattr(inode, &no_expand);
BUG_ON(!ext4_has_inline_data(inode));
ret = ext4_get_inode_loc(inode, &iloc); /*
if (ret) { * ei->i_inline_off may have changed since
ext4_std_error(inode->i_sb, ret); * ext4_write_begin() called
copied = 0; * ext4_try_to_write_inline_data()
goto out; */
} (void) ext4_find_inline_data_nolock(inode);
ext4_write_lock_xattr(inode, &no_expand); kaddr = kmap_atomic(page);
BUG_ON(!ext4_has_inline_data(inode)); ext4_write_inline_data(inode, &iloc, kaddr, pos, copied);
kunmap_atomic(kaddr);
SetPageUptodate(page);
/* clear page dirty so that writepages wouldn't work for us. */
ClearPageDirty(page);
/* ext4_write_unlock_xattr(inode, &no_expand);
* ei->i_inline_off may have changed since ext4_write_begin() brelse(iloc.bh);
* called ext4_try_to_write_inline_data()
*/
(void) ext4_find_inline_data_nolock(inode);
kaddr = kmap_atomic(page); /*
ext4_write_inline_data(inode, &iloc, kaddr, pos, len); * It's important to update i_size while still holding page
kunmap_atomic(kaddr); * lock: page writeout could otherwise come in and zero
SetPageUptodate(page); * beyond i_size.
/* clear page dirty so that writepages wouldn't work for us. */ */
ClearPageDirty(page); ext4_update_inode_size(inode, pos + copied);
}
unlock_page(page);
put_page(page);
ext4_write_unlock_xattr(inode, &no_expand); /*
brelse(iloc.bh); * Don't mark the inode dirty under page lock. First, it unnecessarily
mark_inode_dirty(inode); * makes the holding time of page lock longer. Second, it forces lock
* ordering of page lock and transaction start for journaling
* filesystems.
*/
if (likely(copied))
mark_inode_dirty(inode);
out: out:
return copied; /*
* If we didn't copy as much data as expected, we need to trim back
* size of xattr containing inline data.
*/
if (pos + len > inode->i_size && ext4_can_truncate(inode))
ext4_orphan_add(handle, inode);
ret2 = ext4_journal_stop(handle);
if (!ret)
ret = ret2;
if (pos + len > inode->i_size) {
ext4_truncate_failed_write(inode);
/*
* If truncate failed early the inode might still be
* on the orphan list; we need to make sure the inode
* is removed from the orphan list in that case.
*/
if (inode->i_nlink)
ext4_orphan_del(NULL, inode);
}
return ret ? ret : copied;
} }
struct buffer_head * struct buffer_head *
...@@ -953,43 +992,6 @@ int ext4_da_write_inline_data_begin(struct address_space *mapping, ...@@ -953,43 +992,6 @@ int ext4_da_write_inline_data_begin(struct address_space *mapping,
return ret; return ret;
} }
int ext4_da_write_inline_data_end(struct inode *inode, loff_t pos,
unsigned len, unsigned copied,
struct page *page)
{
int ret;
ret = ext4_write_inline_data_end(inode, pos, len, copied, page);
if (ret < 0) {
unlock_page(page);
put_page(page);
return ret;
}
copied = ret;
/*
* No need to use i_size_read() here, the i_size
* cannot change under us because we hold i_mutex.
*
* But it's important to update i_size while still holding page lock:
* page writeout could otherwise come in and zero beyond i_size.
*/
if (pos+copied > inode->i_size)
i_size_write(inode, pos+copied);
unlock_page(page);
put_page(page);
/*
* Don't mark the inode dirty under page lock. First, it unnecessarily
* makes the holding time of page lock longer. Second, it forces lock
* ordering of page lock and transaction start for journaling
* filesystems.
*/
mark_inode_dirty(inode);
return copied;
}
#ifdef INLINE_DIR_DEBUG #ifdef INLINE_DIR_DEBUG
void ext4_show_inline_dir(struct inode *dir, struct buffer_head *bh, void ext4_show_inline_dir(struct inode *dir, struct buffer_head *bh,
void *inline_start, int inline_size) void *inline_start, int inline_size)
...@@ -1917,6 +1919,24 @@ int ext4_inline_data_truncate(struct inode *inode, int *has_inline) ...@@ -1917,6 +1919,24 @@ int ext4_inline_data_truncate(struct inode *inode, int *has_inline)
EXT4_I(inode)->i_disksize = i_size; EXT4_I(inode)->i_disksize = i_size;
if (i_size < inline_size) { if (i_size < inline_size) {
/*
* if there's inline data to truncate and this file was
* converted to extents after that inline data was written,
* the extent status cache must be cleared to avoid leaving
* behind stale delayed allocated extent entries
*/
if (!ext4_test_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA)) {
retry:
err = ext4_es_remove_extent(inode, 0, EXT_MAX_BLOCKS);
if (err == -ENOMEM) {
cond_resched();
congestion_wait(BLK_RW_ASYNC, HZ/50);
goto retry;
}
if (err)
goto out_error;
}
/* Clear the content in the xattr space. */ /* Clear the content in the xattr space. */
if (inline_size > EXT4_MIN_INLINE_DATA_SIZE) { if (inline_size > EXT4_MIN_INLINE_DATA_SIZE) {
if ((err = ext4_xattr_ibody_find(inode, &i, &is)) != 0) if ((err = ext4_xattr_ibody_find(inode, &i, &is)) != 0)
......
...@@ -1284,22 +1284,14 @@ static int ext4_write_end(struct file *file, ...@@ -1284,22 +1284,14 @@ static int ext4_write_end(struct file *file,
loff_t old_size = inode->i_size; loff_t old_size = inode->i_size;
int ret = 0, ret2; int ret = 0, ret2;
int i_size_changed = 0; int i_size_changed = 0;
int inline_data = ext4_has_inline_data(inode);
bool verity = ext4_verity_in_progress(inode); bool verity = ext4_verity_in_progress(inode);
trace_ext4_write_end(inode, pos, len, copied); trace_ext4_write_end(inode, pos, len, copied);
if (inline_data) {
ret = ext4_write_inline_data_end(inode, pos, len, if (ext4_has_inline_data(inode))
copied, page); return ext4_write_inline_data_end(inode, pos, len, copied, page);
if (ret < 0) {
unlock_page(page); copied = block_write_end(file, mapping, pos, len, copied, page, fsdata);
put_page(page);
goto errout;
}
copied = ret;
} else
copied = block_write_end(file, mapping, pos,
len, copied, page, fsdata);
/* /*
* it's important to update i_size while still holding page lock: * it's important to update i_size while still holding page lock:
* page writeout could otherwise come in and zero beyond i_size. * page writeout could otherwise come in and zero beyond i_size.
...@@ -1320,7 +1312,7 @@ static int ext4_write_end(struct file *file, ...@@ -1320,7 +1312,7 @@ static int ext4_write_end(struct file *file,
* ordering of page lock and transaction start for journaling * ordering of page lock and transaction start for journaling
* filesystems. * filesystems.
*/ */
if (i_size_changed || inline_data) if (i_size_changed)
ret = ext4_mark_inode_dirty(handle, inode); ret = ext4_mark_inode_dirty(handle, inode);
if (pos + len > inode->i_size && !verity && ext4_can_truncate(inode)) if (pos + len > inode->i_size && !verity && ext4_can_truncate(inode))
...@@ -1329,7 +1321,7 @@ static int ext4_write_end(struct file *file, ...@@ -1329,7 +1321,7 @@ static int ext4_write_end(struct file *file,
* inode->i_size. So truncate them * inode->i_size. So truncate them
*/ */
ext4_orphan_add(handle, inode); ext4_orphan_add(handle, inode);
errout:
ret2 = ext4_journal_stop(handle); ret2 = ext4_journal_stop(handle);
if (!ret) if (!ret)
ret = ret2; ret = ret2;
...@@ -1395,7 +1387,6 @@ static int ext4_journalled_write_end(struct file *file, ...@@ -1395,7 +1387,6 @@ static int ext4_journalled_write_end(struct file *file,
int partial = 0; int partial = 0;
unsigned from, to; unsigned from, to;
int size_changed = 0; int size_changed = 0;
int inline_data = ext4_has_inline_data(inode);
bool verity = ext4_verity_in_progress(inode); bool verity = ext4_verity_in_progress(inode);
trace_ext4_journalled_write_end(inode, pos, len, copied); trace_ext4_journalled_write_end(inode, pos, len, copied);
...@@ -1404,16 +1395,10 @@ static int ext4_journalled_write_end(struct file *file, ...@@ -1404,16 +1395,10 @@ static int ext4_journalled_write_end(struct file *file,
BUG_ON(!ext4_handle_valid(handle)); BUG_ON(!ext4_handle_valid(handle));
if (inline_data) { if (ext4_has_inline_data(inode))
ret = ext4_write_inline_data_end(inode, pos, len, return ext4_write_inline_data_end(inode, pos, len, copied, page);
copied, page);
if (ret < 0) { if (unlikely(copied < len) && !PageUptodate(page)) {
unlock_page(page);
put_page(page);
goto errout;
}
copied = ret;
} else if (unlikely(copied < len) && !PageUptodate(page)) {
copied = 0; copied = 0;
ext4_journalled_zero_new_buffers(handle, inode, page, from, to); ext4_journalled_zero_new_buffers(handle, inode, page, from, to);
} else { } else {
...@@ -1436,7 +1421,7 @@ static int ext4_journalled_write_end(struct file *file, ...@@ -1436,7 +1421,7 @@ static int ext4_journalled_write_end(struct file *file,
if (old_size < pos && !verity) if (old_size < pos && !verity)
pagecache_isize_extended(inode, old_size, pos); pagecache_isize_extended(inode, old_size, pos);
if (size_changed || inline_data) { if (size_changed) {
ret2 = ext4_mark_inode_dirty(handle, inode); ret2 = ext4_mark_inode_dirty(handle, inode);
if (!ret) if (!ret)
ret = ret2; ret = ret2;
...@@ -1449,7 +1434,6 @@ static int ext4_journalled_write_end(struct file *file, ...@@ -1449,7 +1434,6 @@ static int ext4_journalled_write_end(struct file *file,
*/ */
ext4_orphan_add(handle, inode); ext4_orphan_add(handle, inode);
errout:
ret2 = ext4_journal_stop(handle); ret2 = ext4_journal_stop(handle);
if (!ret) if (!ret)
ret = ret2; ret = ret2;
...@@ -1644,6 +1628,7 @@ static int ext4_insert_delayed_block(struct inode *inode, ext4_lblk_t lblk) ...@@ -1644,6 +1628,7 @@ static int ext4_insert_delayed_block(struct inode *inode, ext4_lblk_t lblk)
struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
int ret; int ret;
bool allocated = false; bool allocated = false;
bool reserved = false;
/* /*
* If the cluster containing lblk is shared with a delayed, * If the cluster containing lblk is shared with a delayed,
...@@ -1660,6 +1645,7 @@ static int ext4_insert_delayed_block(struct inode *inode, ext4_lblk_t lblk) ...@@ -1660,6 +1645,7 @@ static int ext4_insert_delayed_block(struct inode *inode, ext4_lblk_t lblk)
ret = ext4_da_reserve_space(inode); ret = ext4_da_reserve_space(inode);
if (ret != 0) /* ENOSPC */ if (ret != 0) /* ENOSPC */
goto errout; goto errout;
reserved = true;
} else { /* bigalloc */ } else { /* bigalloc */
if (!ext4_es_scan_clu(inode, &ext4_es_is_delonly, lblk)) { if (!ext4_es_scan_clu(inode, &ext4_es_is_delonly, lblk)) {
if (!ext4_es_scan_clu(inode, if (!ext4_es_scan_clu(inode,
...@@ -1672,6 +1658,7 @@ static int ext4_insert_delayed_block(struct inode *inode, ext4_lblk_t lblk) ...@@ -1672,6 +1658,7 @@ static int ext4_insert_delayed_block(struct inode *inode, ext4_lblk_t lblk)
ret = ext4_da_reserve_space(inode); ret = ext4_da_reserve_space(inode);
if (ret != 0) /* ENOSPC */ if (ret != 0) /* ENOSPC */
goto errout; goto errout;
reserved = true;
} else { } else {
allocated = true; allocated = true;
} }
...@@ -1682,6 +1669,8 @@ static int ext4_insert_delayed_block(struct inode *inode, ext4_lblk_t lblk) ...@@ -1682,6 +1669,8 @@ static int ext4_insert_delayed_block(struct inode *inode, ext4_lblk_t lblk)
} }
ret = ext4_es_insert_delayed_block(inode, lblk, allocated); ret = ext4_es_insert_delayed_block(inode, lblk, allocated);
if (ret && reserved)
ext4_da_release_space(inode, 1);
errout: errout:
return ret; return ret;
...@@ -1722,13 +1711,16 @@ static int ext4_da_map_blocks(struct inode *inode, sector_t iblock, ...@@ -1722,13 +1711,16 @@ static int ext4_da_map_blocks(struct inode *inode, sector_t iblock,
} }
/* /*
* Delayed extent could be allocated by fallocate. * the buffer head associated with a delayed and not unwritten
* So we need to check it. * block found in the extent status cache must contain an
* invalid block number and have its BH_New and BH_Delay bits
* set, reflecting the state assigned when the block was
* initially delayed allocated
*/ */
if (ext4_es_is_delayed(&es) && !ext4_es_is_unwritten(&es)) { if (ext4_es_is_delonly(&es)) {
map_bh(bh, inode->i_sb, invalid_block); BUG_ON(bh->b_blocknr != invalid_block);
set_buffer_new(bh); BUG_ON(!buffer_new(bh));
set_buffer_delay(bh); BUG_ON(!buffer_delay(bh));
return 0; return 0;
} }
...@@ -2932,19 +2924,6 @@ static int ext4_nonda_switch(struct super_block *sb) ...@@ -2932,19 +2924,6 @@ static int ext4_nonda_switch(struct super_block *sb)
return 0; return 0;
} }
/* We always reserve for an inode update; the superblock could be there too */
static int ext4_da_write_credits(struct inode *inode, loff_t pos, unsigned len)
{
if (likely(ext4_has_feature_large_file(inode->i_sb)))
return 1;
if (pos + len <= 0x7fffffffULL)
return 1;
/* We might need to update the superblock to set LARGE_FILE */
return 2;
}
static int ext4_da_write_begin(struct file *file, struct address_space *mapping, static int ext4_da_write_begin(struct file *file, struct address_space *mapping,
loff_t pos, unsigned len, unsigned flags, loff_t pos, unsigned len, unsigned flags,
struct page **pagep, void **fsdata) struct page **pagep, void **fsdata)
...@@ -2953,7 +2932,6 @@ static int ext4_da_write_begin(struct file *file, struct address_space *mapping, ...@@ -2953,7 +2932,6 @@ static int ext4_da_write_begin(struct file *file, struct address_space *mapping,
struct page *page; struct page *page;
pgoff_t index; pgoff_t index;
struct inode *inode = mapping->host; struct inode *inode = mapping->host;
handle_t *handle;
if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb)))) if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
return -EIO; return -EIO;
...@@ -2979,41 +2957,11 @@ static int ext4_da_write_begin(struct file *file, struct address_space *mapping, ...@@ -2979,41 +2957,11 @@ static int ext4_da_write_begin(struct file *file, struct address_space *mapping,
return 0; return 0;
} }
/* retry:
* grab_cache_page_write_begin() can take a long time if the
* system is thrashing due to memory pressure, or if the page
* is being written back. So grab it first before we start
* the transaction handle. This also allows us to allocate
* the page (if needed) without using GFP_NOFS.
*/
retry_grab:
page = grab_cache_page_write_begin(mapping, index, flags); page = grab_cache_page_write_begin(mapping, index, flags);
if (!page) if (!page)
return -ENOMEM; return -ENOMEM;
unlock_page(page);
/*
* With delayed allocation, we don't log the i_disksize update
* if there is delayed block allocation. But we still need
* to journalling the i_disksize update if writes to the end
* of file which has an already mapped buffer.
*/
retry_journal:
handle = ext4_journal_start(inode, EXT4_HT_WRITE_PAGE,
ext4_da_write_credits(inode, pos, len));
if (IS_ERR(handle)) {
put_page(page);
return PTR_ERR(handle);
}
lock_page(page);
if (page->mapping != mapping) {
/* The page got truncated from under us */
unlock_page(page);
put_page(page);
ext4_journal_stop(handle);
goto retry_grab;
}
/* In case writeback began while the page was unlocked */ /* In case writeback began while the page was unlocked */
wait_for_stable_page(page); wait_for_stable_page(page);
...@@ -3025,20 +2973,18 @@ static int ext4_da_write_begin(struct file *file, struct address_space *mapping, ...@@ -3025,20 +2973,18 @@ static int ext4_da_write_begin(struct file *file, struct address_space *mapping,
#endif #endif
if (ret < 0) { if (ret < 0) {
unlock_page(page); unlock_page(page);
ext4_journal_stop(handle); put_page(page);
/* /*
* block_write_begin may have instantiated a few blocks * block_write_begin may have instantiated a few blocks
* outside i_size. Trim these off again. Don't need * outside i_size. Trim these off again. Don't need
* i_size_read because we hold i_mutex. * i_size_read because we hold inode lock.
*/ */
if (pos + len > inode->i_size) if (pos + len > inode->i_size)
ext4_truncate_failed_write(inode); ext4_truncate_failed_write(inode);
if (ret == -ENOSPC && if (ret == -ENOSPC &&
ext4_should_retry_alloc(inode->i_sb, &retries)) ext4_should_retry_alloc(inode->i_sb, &retries))
goto retry_journal; goto retry;
put_page(page);
return ret; return ret;
} }
...@@ -3075,8 +3021,6 @@ static int ext4_da_write_end(struct file *file, ...@@ -3075,8 +3021,6 @@ static int ext4_da_write_end(struct file *file,
struct page *page, void *fsdata) struct page *page, void *fsdata)
{ {
struct inode *inode = mapping->host; struct inode *inode = mapping->host;
int ret = 0, ret2;
handle_t *handle = ext4_journal_current_handle();
loff_t new_i_size; loff_t new_i_size;
unsigned long start, end; unsigned long start, end;
int write_mode = (int)(unsigned long)fsdata; int write_mode = (int)(unsigned long)fsdata;
...@@ -3086,44 +3030,36 @@ static int ext4_da_write_end(struct file *file, ...@@ -3086,44 +3030,36 @@ static int ext4_da_write_end(struct file *file,
len, copied, page, fsdata); len, copied, page, fsdata);
trace_ext4_da_write_end(inode, pos, len, copied); trace_ext4_da_write_end(inode, pos, len, copied);
if (write_mode != CONVERT_INLINE_DATA &&
ext4_test_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA) &&
ext4_has_inline_data(inode))
return ext4_write_inline_data_end(inode, pos, len, copied, page);
start = pos & (PAGE_SIZE - 1); start = pos & (PAGE_SIZE - 1);
end = start + copied - 1; end = start + copied - 1;
/* /*
* generic_write_end() will run mark_inode_dirty() if i_size * Since we are holding inode lock, we are sure i_disksize <=
* changes. So let's piggyback the i_disksize mark_inode_dirty * i_size. We also know that if i_disksize < i_size, there are
* into that. * delalloc writes pending in the range upto i_size. If the end of
* the current write is <= i_size, there's no need to touch
* i_disksize since writeback will push i_disksize upto i_size
* eventually. If the end of the current write is > i_size and
* inside an allocated block (ext4_da_should_update_i_disksize()
* check), we need to update i_disksize here as neither
* ext4_writepage() nor certain ext4_writepages() paths not
* allocating blocks update i_disksize.
*
* Note that we defer inode dirtying to generic_write_end() /
* ext4_da_write_inline_data_end().
*/ */
new_i_size = pos + copied; new_i_size = pos + copied;
if (copied && new_i_size > EXT4_I(inode)->i_disksize) { if (copied && new_i_size > inode->i_size &&
if (ext4_has_inline_data(inode) || ext4_da_should_update_i_disksize(page, end))
ext4_da_should_update_i_disksize(page, end)) { ext4_update_i_disksize(inode, new_i_size);
ext4_update_i_disksize(inode, new_i_size);
/* We need to mark inode dirty even if
* new_i_size is less that inode->i_size
* bu greater than i_disksize.(hint delalloc)
*/
ret = ext4_mark_inode_dirty(handle, inode);
}
}
if (write_mode != CONVERT_INLINE_DATA && return generic_write_end(file, mapping, pos, len, copied, page, fsdata);
ext4_test_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA) &&
ext4_has_inline_data(inode))
ret2 = ext4_da_write_inline_data_end(inode, pos, len, copied,
page);
else
ret2 = generic_write_end(file, mapping, pos, len, copied,
page, fsdata);
copied = ret2;
if (ret2 < 0)
ret = ret2;
ret2 = ext4_journal_stop(handle);
if (unlikely(ret2 && !ret))
ret = ret2;
return ret ? ret : copied;
} }
/* /*
...@@ -4340,6 +4276,12 @@ static int __ext4_get_inode_loc(struct super_block *sb, unsigned long ino, ...@@ -4340,6 +4276,12 @@ static int __ext4_get_inode_loc(struct super_block *sb, unsigned long ino,
goto has_buffer; goto has_buffer;
lock_buffer(bh); lock_buffer(bh);
if (ext4_buffer_uptodate(bh)) {
/* Someone brought it uptodate while we waited */
unlock_buffer(bh);
goto has_buffer;
}
/* /*
* If we have all information of the inode in memory and this * If we have all information of the inode in memory and this
* is the only valid inode in the block, we need not read the * is the only valid inode in the block, we need not read the
......
...@@ -658,7 +658,7 @@ static void ext4_handle_error(struct super_block *sb, bool force_ro, int error, ...@@ -658,7 +658,7 @@ static void ext4_handle_error(struct super_block *sb, bool force_ro, int error,
* constraints, it may not be safe to do it right here so we * constraints, it may not be safe to do it right here so we
* defer superblock flushing to a workqueue. * defer superblock flushing to a workqueue.
*/ */
if (continue_fs) if (continue_fs && journal)
schedule_work(&EXT4_SB(sb)->s_error_work); schedule_work(&EXT4_SB(sb)->s_error_work);
else else
ext4_commit_super(sb); ext4_commit_super(sb);
...@@ -1350,6 +1350,12 @@ static void ext4_destroy_inode(struct inode *inode) ...@@ -1350,6 +1350,12 @@ static void ext4_destroy_inode(struct inode *inode)
true); true);
dump_stack(); dump_stack();
} }
if (EXT4_I(inode)->i_reserved_data_blocks)
ext4_msg(inode->i_sb, KERN_ERR,
"Inode %lu (%p): i_reserved_data_blocks (%u) not cleared!",
inode->i_ino, EXT4_I(inode),
EXT4_I(inode)->i_reserved_data_blocks);
} }
static void init_once(void *foo) static void init_once(void *foo)
...@@ -3021,17 +3027,17 @@ static loff_t ext4_max_size(int blkbits, int has_huge_files) ...@@ -3021,17 +3027,17 @@ static loff_t ext4_max_size(int blkbits, int has_huge_files)
*/ */
static loff_t ext4_max_bitmap_size(int bits, int has_huge_files) static loff_t ext4_max_bitmap_size(int bits, int has_huge_files)
{ {
loff_t res = EXT4_NDIR_BLOCKS; unsigned long long upper_limit, res = EXT4_NDIR_BLOCKS;
int meta_blocks; int meta_blocks;
loff_t upper_limit;
/* This is calculated to be the largest file size for a dense, block /*
* This is calculated to be the largest file size for a dense, block
* mapped file such that the file's total number of 512-byte sectors, * mapped file such that the file's total number of 512-byte sectors,
* including data and all indirect blocks, does not exceed (2^48 - 1). * including data and all indirect blocks, does not exceed (2^48 - 1).
* *
* __u32 i_blocks_lo and _u16 i_blocks_high represent the total * __u32 i_blocks_lo and _u16 i_blocks_high represent the total
* number of 512-byte sectors of the file. * number of 512-byte sectors of the file.
*/ */
if (!has_huge_files) { if (!has_huge_files) {
/* /*
* !has_huge_files or implies that the inode i_block field * !has_huge_files or implies that the inode i_block field
...@@ -3074,7 +3080,7 @@ static loff_t ext4_max_bitmap_size(int bits, int has_huge_files) ...@@ -3074,7 +3080,7 @@ static loff_t ext4_max_bitmap_size(int bits, int has_huge_files)
if (res > MAX_LFS_FILESIZE) if (res > MAX_LFS_FILESIZE)
res = MAX_LFS_FILESIZE; res = MAX_LFS_FILESIZE;
return res; return (loff_t)res;
} }
static ext4_fsblk_t descriptor_loc(struct super_block *sb, static ext4_fsblk_t descriptor_loc(struct super_block *sb,
...@@ -5042,12 +5048,15 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) ...@@ -5042,12 +5048,15 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
sbi->s_ea_block_cache = NULL; sbi->s_ea_block_cache = NULL;
if (sbi->s_journal) { if (sbi->s_journal) {
/* flush s_error_work before journal destroy. */
flush_work(&sbi->s_error_work);
jbd2_journal_destroy(sbi->s_journal); jbd2_journal_destroy(sbi->s_journal);
sbi->s_journal = NULL; sbi->s_journal = NULL;
} }
failed_mount3a: failed_mount3a:
ext4_es_unregister_shrinker(sbi); ext4_es_unregister_shrinker(sbi);
failed_mount3: failed_mount3:
/* flush s_error_work before sbi destroy */
flush_work(&sbi->s_error_work); flush_work(&sbi->s_error_work);
del_timer_sync(&sbi->s_err_report); del_timer_sync(&sbi->s_err_report);
ext4_stop_mmpd(sbi); ext4_stop_mmpd(sbi);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment