Fix a number of bugs, most notably a potential stale data exposure
after a crash and a potential BUG_ON crash if a file has the data journalling flag enabled while it has dirty delayed allocation blocks that haven't been written yet. Also fix a potential crash in the new project quota code and a maliciously corrupted file system. In addition, fix some DAX-specific bugs, including when there is a transient ENOSPC situation and races between writes via direct I/O and an mmap'ed segment that could lead to lost I/O. Finally the usual set of miscellaneous cleanups. -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iQEcBAABCAAGBQJXQ40fAAoJEPL5WVaVDYGjnwMH+wXHASgPfzZgtRInsTG8W/2L jsmAcMlyMAYIATWMppNtPIq0td49z1dYO0YkKhtPVMwfzu230IFWhGWp93WqP9ve XYHMmaBorFlMAzWgMKn1K0ExWZlV+ammmcTKgU0kU4qyZp0G/NnMtlXIkSNv2amI 9Mn6R+v97c20gn8e9HWP/IVWkgPr+WBtEXaSGjC7dL6yI8hL+rJMqN82D76oU5ea vtwzrna/ISijy+etYmQzqHNYNaBKf40+B5HxQZw/Ta3FSHofBwXAyLaeEAr260Mf V3Eg2NDcKQxiZ3adBzIUvrRnrJV381OmHoguo8Frs8YHTTRiZ0T/s7FGr2Q0NYE= =7yIM -----END PGP SIGNATURE----- Merge tag 'ext4_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4 Pull ext4 updates from Ted Ts'o: "Fix a number of bugs, most notably a potential stale data exposure after a crash and a potential BUG_ON crash if a file has the data journalling flag enabled while it has dirty delayed allocation blocks that haven't been written yet. Also fix a potential crash in the new project quota code and a maliciously corrupted file system. In addition, fix some DAX-specific bugs, including when there is a transient ENOSPC situation and races between writes via direct I/O and an mmap'ed segment that could lead to lost I/O. Finally the usual set of miscellaneous cleanups" * tag 'ext4_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4: (23 commits) ext4: pre-zero allocated blocks for DAX IO ext4: refactor direct IO code ext4: fix race in transient ENOSPC detection ext4: handle transient ENOSPC properly for DAX dax: call get_blocks() with create == 1 for write faults to unwritten extents ext4: remove unmeetable inconsisteny check from ext4_find_extent() jbd2: remove excess descriptions for handle_s ext4: remove unnecessary bio get/put ext4: silence UBSAN in ext4_mb_init() ext4: address UBSAN warning in mb_find_order_for_block() ext4: fix oops on corrupted filesystem ext4: fix check of dqget() return value in ext4_ioctl_setproject() ext4: clean up error handling when orphan list is corrupted ext4: fix hang when processing corrupted orphaned inode list ext4: remove trailing \n from ext4_warning/ext4_error calls ext4: fix races between changing inode journal mode and ext4_writepages ext4: handle unwritten or delalloc buffers before enabling data journaling ext4: fix jbd2 handle extension in ext4_ext_truncate_extend_restart() ext4: do not ask jbd2 to write data for delalloc buffers jbd2: add support for avoiding data writes during transaction commits ...
This commit is contained in:
Коммит
0e01df100b
|
@ -936,6 +936,8 @@ static int compat_filldir(struct dir_context *ctx, const char *name, int namlen,
|
|||
}
|
||||
dirent = buf->previous;
|
||||
if (dirent) {
|
||||
if (signal_pending(current))
|
||||
return -EINTR;
|
||||
if (__put_user(offset, &dirent->d_off))
|
||||
goto efault;
|
||||
}
|
||||
|
@ -1020,6 +1022,8 @@ static int compat_filldir64(struct dir_context *ctx, const char *name,
|
|||
dirent = buf->previous;
|
||||
|
||||
if (dirent) {
|
||||
if (signal_pending(current))
|
||||
return -EINTR;
|
||||
if (__put_user_unaligned(offset, &dirent->d_off))
|
||||
goto efault;
|
||||
}
|
||||
|
|
2
fs/dax.c
2
fs/dax.c
|
@ -676,7 +676,7 @@ int __dax_fault(struct vm_area_struct *vma, struct vm_fault *vmf,
|
|||
if (error)
|
||||
goto unlock_page;
|
||||
|
||||
if (!buffer_mapped(&bh) && !buffer_unwritten(&bh) && !vmf->cow_page) {
|
||||
if (!buffer_mapped(&bh) && !vmf->cow_page) {
|
||||
if (vmf->flags & FAULT_FLAG_WRITE) {
|
||||
error = get_block(inode, block, &bh, 1);
|
||||
count_vm_event(PGMAJFAULT);
|
||||
|
|
|
@ -610,7 +610,8 @@ int ext4_should_retry_alloc(struct super_block *sb, int *retries)
|
|||
|
||||
jbd_debug(1, "%s: retrying operation after ENOSPC\n", sb->s_id);
|
||||
|
||||
return jbd2_journal_force_commit_nested(EXT4_SB(sb)->s_journal);
|
||||
jbd2_journal_force_commit_nested(EXT4_SB(sb)->s_journal);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -150,6 +150,11 @@ static int ext4_readdir(struct file *file, struct dir_context *ctx)
|
|||
while (ctx->pos < inode->i_size) {
|
||||
struct ext4_map_blocks map;
|
||||
|
||||
if (fatal_signal_pending(current)) {
|
||||
err = -ERESTARTSYS;
|
||||
goto errout;
|
||||
}
|
||||
cond_resched();
|
||||
map.m_lblk = ctx->pos >> EXT4_BLOCK_SIZE_BITS(sb);
|
||||
map.m_len = 1;
|
||||
err = ext4_map_blocks(NULL, inode, &map, 0);
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include <linux/ratelimit.h>
|
||||
#include <crypto/hash.h>
|
||||
#include <linux/falloc.h>
|
||||
#include <linux/percpu-rwsem.h>
|
||||
#ifdef __KERNEL__
|
||||
#include <linux/compat.h>
|
||||
#endif
|
||||
|
@ -581,6 +582,9 @@ enum {
|
|||
#define EXT4_GET_BLOCKS_ZERO 0x0200
|
||||
#define EXT4_GET_BLOCKS_CREATE_ZERO (EXT4_GET_BLOCKS_CREATE |\
|
||||
EXT4_GET_BLOCKS_ZERO)
|
||||
/* Caller will submit data before dropping transaction handle. This
|
||||
* allows jbd2 to avoid submitting data before commit. */
|
||||
#define EXT4_GET_BLOCKS_IO_SUBMIT 0x0400
|
||||
|
||||
/*
|
||||
* The bit position of these flags must not overlap with any of the
|
||||
|
@ -1505,6 +1509,9 @@ struct ext4_sb_info {
|
|||
struct ratelimit_state s_err_ratelimit_state;
|
||||
struct ratelimit_state s_warning_ratelimit_state;
|
||||
struct ratelimit_state s_msg_ratelimit_state;
|
||||
|
||||
/* Barrier between changing inodes' journal flags and writepages ops. */
|
||||
struct percpu_rw_semaphore s_journal_flag_rwsem;
|
||||
};
|
||||
|
||||
static inline struct ext4_sb_info *EXT4_SB(struct super_block *sb)
|
||||
|
@ -1549,7 +1556,6 @@ enum {
|
|||
EXT4_STATE_DIOREAD_LOCK, /* Disable support for dio read
|
||||
nolocking */
|
||||
EXT4_STATE_MAY_INLINE_DATA, /* may have in-inode data */
|
||||
EXT4_STATE_ORDERED_MODE, /* data=ordered mode */
|
||||
EXT4_STATE_EXT_PRECACHED, /* extents have been precached */
|
||||
};
|
||||
|
||||
|
@ -2521,8 +2527,8 @@ struct buffer_head *ext4_getblk(handle_t *, struct inode *, ext4_lblk_t, int);
|
|||
struct buffer_head *ext4_bread(handle_t *, struct inode *, ext4_lblk_t, int);
|
||||
int ext4_get_block_unwritten(struct inode *inode, sector_t iblock,
|
||||
struct buffer_head *bh_result, int create);
|
||||
int ext4_dax_mmap_get_block(struct inode *inode, sector_t iblock,
|
||||
struct buffer_head *bh_result, int create);
|
||||
int ext4_dax_get_block(struct inode *inode, sector_t iblock,
|
||||
struct buffer_head *bh_result, int create);
|
||||
int ext4_get_block(struct inode *inode, sector_t iblock,
|
||||
struct buffer_head *bh_result, int create);
|
||||
int ext4_dio_get_block(struct inode *inode, sector_t iblock,
|
||||
|
@ -2581,7 +2587,6 @@ extern int ext4_get_next_extent(struct inode *inode, ext4_lblk_t lblk,
|
|||
/* indirect.c */
|
||||
extern int ext4_ind_map_blocks(handle_t *handle, struct inode *inode,
|
||||
struct ext4_map_blocks *map, int flags);
|
||||
extern ssize_t ext4_ind_direct_IO(struct kiocb *iocb, struct iov_iter *iter);
|
||||
extern int ext4_ind_calc_metadata_amount(struct inode *inode, sector_t lblock);
|
||||
extern int ext4_ind_trans_blocks(struct inode *inode, int nrblocks);
|
||||
extern void ext4_ind_truncate(handle_t *, struct inode *inode);
|
||||
|
@ -3329,6 +3334,13 @@ static inline void ext4_clear_io_unwritten_flag(ext4_io_end_t *io_end)
|
|||
}
|
||||
}
|
||||
|
||||
static inline bool ext4_aligned_io(struct inode *inode, loff_t off, loff_t len)
|
||||
{
|
||||
int blksize = 1 << inode->i_blkbits;
|
||||
|
||||
return IS_ALIGNED(off, blksize) && IS_ALIGNED(len, blksize);
|
||||
}
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
#define EFSBADCRC EBADMSG /* Bad CRC detected */
|
||||
|
|
|
@ -359,10 +359,21 @@ static inline int ext4_journal_force_commit(journal_t *journal)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline int ext4_jbd2_file_inode(handle_t *handle, struct inode *inode)
|
||||
static inline int ext4_jbd2_inode_add_write(handle_t *handle,
|
||||
struct inode *inode)
|
||||
{
|
||||
if (ext4_handle_valid(handle))
|
||||
return jbd2_journal_file_inode(handle, EXT4_I(inode)->jinode);
|
||||
return jbd2_journal_inode_add_write(handle,
|
||||
EXT4_I(inode)->jinode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int ext4_jbd2_inode_add_wait(handle_t *handle,
|
||||
struct inode *inode)
|
||||
{
|
||||
if (ext4_handle_valid(handle))
|
||||
return jbd2_journal_inode_add_wait(handle,
|
||||
EXT4_I(inode)->jinode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -120,9 +120,14 @@ static int ext4_ext_truncate_extend_restart(handle_t *handle,
|
|||
|
||||
if (!ext4_handle_valid(handle))
|
||||
return 0;
|
||||
if (handle->h_buffer_credits > needed)
|
||||
if (handle->h_buffer_credits >= needed)
|
||||
return 0;
|
||||
err = ext4_journal_extend(handle, needed);
|
||||
/*
|
||||
* If we need to extend the journal get a few extra blocks
|
||||
* while we're at it for efficiency's sake.
|
||||
*/
|
||||
needed += 3;
|
||||
err = ext4_journal_extend(handle, needed - handle->h_buffer_credits);
|
||||
if (err <= 0)
|
||||
return err;
|
||||
err = ext4_truncate_restart_trans(handle, inode, needed);
|
||||
|
@ -907,13 +912,6 @@ ext4_find_extent(struct inode *inode, ext4_lblk_t block,
|
|||
|
||||
eh = ext_block_hdr(bh);
|
||||
ppos++;
|
||||
if (unlikely(ppos > depth)) {
|
||||
put_bh(bh);
|
||||
EXT4_ERROR_INODE(inode,
|
||||
"ppos %d > depth %d", ppos, depth);
|
||||
ret = -EFSCORRUPTED;
|
||||
goto err;
|
||||
}
|
||||
path[ppos].p_bh = bh;
|
||||
path[ppos].p_hdr = eh;
|
||||
}
|
||||
|
@ -2583,7 +2581,7 @@ static int ext4_remove_blocks(handle_t *handle, struct inode *inode,
|
|||
}
|
||||
} else
|
||||
ext4_error(sbi->s_sb, "strange request: removal(2) "
|
||||
"%u-%u from %u:%u\n",
|
||||
"%u-%u from %u:%u",
|
||||
from, to, le32_to_cpu(ex->ee_block), ee_len);
|
||||
return 0;
|
||||
}
|
||||
|
@ -3738,7 +3736,7 @@ static int ext4_convert_unwritten_extents_endio(handle_t *handle,
|
|||
if (ee_block != map->m_lblk || ee_len > map->m_len) {
|
||||
#ifdef EXT4_DEBUG
|
||||
ext4_warning("Inode (%ld) finished: extent logical block %llu,"
|
||||
" len %u; IO logical block %llu, len %u\n",
|
||||
" len %u; IO logical block %llu, len %u",
|
||||
inode->i_ino, (unsigned long long)ee_block, ee_len,
|
||||
(unsigned long long)map->m_lblk, map->m_len);
|
||||
#endif
|
||||
|
|
|
@ -707,7 +707,7 @@ int ext4_es_insert_extent(struct inode *inode, ext4_lblk_t lblk,
|
|||
(status & EXTENT_STATUS_WRITTEN)) {
|
||||
ext4_warning(inode->i_sb, "Inserting extent [%u/%u] as "
|
||||
" delayed and written which can potentially "
|
||||
" cause data loss.\n", lblk, len);
|
||||
" cause data loss.", lblk, len);
|
||||
WARN_ON(1);
|
||||
}
|
||||
|
||||
|
|
|
@ -202,7 +202,7 @@ static int ext4_dax_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
|
|||
if (IS_ERR(handle))
|
||||
result = VM_FAULT_SIGBUS;
|
||||
else
|
||||
result = __dax_fault(vma, vmf, ext4_dax_mmap_get_block, NULL);
|
||||
result = __dax_fault(vma, vmf, ext4_dax_get_block, NULL);
|
||||
|
||||
if (write) {
|
||||
if (!IS_ERR(handle))
|
||||
|
@ -238,7 +238,7 @@ static int ext4_dax_pmd_fault(struct vm_area_struct *vma, unsigned long addr,
|
|||
result = VM_FAULT_SIGBUS;
|
||||
else
|
||||
result = __dax_pmd_fault(vma, addr, pmd, flags,
|
||||
ext4_dax_mmap_get_block, NULL);
|
||||
ext4_dax_get_block, NULL);
|
||||
|
||||
if (write) {
|
||||
if (!IS_ERR(handle))
|
||||
|
@ -373,7 +373,7 @@ static int ext4_file_open(struct inode * inode, struct file * filp)
|
|||
if (ext4_encrypted_inode(d_inode(dir)) &&
|
||||
!ext4_is_child_context_consistent_with_parent(d_inode(dir), inode)) {
|
||||
ext4_warning(inode->i_sb,
|
||||
"Inconsistent encryption contexts: %lu/%lu\n",
|
||||
"Inconsistent encryption contexts: %lu/%lu",
|
||||
(unsigned long) d_inode(dir)->i_ino,
|
||||
(unsigned long) inode->i_ino);
|
||||
dput(dir);
|
||||
|
|
|
@ -1150,25 +1150,20 @@ struct inode *ext4_orphan_get(struct super_block *sb, unsigned long ino)
|
|||
unsigned long max_ino = le32_to_cpu(EXT4_SB(sb)->s_es->s_inodes_count);
|
||||
ext4_group_t block_group;
|
||||
int bit;
|
||||
struct buffer_head *bitmap_bh;
|
||||
struct buffer_head *bitmap_bh = NULL;
|
||||
struct inode *inode = NULL;
|
||||
long err = -EIO;
|
||||
int err = -EFSCORRUPTED;
|
||||
|
||||
/* Error cases - e2fsck has already cleaned up for us */
|
||||
if (ino > max_ino) {
|
||||
ext4_warning(sb, "bad orphan ino %lu! e2fsck was run?", ino);
|
||||
err = -EFSCORRUPTED;
|
||||
goto error;
|
||||
}
|
||||
if (ino < EXT4_FIRST_INO(sb) || ino > max_ino)
|
||||
goto bad_orphan;
|
||||
|
||||
block_group = (ino - 1) / EXT4_INODES_PER_GROUP(sb);
|
||||
bit = (ino - 1) % EXT4_INODES_PER_GROUP(sb);
|
||||
bitmap_bh = ext4_read_inode_bitmap(sb, block_group);
|
||||
if (IS_ERR(bitmap_bh)) {
|
||||
err = PTR_ERR(bitmap_bh);
|
||||
ext4_warning(sb, "inode bitmap error %ld for orphan %lu",
|
||||
ino, err);
|
||||
goto error;
|
||||
ext4_error(sb, "inode bitmap error %ld for orphan %lu",
|
||||
ino, PTR_ERR(bitmap_bh));
|
||||
return (struct inode *) bitmap_bh;
|
||||
}
|
||||
|
||||
/* Having the inode bit set should be a 100% indicator that this
|
||||
|
@ -1179,15 +1174,21 @@ struct inode *ext4_orphan_get(struct super_block *sb, unsigned long ino)
|
|||
goto bad_orphan;
|
||||
|
||||
inode = ext4_iget(sb, ino);
|
||||
if (IS_ERR(inode))
|
||||
goto iget_failed;
|
||||
if (IS_ERR(inode)) {
|
||||
err = PTR_ERR(inode);
|
||||
ext4_error(sb, "couldn't read orphan inode %lu (err %d)",
|
||||
ino, err);
|
||||
return inode;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the orphans has i_nlinks > 0 then it should be able to be
|
||||
* truncated, otherwise it won't be removed from the orphan list
|
||||
* during processing and an infinite loop will result.
|
||||
* If the orphans has i_nlinks > 0 then it should be able to
|
||||
* be truncated, otherwise it won't be removed from the orphan
|
||||
* list during processing and an infinite loop will result.
|
||||
* Similarly, it must not be a bad inode.
|
||||
*/
|
||||
if (inode->i_nlink && !ext4_can_truncate(inode))
|
||||
if ((inode->i_nlink && !ext4_can_truncate(inode)) ||
|
||||
is_bad_inode(inode))
|
||||
goto bad_orphan;
|
||||
|
||||
if (NEXT_ORPHAN(inode) > max_ino)
|
||||
|
@ -1195,29 +1196,25 @@ struct inode *ext4_orphan_get(struct super_block *sb, unsigned long ino)
|
|||
brelse(bitmap_bh);
|
||||
return inode;
|
||||
|
||||
iget_failed:
|
||||
err = PTR_ERR(inode);
|
||||
inode = NULL;
|
||||
bad_orphan:
|
||||
ext4_warning(sb, "bad orphan inode %lu! e2fsck was run?", ino);
|
||||
printk(KERN_WARNING "ext4_test_bit(bit=%d, block=%llu) = %d\n",
|
||||
bit, (unsigned long long)bitmap_bh->b_blocknr,
|
||||
ext4_test_bit(bit, bitmap_bh->b_data));
|
||||
printk(KERN_WARNING "inode=%p\n", inode);
|
||||
ext4_error(sb, "bad orphan inode %lu", ino);
|
||||
if (bitmap_bh)
|
||||
printk(KERN_ERR "ext4_test_bit(bit=%d, block=%llu) = %d\n",
|
||||
bit, (unsigned long long)bitmap_bh->b_blocknr,
|
||||
ext4_test_bit(bit, bitmap_bh->b_data));
|
||||
if (inode) {
|
||||
printk(KERN_WARNING "is_bad_inode(inode)=%d\n",
|
||||
printk(KERN_ERR "is_bad_inode(inode)=%d\n",
|
||||
is_bad_inode(inode));
|
||||
printk(KERN_WARNING "NEXT_ORPHAN(inode)=%u\n",
|
||||
printk(KERN_ERR "NEXT_ORPHAN(inode)=%u\n",
|
||||
NEXT_ORPHAN(inode));
|
||||
printk(KERN_WARNING "max_ino=%lu\n", max_ino);
|
||||
printk(KERN_WARNING "i_nlink=%u\n", inode->i_nlink);
|
||||
printk(KERN_ERR "max_ino=%lu\n", max_ino);
|
||||
printk(KERN_ERR "i_nlink=%u\n", inode->i_nlink);
|
||||
/* Avoid freeing blocks if we got a bad deleted inode */
|
||||
if (inode->i_nlink == 0)
|
||||
inode->i_blocks = 0;
|
||||
iput(inode);
|
||||
}
|
||||
brelse(bitmap_bh);
|
||||
error:
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
|
|
|
@ -648,133 +648,6 @@ out:
|
|||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* O_DIRECT for ext3 (or indirect map) based files
|
||||
*
|
||||
* If the O_DIRECT write will extend the file then add this inode to the
|
||||
* orphan list. So recovery will truncate it back to the original size
|
||||
* if the machine crashes during the write.
|
||||
*
|
||||
* If the O_DIRECT write is intantiating holes inside i_size and the machine
|
||||
* crashes then stale disk data _may_ be exposed inside the file. But current
|
||||
* VFS code falls back into buffered path in that case so we are safe.
|
||||
*/
|
||||
ssize_t ext4_ind_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
|
||||
{
|
||||
struct file *file = iocb->ki_filp;
|
||||
struct inode *inode = file->f_mapping->host;
|
||||
struct ext4_inode_info *ei = EXT4_I(inode);
|
||||
loff_t offset = iocb->ki_pos;
|
||||
handle_t *handle;
|
||||
ssize_t ret;
|
||||
int orphan = 0;
|
||||
size_t count = iov_iter_count(iter);
|
||||
int retries = 0;
|
||||
|
||||
if (iov_iter_rw(iter) == WRITE) {
|
||||
loff_t final_size = offset + count;
|
||||
|
||||
if (final_size > inode->i_size) {
|
||||
/* Credits for sb + inode write */
|
||||
handle = ext4_journal_start(inode, EXT4_HT_INODE, 2);
|
||||
if (IS_ERR(handle)) {
|
||||
ret = PTR_ERR(handle);
|
||||
goto out;
|
||||
}
|
||||
ret = ext4_orphan_add(handle, inode);
|
||||
if (ret) {
|
||||
ext4_journal_stop(handle);
|
||||
goto out;
|
||||
}
|
||||
orphan = 1;
|
||||
ei->i_disksize = inode->i_size;
|
||||
ext4_journal_stop(handle);
|
||||
}
|
||||
}
|
||||
|
||||
retry:
|
||||
if (iov_iter_rw(iter) == READ && ext4_should_dioread_nolock(inode)) {
|
||||
/*
|
||||
* Nolock dioread optimization may be dynamically disabled
|
||||
* via ext4_inode_block_unlocked_dio(). Check inode's state
|
||||
* while holding extra i_dio_count ref.
|
||||
*/
|
||||
inode_dio_begin(inode);
|
||||
smp_mb();
|
||||
if (unlikely(ext4_test_inode_state(inode,
|
||||
EXT4_STATE_DIOREAD_LOCK))) {
|
||||
inode_dio_end(inode);
|
||||
goto locked;
|
||||
}
|
||||
if (IS_DAX(inode))
|
||||
ret = dax_do_io(iocb, inode, iter,
|
||||
ext4_dio_get_block, NULL, 0);
|
||||
else
|
||||
ret = __blockdev_direct_IO(iocb, inode,
|
||||
inode->i_sb->s_bdev, iter,
|
||||
ext4_dio_get_block,
|
||||
NULL, NULL, 0);
|
||||
inode_dio_end(inode);
|
||||
} else {
|
||||
locked:
|
||||
if (IS_DAX(inode))
|
||||
ret = dax_do_io(iocb, inode, iter,
|
||||
ext4_dio_get_block, NULL, DIO_LOCKING);
|
||||
else
|
||||
ret = blockdev_direct_IO(iocb, inode, iter,
|
||||
ext4_dio_get_block);
|
||||
|
||||
if (unlikely(iov_iter_rw(iter) == WRITE && ret < 0)) {
|
||||
loff_t isize = i_size_read(inode);
|
||||
loff_t end = offset + count;
|
||||
|
||||
if (end > isize)
|
||||
ext4_truncate_failed_write(inode);
|
||||
}
|
||||
}
|
||||
if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries))
|
||||
goto retry;
|
||||
|
||||
if (orphan) {
|
||||
int err;
|
||||
|
||||
/* Credits for sb + inode write */
|
||||
handle = ext4_journal_start(inode, EXT4_HT_INODE, 2);
|
||||
if (IS_ERR(handle)) {
|
||||
/* This is really bad luck. We've written the data
|
||||
* but cannot extend i_size. Bail out and pretend
|
||||
* the write failed... */
|
||||
ret = PTR_ERR(handle);
|
||||
if (inode->i_nlink)
|
||||
ext4_orphan_del(NULL, inode);
|
||||
|
||||
goto out;
|
||||
}
|
||||
if (inode->i_nlink)
|
||||
ext4_orphan_del(handle, inode);
|
||||
if (ret > 0) {
|
||||
loff_t end = offset + ret;
|
||||
if (end > inode->i_size) {
|
||||
ei->i_disksize = end;
|
||||
i_size_write(inode, end);
|
||||
/*
|
||||
* We're going to return a positive `ret'
|
||||
* here due to non-zero-length I/O, so there's
|
||||
* no way of reporting error returns from
|
||||
* ext4_mark_inode_dirty() to userspace. So
|
||||
* ignore it.
|
||||
*/
|
||||
ext4_mark_inode_dirty(handle, inode);
|
||||
}
|
||||
}
|
||||
err = ext4_journal_stop(handle);
|
||||
if (ret == 0)
|
||||
ret = err;
|
||||
}
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate the number of metadata blocks need to reserve
|
||||
* to allocate a new block at @lblocks for non extent file based file
|
||||
|
|
|
@ -1780,7 +1780,7 @@ int empty_inline_dir(struct inode *dir, int *has_inline_data)
|
|||
ext4_warning(dir->i_sb,
|
||||
"bad inline directory (dir #%lu) - "
|
||||
"inode %u, rec_len %u, name_len %d"
|
||||
"inline size %d\n",
|
||||
"inline size %d",
|
||||
dir->i_ino, le32_to_cpu(de->inode),
|
||||
le16_to_cpu(de->rec_len), de->name_len,
|
||||
inline_size);
|
||||
|
|
329
fs/ext4/inode.c
329
fs/ext4/inode.c
|
@ -684,6 +684,24 @@ out_sem:
|
|||
ret = check_block_validity(inode, map);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Inodes with freshly allocated blocks where contents will be
|
||||
* visible after transaction commit must be on transaction's
|
||||
* ordered data list.
|
||||
*/
|
||||
if (map->m_flags & EXT4_MAP_NEW &&
|
||||
!(map->m_flags & EXT4_MAP_UNWRITTEN) &&
|
||||
!(flags & EXT4_GET_BLOCKS_ZERO) &&
|
||||
!IS_NOQUOTA(inode) &&
|
||||
ext4_should_order_data(inode)) {
|
||||
if (flags & EXT4_GET_BLOCKS_IO_SUBMIT)
|
||||
ret = ext4_jbd2_inode_add_wait(handle, inode);
|
||||
else
|
||||
ret = ext4_jbd2_inode_add_write(handle, inode);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
@ -1289,15 +1307,6 @@ static int ext4_write_end(struct file *file,
|
|||
int i_size_changed = 0;
|
||||
|
||||
trace_ext4_write_end(inode, pos, len, copied);
|
||||
if (ext4_test_inode_state(inode, EXT4_STATE_ORDERED_MODE)) {
|
||||
ret = ext4_jbd2_file_inode(handle, inode);
|
||||
if (ret) {
|
||||
unlock_page(page);
|
||||
put_page(page);
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
|
||||
if (ext4_has_inline_data(inode)) {
|
||||
ret = ext4_write_inline_data_end(inode, pos, len,
|
||||
copied, page);
|
||||
|
@ -2313,7 +2322,8 @@ static int mpage_map_one_extent(handle_t *handle, struct mpage_da_data *mpd)
|
|||
* the data was copied into the page cache.
|
||||
*/
|
||||
get_blocks_flags = EXT4_GET_BLOCKS_CREATE |
|
||||
EXT4_GET_BLOCKS_METADATA_NOFAIL;
|
||||
EXT4_GET_BLOCKS_METADATA_NOFAIL |
|
||||
EXT4_GET_BLOCKS_IO_SUBMIT;
|
||||
dioread_nolock = ext4_should_dioread_nolock(inode);
|
||||
if (dioread_nolock)
|
||||
get_blocks_flags |= EXT4_GET_BLOCKS_IO_CREATE_EXT;
|
||||
|
@ -2602,11 +2612,14 @@ static int ext4_writepages(struct address_space *mapping,
|
|||
struct blk_plug plug;
|
||||
bool give_up_on_write = false;
|
||||
|
||||
percpu_down_read(&sbi->s_journal_flag_rwsem);
|
||||
trace_ext4_writepages(inode, wbc);
|
||||
|
||||
if (dax_mapping(mapping))
|
||||
return dax_writeback_mapping_range(mapping, inode->i_sb->s_bdev,
|
||||
wbc);
|
||||
if (dax_mapping(mapping)) {
|
||||
ret = dax_writeback_mapping_range(mapping, inode->i_sb->s_bdev,
|
||||
wbc);
|
||||
goto out_writepages;
|
||||
}
|
||||
|
||||
/*
|
||||
* No pages to write? This is mainly a kludge to avoid starting
|
||||
|
@ -2776,6 +2789,7 @@ retry:
|
|||
out_writepages:
|
||||
trace_ext4_writepages_result(inode, wbc, ret,
|
||||
nr_to_write - wbc->nr_to_write);
|
||||
percpu_up_read(&sbi->s_journal_flag_rwsem);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -3215,75 +3229,52 @@ static int ext4_releasepage(struct page *page, gfp_t wait)
|
|||
}
|
||||
|
||||
#ifdef CONFIG_FS_DAX
|
||||
int ext4_dax_mmap_get_block(struct inode *inode, sector_t iblock,
|
||||
struct buffer_head *bh_result, int create)
|
||||
/*
|
||||
* Get block function for DAX IO and mmap faults. It takes care of converting
|
||||
* unwritten extents to written ones and initializes new / converted blocks
|
||||
* to zeros.
|
||||
*/
|
||||
int ext4_dax_get_block(struct inode *inode, sector_t iblock,
|
||||
struct buffer_head *bh_result, int create)
|
||||
{
|
||||
int ret, err;
|
||||
int credits;
|
||||
struct ext4_map_blocks map;
|
||||
handle_t *handle = NULL;
|
||||
int flags = 0;
|
||||
int ret;
|
||||
|
||||
ext4_debug("ext4_dax_mmap_get_block: inode %lu, create flag %d\n",
|
||||
inode->i_ino, create);
|
||||
map.m_lblk = iblock;
|
||||
map.m_len = bh_result->b_size >> inode->i_blkbits;
|
||||
credits = ext4_chunk_trans_blocks(inode, map.m_len);
|
||||
if (create) {
|
||||
flags |= EXT4_GET_BLOCKS_PRE_IO | EXT4_GET_BLOCKS_CREATE_ZERO;
|
||||
handle = ext4_journal_start(inode, EXT4_HT_MAP_BLOCKS, credits);
|
||||
if (IS_ERR(handle)) {
|
||||
ret = PTR_ERR(handle);
|
||||
ext4_debug("inode %lu, create flag %d\n", inode->i_ino, create);
|
||||
if (!create)
|
||||
return _ext4_get_block(inode, iblock, bh_result, 0);
|
||||
|
||||
ret = ext4_get_block_trans(inode, iblock, bh_result,
|
||||
EXT4_GET_BLOCKS_PRE_IO |
|
||||
EXT4_GET_BLOCKS_CREATE_ZERO);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (buffer_unwritten(bh_result)) {
|
||||
/*
|
||||
* We are protected by i_mmap_sem or i_mutex so we know block
|
||||
* cannot go away from under us even though we dropped
|
||||
* i_data_sem. Convert extent to written and write zeros there.
|
||||
*/
|
||||
ret = ext4_get_block_trans(inode, iblock, bh_result,
|
||||
EXT4_GET_BLOCKS_CONVERT |
|
||||
EXT4_GET_BLOCKS_CREATE_ZERO);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ret = ext4_map_blocks(handle, inode, &map, flags);
|
||||
if (create) {
|
||||
err = ext4_journal_stop(handle);
|
||||
if (ret >= 0 && err < 0)
|
||||
ret = err;
|
||||
}
|
||||
if (ret <= 0)
|
||||
goto out;
|
||||
if (map.m_flags & EXT4_MAP_UNWRITTEN) {
|
||||
int err2;
|
||||
|
||||
/*
|
||||
* We are protected by i_mmap_sem so we know block cannot go
|
||||
* away from under us even though we dropped i_data_sem.
|
||||
* Convert extent to written and write zeros there.
|
||||
*
|
||||
* Note: We may get here even when create == 0.
|
||||
*/
|
||||
handle = ext4_journal_start(inode, EXT4_HT_MAP_BLOCKS, credits);
|
||||
if (IS_ERR(handle)) {
|
||||
ret = PTR_ERR(handle);
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = ext4_map_blocks(handle, inode, &map,
|
||||
EXT4_GET_BLOCKS_CONVERT | EXT4_GET_BLOCKS_CREATE_ZERO);
|
||||
if (err < 0)
|
||||
ret = err;
|
||||
err2 = ext4_journal_stop(handle);
|
||||
if (err2 < 0 && ret > 0)
|
||||
ret = err2;
|
||||
}
|
||||
out:
|
||||
WARN_ON_ONCE(ret == 0 && create);
|
||||
if (ret > 0) {
|
||||
map_bh(bh_result, inode->i_sb, map.m_pblk);
|
||||
/*
|
||||
* At least for now we have to clear BH_New so that DAX code
|
||||
* doesn't attempt to zero blocks again in a racy way.
|
||||
*/
|
||||
map.m_flags &= ~EXT4_MAP_NEW;
|
||||
ext4_update_bh_state(bh_result, map.m_flags);
|
||||
bh_result->b_size = map.m_len << inode->i_blkbits;
|
||||
ret = 0;
|
||||
}
|
||||
return ret;
|
||||
/*
|
||||
* At least for now we have to clear BH_New so that DAX code
|
||||
* doesn't attempt to zero blocks again in a racy way.
|
||||
*/
|
||||
clear_buffer_new(bh_result);
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
/* Just define empty function, it will never get called. */
|
||||
int ext4_dax_get_block(struct inode *inode, sector_t iblock,
|
||||
struct buffer_head *bh_result, int create)
|
||||
{
|
||||
BUG();
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -3316,7 +3307,9 @@ static int ext4_end_io_dio(struct kiocb *iocb, loff_t offset,
|
|||
}
|
||||
|
||||
/*
|
||||
* For ext4 extent files, ext4 will do direct-io write to holes,
|
||||
* Handling of direct IO writes.
|
||||
*
|
||||
* For ext4 extent files, ext4 will do direct-io write even to holes,
|
||||
* preallocated extents, and those write extend the file, no need to
|
||||
* fall back to buffered IO.
|
||||
*
|
||||
|
@ -3334,10 +3327,11 @@ static int ext4_end_io_dio(struct kiocb *iocb, loff_t offset,
|
|||
* if the machine crashes during the write.
|
||||
*
|
||||
*/
|
||||
static ssize_t ext4_ext_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
|
||||
static ssize_t ext4_direct_IO_write(struct kiocb *iocb, struct iov_iter *iter)
|
||||
{
|
||||
struct file *file = iocb->ki_filp;
|
||||
struct inode *inode = file->f_mapping->host;
|
||||
struct ext4_inode_info *ei = EXT4_I(inode);
|
||||
ssize_t ret;
|
||||
loff_t offset = iocb->ki_pos;
|
||||
size_t count = iov_iter_count(iter);
|
||||
|
@ -3345,10 +3339,25 @@ static ssize_t ext4_ext_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
|
|||
get_block_t *get_block_func = NULL;
|
||||
int dio_flags = 0;
|
||||
loff_t final_size = offset + count;
|
||||
int orphan = 0;
|
||||
handle_t *handle;
|
||||
|
||||
/* Use the old path for reads and writes beyond i_size. */
|
||||
if (iov_iter_rw(iter) != WRITE || final_size > inode->i_size)
|
||||
return ext4_ind_direct_IO(iocb, iter);
|
||||
if (final_size > inode->i_size) {
|
||||
/* Credits for sb + inode write */
|
||||
handle = ext4_journal_start(inode, EXT4_HT_INODE, 2);
|
||||
if (IS_ERR(handle)) {
|
||||
ret = PTR_ERR(handle);
|
||||
goto out;
|
||||
}
|
||||
ret = ext4_orphan_add(handle, inode);
|
||||
if (ret) {
|
||||
ext4_journal_stop(handle);
|
||||
goto out;
|
||||
}
|
||||
orphan = 1;
|
||||
ei->i_disksize = inode->i_size;
|
||||
ext4_journal_stop(handle);
|
||||
}
|
||||
|
||||
BUG_ON(iocb->private == NULL);
|
||||
|
||||
|
@ -3357,8 +3366,7 @@ static ssize_t ext4_ext_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
|
|||
* conversion. This also disallows race between truncate() and
|
||||
* overwrite DIO as i_dio_count needs to be incremented under i_mutex.
|
||||
*/
|
||||
if (iov_iter_rw(iter) == WRITE)
|
||||
inode_dio_begin(inode);
|
||||
inode_dio_begin(inode);
|
||||
|
||||
/* If we do a overwrite dio, i_mutex locking can be released */
|
||||
overwrite = *((int *)iocb->private);
|
||||
|
@ -3367,7 +3375,7 @@ static ssize_t ext4_ext_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
|
|||
inode_unlock(inode);
|
||||
|
||||
/*
|
||||
* We could direct write to holes and fallocate.
|
||||
* For extent mapped files we could direct write to holes and fallocate.
|
||||
*
|
||||
* Allocated blocks to fill the hole are marked as unwritten to prevent
|
||||
* parallel buffered read to expose the stale data before DIO complete
|
||||
|
@ -3389,7 +3397,23 @@ static ssize_t ext4_ext_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
|
|||
iocb->private = NULL;
|
||||
if (overwrite)
|
||||
get_block_func = ext4_dio_get_block_overwrite;
|
||||
else if (is_sync_kiocb(iocb)) {
|
||||
else if (IS_DAX(inode)) {
|
||||
/*
|
||||
* We can avoid zeroing for aligned DAX writes beyond EOF. Other
|
||||
* writes need zeroing either because they can race with page
|
||||
* faults or because they use partial blocks.
|
||||
*/
|
||||
if (round_down(offset, 1<<inode->i_blkbits) >= inode->i_size &&
|
||||
ext4_aligned_io(inode, offset, count))
|
||||
get_block_func = ext4_dio_get_block;
|
||||
else
|
||||
get_block_func = ext4_dax_get_block;
|
||||
dio_flags = DIO_LOCKING;
|
||||
} else if (!ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS) ||
|
||||
round_down(offset, 1 << inode->i_blkbits) >= inode->i_size) {
|
||||
get_block_func = ext4_dio_get_block;
|
||||
dio_flags = DIO_LOCKING | DIO_SKIP_HOLES;
|
||||
} else if (is_sync_kiocb(iocb)) {
|
||||
get_block_func = ext4_dio_get_block_unwritten_sync;
|
||||
dio_flags = DIO_LOCKING;
|
||||
} else {
|
||||
|
@ -3399,10 +3423,10 @@ static ssize_t ext4_ext_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
|
|||
#ifdef CONFIG_EXT4_FS_ENCRYPTION
|
||||
BUG_ON(ext4_encrypted_inode(inode) && S_ISREG(inode->i_mode));
|
||||
#endif
|
||||
if (IS_DAX(inode))
|
||||
if (IS_DAX(inode)) {
|
||||
ret = dax_do_io(iocb, inode, iter, get_block_func,
|
||||
ext4_end_io_dio, dio_flags);
|
||||
else
|
||||
} else
|
||||
ret = __blockdev_direct_IO(iocb, inode,
|
||||
inode->i_sb->s_bdev, iter,
|
||||
get_block_func,
|
||||
|
@ -3422,12 +3446,86 @@ static ssize_t ext4_ext_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
|
|||
ext4_clear_inode_state(inode, EXT4_STATE_DIO_UNWRITTEN);
|
||||
}
|
||||
|
||||
if (iov_iter_rw(iter) == WRITE)
|
||||
inode_dio_end(inode);
|
||||
inode_dio_end(inode);
|
||||
/* take i_mutex locking again if we do a ovewrite dio */
|
||||
if (overwrite)
|
||||
inode_lock(inode);
|
||||
|
||||
if (ret < 0 && final_size > inode->i_size)
|
||||
ext4_truncate_failed_write(inode);
|
||||
|
||||
/* Handle extending of i_size after direct IO write */
|
||||
if (orphan) {
|
||||
int err;
|
||||
|
||||
/* Credits for sb + inode write */
|
||||
handle = ext4_journal_start(inode, EXT4_HT_INODE, 2);
|
||||
if (IS_ERR(handle)) {
|
||||
/* This is really bad luck. We've written the data
|
||||
* but cannot extend i_size. Bail out and pretend
|
||||
* the write failed... */
|
||||
ret = PTR_ERR(handle);
|
||||
if (inode->i_nlink)
|
||||
ext4_orphan_del(NULL, inode);
|
||||
|
||||
goto out;
|
||||
}
|
||||
if (inode->i_nlink)
|
||||
ext4_orphan_del(handle, inode);
|
||||
if (ret > 0) {
|
||||
loff_t end = offset + ret;
|
||||
if (end > inode->i_size) {
|
||||
ei->i_disksize = end;
|
||||
i_size_write(inode, end);
|
||||
/*
|
||||
* We're going to return a positive `ret'
|
||||
* here due to non-zero-length I/O, so there's
|
||||
* no way of reporting error returns from
|
||||
* ext4_mark_inode_dirty() to userspace. So
|
||||
* ignore it.
|
||||
*/
|
||||
ext4_mark_inode_dirty(handle, inode);
|
||||
}
|
||||
}
|
||||
err = ext4_journal_stop(handle);
|
||||
if (ret == 0)
|
||||
ret = err;
|
||||
}
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t ext4_direct_IO_read(struct kiocb *iocb, struct iov_iter *iter)
|
||||
{
|
||||
int unlocked = 0;
|
||||
struct inode *inode = iocb->ki_filp->f_mapping->host;
|
||||
ssize_t ret;
|
||||
|
||||
if (ext4_should_dioread_nolock(inode)) {
|
||||
/*
|
||||
* Nolock dioread optimization may be dynamically disabled
|
||||
* via ext4_inode_block_unlocked_dio(). Check inode's state
|
||||
* while holding extra i_dio_count ref.
|
||||
*/
|
||||
inode_dio_begin(inode);
|
||||
smp_mb();
|
||||
if (unlikely(ext4_test_inode_state(inode,
|
||||
EXT4_STATE_DIOREAD_LOCK)))
|
||||
inode_dio_end(inode);
|
||||
else
|
||||
unlocked = 1;
|
||||
}
|
||||
if (IS_DAX(inode)) {
|
||||
ret = dax_do_io(iocb, inode, iter, ext4_dio_get_block,
|
||||
NULL, unlocked ? 0 : DIO_LOCKING);
|
||||
} else {
|
||||
ret = __blockdev_direct_IO(iocb, inode, inode->i_sb->s_bdev,
|
||||
iter, ext4_dio_get_block,
|
||||
NULL, NULL,
|
||||
unlocked ? 0 : DIO_LOCKING);
|
||||
}
|
||||
if (unlocked)
|
||||
inode_dio_end(inode);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -3455,10 +3553,10 @@ static ssize_t ext4_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
|
|||
return 0;
|
||||
|
||||
trace_ext4_direct_IO_enter(inode, offset, count, iov_iter_rw(iter));
|
||||
if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))
|
||||
ret = ext4_ext_direct_IO(iocb, iter);
|
||||
if (iov_iter_rw(iter) == READ)
|
||||
ret = ext4_direct_IO_read(iocb, iter);
|
||||
else
|
||||
ret = ext4_ind_direct_IO(iocb, iter);
|
||||
ret = ext4_direct_IO_write(iocb, iter);
|
||||
trace_ext4_direct_IO_exit(inode, offset, count, iov_iter_rw(iter), ret);
|
||||
return ret;
|
||||
}
|
||||
|
@ -3534,10 +3632,7 @@ void ext4_set_aops(struct inode *inode)
|
|||
{
|
||||
switch (ext4_inode_journal_mode(inode)) {
|
||||
case EXT4_INODE_ORDERED_DATA_MODE:
|
||||
ext4_set_inode_state(inode, EXT4_STATE_ORDERED_MODE);
|
||||
break;
|
||||
case EXT4_INODE_WRITEBACK_DATA_MODE:
|
||||
ext4_clear_inode_state(inode, EXT4_STATE_ORDERED_MODE);
|
||||
break;
|
||||
case EXT4_INODE_JOURNAL_DATA_MODE:
|
||||
inode->i_mapping->a_ops = &ext4_journalled_aops;
|
||||
|
@ -3630,8 +3725,8 @@ static int __ext4_block_zero_page_range(handle_t *handle,
|
|||
} else {
|
||||
err = 0;
|
||||
mark_buffer_dirty(bh);
|
||||
if (ext4_test_inode_state(inode, EXT4_STATE_ORDERED_MODE))
|
||||
err = ext4_jbd2_file_inode(handle, inode);
|
||||
if (ext4_should_order_data(inode))
|
||||
err = ext4_jbd2_inode_add_write(handle, inode);
|
||||
}
|
||||
|
||||
unlock:
|
||||
|
@ -5429,6 +5524,7 @@ int ext4_change_inode_journal_flag(struct inode *inode, int val)
|
|||
journal_t *journal;
|
||||
handle_t *handle;
|
||||
int err;
|
||||
struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
|
||||
|
||||
/*
|
||||
* We have to be very careful here: changing a data block's
|
||||
|
@ -5445,22 +5541,30 @@ int ext4_change_inode_journal_flag(struct inode *inode, int val)
|
|||
return 0;
|
||||
if (is_journal_aborted(journal))
|
||||
return -EROFS;
|
||||
/* We have to allocate physical blocks for delalloc blocks
|
||||
* before flushing journal. otherwise delalloc blocks can not
|
||||
* be allocated any more. even more truncate on delalloc blocks
|
||||
* could trigger BUG by flushing delalloc blocks in journal.
|
||||
* There is no delalloc block in non-journal data mode.
|
||||
*/
|
||||
if (val && test_opt(inode->i_sb, DELALLOC)) {
|
||||
err = ext4_alloc_da_blocks(inode);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Wait for all existing dio workers */
|
||||
ext4_inode_block_unlocked_dio(inode);
|
||||
inode_dio_wait(inode);
|
||||
|
||||
/*
|
||||
* Before flushing the journal and switching inode's aops, we have
|
||||
* to flush all dirty data the inode has. There can be outstanding
|
||||
* delayed allocations, there can be unwritten extents created by
|
||||
* fallocate or buffered writes in dioread_nolock mode covered by
|
||||
* dirty data which can be converted only after flushing the dirty
|
||||
* data (and journalled aops don't know how to handle these cases).
|
||||
*/
|
||||
if (val) {
|
||||
down_write(&EXT4_I(inode)->i_mmap_sem);
|
||||
err = filemap_write_and_wait(inode->i_mapping);
|
||||
if (err < 0) {
|
||||
up_write(&EXT4_I(inode)->i_mmap_sem);
|
||||
ext4_inode_resume_unlocked_dio(inode);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
percpu_down_write(&sbi->s_journal_flag_rwsem);
|
||||
jbd2_journal_lock_updates(journal);
|
||||
|
||||
/*
|
||||
|
@ -5477,6 +5581,7 @@ int ext4_change_inode_journal_flag(struct inode *inode, int val)
|
|||
err = jbd2_journal_flush(journal);
|
||||
if (err < 0) {
|
||||
jbd2_journal_unlock_updates(journal);
|
||||
percpu_up_write(&sbi->s_journal_flag_rwsem);
|
||||
ext4_inode_resume_unlocked_dio(inode);
|
||||
return err;
|
||||
}
|
||||
|
@ -5485,6 +5590,10 @@ int ext4_change_inode_journal_flag(struct inode *inode, int val)
|
|||
ext4_set_aops(inode);
|
||||
|
||||
jbd2_journal_unlock_updates(journal);
|
||||
percpu_up_write(&sbi->s_journal_flag_rwsem);
|
||||
|
||||
if (val)
|
||||
up_write(&EXT4_I(inode)->i_mmap_sem);
|
||||
ext4_inode_resume_unlocked_dio(inode);
|
||||
|
||||
/* Finally we can mark the inode as dirty. */
|
||||
|
|
|
@ -365,7 +365,7 @@ static int ext4_ioctl_setproject(struct file *filp, __u32 projid)
|
|||
struct dquot *transfer_to[MAXQUOTAS] = { };
|
||||
|
||||
transfer_to[PRJQUOTA] = dqget(sb, make_kqid_projid(kprojid));
|
||||
if (transfer_to[PRJQUOTA]) {
|
||||
if (!IS_ERR(transfer_to[PRJQUOTA])) {
|
||||
err = __dquot_transfer(inode, transfer_to);
|
||||
dqput(transfer_to[PRJQUOTA]);
|
||||
if (err)
|
||||
|
|
|
@ -1266,6 +1266,7 @@ static void ext4_mb_unload_buddy(struct ext4_buddy *e4b)
|
|||
static int mb_find_order_for_block(struct ext4_buddy *e4b, int block)
|
||||
{
|
||||
int order = 1;
|
||||
int bb_incr = 1 << (e4b->bd_blkbits - 1);
|
||||
void *bb;
|
||||
|
||||
BUG_ON(e4b->bd_bitmap == e4b->bd_buddy);
|
||||
|
@ -1278,7 +1279,8 @@ static int mb_find_order_for_block(struct ext4_buddy *e4b, int block)
|
|||
/* this block is part of buddy of order 'order' */
|
||||
return order;
|
||||
}
|
||||
bb += 1 << (e4b->bd_blkbits - order);
|
||||
bb += bb_incr;
|
||||
bb_incr >>= 1;
|
||||
order++;
|
||||
}
|
||||
return 0;
|
||||
|
@ -2583,7 +2585,7 @@ int ext4_mb_init(struct super_block *sb)
|
|||
{
|
||||
struct ext4_sb_info *sbi = EXT4_SB(sb);
|
||||
unsigned i, j;
|
||||
unsigned offset;
|
||||
unsigned offset, offset_incr;
|
||||
unsigned max;
|
||||
int ret;
|
||||
|
||||
|
@ -2612,11 +2614,13 @@ int ext4_mb_init(struct super_block *sb)
|
|||
|
||||
i = 1;
|
||||
offset = 0;
|
||||
offset_incr = 1 << (sb->s_blocksize_bits - 1);
|
||||
max = sb->s_blocksize << 2;
|
||||
do {
|
||||
sbi->s_mb_offsets[i] = offset;
|
||||
sbi->s_mb_maxs[i] = max;
|
||||
offset += 1 << (sb->s_blocksize_bits - i);
|
||||
offset += offset_incr;
|
||||
offset_incr = offset_incr >> 1;
|
||||
max = max >> 1;
|
||||
i++;
|
||||
} while (i <= sb->s_blocksize_bits + 1);
|
||||
|
@ -4935,7 +4939,7 @@ int ext4_group_add_blocks(handle_t *handle, struct super_block *sb,
|
|||
* boundary.
|
||||
*/
|
||||
if (bit + count > EXT4_BLOCKS_PER_GROUP(sb)) {
|
||||
ext4_warning(sb, "too much blocks added to group %u\n",
|
||||
ext4_warning(sb, "too much blocks added to group %u",
|
||||
block_group);
|
||||
err = -EINVAL;
|
||||
goto error_return;
|
||||
|
|
|
@ -121,7 +121,7 @@ void __dump_mmp_msg(struct super_block *sb, struct mmp_struct *mmp,
|
|||
__ext4_warning(sb, function, line, "%s", msg);
|
||||
__ext4_warning(sb, function, line,
|
||||
"MMP failure info: last update time: %llu, last update "
|
||||
"node: %s, last update device: %s\n",
|
||||
"node: %s, last update device: %s",
|
||||
(long long unsigned int) le64_to_cpu(mmp->mmp_time),
|
||||
mmp->mmp_nodename, mmp->mmp_bdevname);
|
||||
}
|
||||
|
@ -353,7 +353,7 @@ skip:
|
|||
* wait for MMP interval and check mmp_seq.
|
||||
*/
|
||||
if (schedule_timeout_interruptible(HZ * wait_time) != 0) {
|
||||
ext4_warning(sb, "MMP startup interrupted, failing mount\n");
|
||||
ext4_warning(sb, "MMP startup interrupted, failing mount");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
|
|
|
@ -400,7 +400,7 @@ data_copy:
|
|||
|
||||
/* Even in case of data=writeback it is reasonable to pin
|
||||
* inode to transaction, to prevent unexpected data loss */
|
||||
*err = ext4_jbd2_file_inode(handle, orig_inode);
|
||||
*err = ext4_jbd2_inode_add_write(handle, orig_inode);
|
||||
|
||||
unlock_pages:
|
||||
unlock_page(pagep[0]);
|
||||
|
|
|
@ -1107,6 +1107,11 @@ int ext4_htree_fill_tree(struct file *dir_file, __u32 start_hash,
|
|||
}
|
||||
|
||||
while (1) {
|
||||
if (fatal_signal_pending(current)) {
|
||||
err = -ERESTARTSYS;
|
||||
goto errout;
|
||||
}
|
||||
cond_resched();
|
||||
block = dx_get_block(frame->at);
|
||||
ret = htree_dirblock_to_tree(dir_file, dir, block, &hinfo,
|
||||
start_hash, start_minor_hash);
|
||||
|
@ -1613,7 +1618,7 @@ static struct dentry *ext4_lookup(struct inode *dir, struct dentry *dentry, unsi
|
|||
if (nokey)
|
||||
return ERR_PTR(-ENOKEY);
|
||||
ext4_warning(inode->i_sb,
|
||||
"Inconsistent encryption contexts: %lu/%lu\n",
|
||||
"Inconsistent encryption contexts: %lu/%lu",
|
||||
(unsigned long) dir->i_ino,
|
||||
(unsigned long) inode->i_ino);
|
||||
return ERR_PTR(-EPERM);
|
||||
|
@ -2828,7 +2833,7 @@ int ext4_orphan_add(handle_t *handle, struct inode *inode)
|
|||
* list entries can cause panics at unmount time.
|
||||
*/
|
||||
mutex_lock(&sbi->s_orphan_lock);
|
||||
list_del(&EXT4_I(inode)->i_orphan);
|
||||
list_del_init(&EXT4_I(inode)->i_orphan);
|
||||
mutex_unlock(&sbi->s_orphan_lock);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -342,9 +342,7 @@ void ext4_io_submit(struct ext4_io_submit *io)
|
|||
if (bio) {
|
||||
int io_op = io->io_wbc->sync_mode == WB_SYNC_ALL ?
|
||||
WRITE_SYNC : WRITE;
|
||||
bio_get(io->io_bio);
|
||||
submit_bio(io_op, io->io_bio);
|
||||
bio_put(io->io_bio);
|
||||
}
|
||||
io->io_bio = NULL;
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ int ext4_resize_begin(struct super_block *sb)
|
|||
*/
|
||||
if (EXT4_SB(sb)->s_mount_state & EXT4_ERROR_FS) {
|
||||
ext4_warning(sb, "There are errors in the filesystem, "
|
||||
"so online resizing is not allowed\n");
|
||||
"so online resizing is not allowed");
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
|
|
|
@ -859,6 +859,7 @@ static void ext4_put_super(struct super_block *sb)
|
|||
percpu_counter_destroy(&sbi->s_freeinodes_counter);
|
||||
percpu_counter_destroy(&sbi->s_dirs_counter);
|
||||
percpu_counter_destroy(&sbi->s_dirtyclusters_counter);
|
||||
percpu_free_rwsem(&sbi->s_journal_flag_rwsem);
|
||||
brelse(sbi->s_sbh);
|
||||
#ifdef CONFIG_QUOTA
|
||||
for (i = 0; i < EXT4_MAXQUOTAS; i++)
|
||||
|
@ -3930,6 +3931,9 @@ no_journal:
|
|||
if (!err)
|
||||
err = percpu_counter_init(&sbi->s_dirtyclusters_counter, 0,
|
||||
GFP_KERNEL);
|
||||
if (!err)
|
||||
err = percpu_init_rwsem(&sbi->s_journal_flag_rwsem);
|
||||
|
||||
if (err) {
|
||||
ext4_msg(sb, KERN_ERR, "insufficient memory");
|
||||
goto failed_mount6;
|
||||
|
|
|
@ -219,6 +219,8 @@ static int journal_submit_data_buffers(journal_t *journal,
|
|||
|
||||
spin_lock(&journal->j_list_lock);
|
||||
list_for_each_entry(jinode, &commit_transaction->t_inode_list, i_list) {
|
||||
if (!(jinode->i_flags & JI_WRITE_DATA))
|
||||
continue;
|
||||
mapping = jinode->i_vfs_inode->i_mapping;
|
||||
jinode->i_flags |= JI_COMMIT_RUNNING;
|
||||
spin_unlock(&journal->j_list_lock);
|
||||
|
@ -256,6 +258,8 @@ static int journal_finish_inode_data_buffers(journal_t *journal,
|
|||
/* For locking, see the comment in journal_submit_data_buffers() */
|
||||
spin_lock(&journal->j_list_lock);
|
||||
list_for_each_entry(jinode, &commit_transaction->t_inode_list, i_list) {
|
||||
if (!(jinode->i_flags & JI_WAIT_DATA))
|
||||
continue;
|
||||
jinode->i_flags |= JI_COMMIT_RUNNING;
|
||||
spin_unlock(&journal->j_list_lock);
|
||||
err = filemap_fdatawait(jinode->i_vfs_inode->i_mapping);
|
||||
|
|
|
@ -94,7 +94,8 @@ EXPORT_SYMBOL(jbd2_journal_blocks_per_page);
|
|||
EXPORT_SYMBOL(jbd2_journal_invalidatepage);
|
||||
EXPORT_SYMBOL(jbd2_journal_try_to_free_buffers);
|
||||
EXPORT_SYMBOL(jbd2_journal_force_commit);
|
||||
EXPORT_SYMBOL(jbd2_journal_file_inode);
|
||||
EXPORT_SYMBOL(jbd2_journal_inode_add_write);
|
||||
EXPORT_SYMBOL(jbd2_journal_inode_add_wait);
|
||||
EXPORT_SYMBOL(jbd2_journal_init_jbd_inode);
|
||||
EXPORT_SYMBOL(jbd2_journal_release_jbd_inode);
|
||||
EXPORT_SYMBOL(jbd2_journal_begin_ordered_truncate);
|
||||
|
|
|
@ -2462,7 +2462,8 @@ void jbd2_journal_refile_buffer(journal_t *journal, struct journal_head *jh)
|
|||
/*
|
||||
* File inode in the inode list of the handle's transaction
|
||||
*/
|
||||
int jbd2_journal_file_inode(handle_t *handle, struct jbd2_inode *jinode)
|
||||
static int jbd2_journal_file_inode(handle_t *handle, struct jbd2_inode *jinode,
|
||||
unsigned long flags)
|
||||
{
|
||||
transaction_t *transaction = handle->h_transaction;
|
||||
journal_t *journal;
|
||||
|
@ -2487,12 +2488,14 @@ int jbd2_journal_file_inode(handle_t *handle, struct jbd2_inode *jinode)
|
|||
* and if jinode->i_next_transaction == transaction, commit code
|
||||
* will only file the inode where we want it.
|
||||
*/
|
||||
if (jinode->i_transaction == transaction ||
|
||||
jinode->i_next_transaction == transaction)
|
||||
if ((jinode->i_transaction == transaction ||
|
||||
jinode->i_next_transaction == transaction) &&
|
||||
(jinode->i_flags & flags) == flags)
|
||||
return 0;
|
||||
|
||||
spin_lock(&journal->j_list_lock);
|
||||
|
||||
jinode->i_flags |= flags;
|
||||
/* Is inode already attached where we need it? */
|
||||
if (jinode->i_transaction == transaction ||
|
||||
jinode->i_next_transaction == transaction)
|
||||
goto done;
|
||||
|
@ -2523,6 +2526,17 @@ done:
|
|||
return 0;
|
||||
}
|
||||
|
||||
int jbd2_journal_inode_add_write(handle_t *handle, struct jbd2_inode *jinode)
|
||||
{
|
||||
return jbd2_journal_file_inode(handle, jinode,
|
||||
JI_WRITE_DATA | JI_WAIT_DATA);
|
||||
}
|
||||
|
||||
int jbd2_journal_inode_add_wait(handle_t *handle, struct jbd2_inode *jinode)
|
||||
{
|
||||
return jbd2_journal_file_inode(handle, jinode, JI_WAIT_DATA);
|
||||
}
|
||||
|
||||
/*
|
||||
* File truncate and transaction commit interact with each other in a
|
||||
* non-trivial way. If a transaction writing data block A is
|
||||
|
|
|
@ -619,7 +619,7 @@ static inline int ocfs2_calc_tree_trunc_credits(struct super_block *sb,
|
|||
|
||||
static inline int ocfs2_jbd2_file_inode(handle_t *handle, struct inode *inode)
|
||||
{
|
||||
return jbd2_journal_file_inode(handle, &OCFS2_I(inode)->ip_jinode);
|
||||
return jbd2_journal_inode_add_write(handle, &OCFS2_I(inode)->ip_jinode);
|
||||
}
|
||||
|
||||
static inline int ocfs2_begin_ordered_truncate(struct inode *inode,
|
||||
|
|
|
@ -182,6 +182,8 @@ static int filldir(struct dir_context *ctx, const char *name, int namlen,
|
|||
}
|
||||
dirent = buf->previous;
|
||||
if (dirent) {
|
||||
if (signal_pending(current))
|
||||
return -EINTR;
|
||||
if (__put_user(offset, &dirent->d_off))
|
||||
goto efault;
|
||||
}
|
||||
|
@ -261,6 +263,8 @@ static int filldir64(struct dir_context *ctx, const char *name, int namlen,
|
|||
return -EINVAL;
|
||||
dirent = buf->previous;
|
||||
if (dirent) {
|
||||
if (signal_pending(current))
|
||||
return -EINTR;
|
||||
if (__put_user(offset, &dirent->d_off))
|
||||
goto efault;
|
||||
}
|
||||
|
|
|
@ -403,11 +403,19 @@ static inline void jbd_unlock_bh_journal_head(struct buffer_head *bh)
|
|||
|
||||
/* Flags in jbd_inode->i_flags */
|
||||
#define __JI_COMMIT_RUNNING 0
|
||||
/* Commit of the inode data in progress. We use this flag to protect us from
|
||||
#define __JI_WRITE_DATA 1
|
||||
#define __JI_WAIT_DATA 2
|
||||
|
||||
/*
|
||||
* Commit of the inode data in progress. We use this flag to protect us from
|
||||
* concurrent deletion of inode. We cannot use reference to inode for this
|
||||
* since we cannot afford doing last iput() on behalf of kjournald
|
||||
*/
|
||||
#define JI_COMMIT_RUNNING (1 << __JI_COMMIT_RUNNING)
|
||||
/* Write allocated dirty buffers in this inode before commit */
|
||||
#define JI_WRITE_DATA (1 << __JI_WRITE_DATA)
|
||||
/* Wait for outstanding data writes for this inode before commit */
|
||||
#define JI_WAIT_DATA (1 << __JI_WAIT_DATA)
|
||||
|
||||
/**
|
||||
* struct jbd_inode is the structure linking inodes in ordered mode
|
||||
|
@ -781,9 +789,6 @@ jbd2_time_diff(unsigned long start, unsigned long end)
|
|||
* @j_wbufsize: maximum number of buffer_heads allowed in j_wbuf, the
|
||||
* number that will fit in j_blocksize
|
||||
* @j_last_sync_writer: most recent pid which did a synchronous write
|
||||
* @j_history: Buffer storing the transactions statistics history
|
||||
* @j_history_max: Maximum number of transactions in the statistics history
|
||||
* @j_history_cur: Current number of transactions in the statistics history
|
||||
* @j_history_lock: Protect the transactions statistics history
|
||||
* @j_proc_entry: procfs entry for the jbd statistics directory
|
||||
* @j_stats: Overall statistics
|
||||
|
@ -1270,7 +1275,8 @@ extern int jbd2_journal_clear_err (journal_t *);
|
|||
extern int jbd2_journal_bmap(journal_t *, unsigned long, unsigned long long *);
|
||||
extern int jbd2_journal_force_commit(journal_t *);
|
||||
extern int jbd2_journal_force_commit_nested(journal_t *);
|
||||
extern int jbd2_journal_file_inode(handle_t *handle, struct jbd2_inode *inode);
|
||||
extern int jbd2_journal_inode_add_write(handle_t *handle, struct jbd2_inode *inode);
|
||||
extern int jbd2_journal_inode_add_wait(handle_t *handle, struct jbd2_inode *inode);
|
||||
extern int jbd2_journal_begin_ordered_truncate(journal_t *journal,
|
||||
struct jbd2_inode *inode, loff_t new_size);
|
||||
extern void jbd2_journal_init_jbd_inode(struct jbd2_inode *jinode, struct inode *inode);
|
||||
|
|
|
@ -37,6 +37,7 @@ void percpu_free_rwsem(struct percpu_rw_semaphore *brw)
|
|||
free_percpu(brw->fast_read_ctr);
|
||||
brw->fast_read_ctr = NULL; /* catch use after free bugs */
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(percpu_free_rwsem);
|
||||
|
||||
/*
|
||||
* This is the fast-path for down_read/up_read. If it succeeds we rely
|
||||
|
|
Загрузка…
Ссылка в новой задаче