Commit a08797e8 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'ext4_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4

Pull jbd2 bug fixes from Ted Ts'o:
 "Two jbd2 bug fixes, one of which is a regression fix"

* tag 'ext4_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4:
  jbd2: Fix oops in jbd2_journal_file_inode()
  jbd2: Fix use after free after error in jbd2_journal_dirty_metadata()
parents 215b28a5 a361293f
...@@ -2086,6 +2086,7 @@ extern int ext4_sync_inode(handle_t *, struct inode *); ...@@ -2086,6 +2086,7 @@ extern int ext4_sync_inode(handle_t *, struct inode *);
extern void ext4_dirty_inode(struct inode *, int); extern void ext4_dirty_inode(struct inode *, int);
extern int ext4_change_inode_journal_flag(struct inode *, int); extern int ext4_change_inode_journal_flag(struct inode *, int);
extern int ext4_get_inode_loc(struct inode *, struct ext4_iloc *); extern int ext4_get_inode_loc(struct inode *, struct ext4_iloc *);
extern int ext4_inode_attach_jinode(struct inode *inode);
extern int ext4_can_truncate(struct inode *inode); extern int ext4_can_truncate(struct inode *inode);
extern void ext4_truncate(struct inode *); extern void ext4_truncate(struct inode *);
extern int ext4_punch_hole(struct inode *inode, loff_t offset, loff_t length); extern int ext4_punch_hole(struct inode *inode, loff_t offset, loff_t length);
......
...@@ -255,10 +255,10 @@ int __ext4_handle_dirty_metadata(const char *where, unsigned int line, ...@@ -255,10 +255,10 @@ int __ext4_handle_dirty_metadata(const char *where, unsigned int line,
set_buffer_prio(bh); set_buffer_prio(bh);
if (ext4_handle_valid(handle)) { if (ext4_handle_valid(handle)) {
err = jbd2_journal_dirty_metadata(handle, bh); err = jbd2_journal_dirty_metadata(handle, bh);
if (err) { /* Errors can only happen if there is a bug */
/* Errors can only happen if there is a bug */ if (WARN_ON_ONCE(err)) {
handle->h_err = err; ext4_journal_abort_handle(where, line, __func__, bh,
__ext4_journal_stop(where, line, handle); handle, err);
} }
} else { } else {
if (inode) if (inode)
......
...@@ -219,7 +219,6 @@ static int ext4_file_open(struct inode * inode, struct file * filp) ...@@ -219,7 +219,6 @@ static int ext4_file_open(struct inode * inode, struct file * filp)
{ {
struct super_block *sb = inode->i_sb; struct super_block *sb = inode->i_sb;
struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
struct ext4_inode_info *ei = EXT4_I(inode);
struct vfsmount *mnt = filp->f_path.mnt; struct vfsmount *mnt = filp->f_path.mnt;
struct path path; struct path path;
char buf[64], *cp; char buf[64], *cp;
...@@ -259,22 +258,10 @@ static int ext4_file_open(struct inode * inode, struct file * filp) ...@@ -259,22 +258,10 @@ static int ext4_file_open(struct inode * inode, struct file * filp)
* Set up the jbd2_inode if we are opening the inode for * Set up the jbd2_inode if we are opening the inode for
* writing and the journal is present * writing and the journal is present
*/ */
if (sbi->s_journal && !ei->jinode && (filp->f_mode & FMODE_WRITE)) { if (filp->f_mode & FMODE_WRITE) {
struct jbd2_inode *jinode = jbd2_alloc_inode(GFP_KERNEL); int ret = ext4_inode_attach_jinode(inode);
if (ret < 0)
spin_lock(&inode->i_lock); return ret;
if (!ei->jinode) {
if (!jinode) {
spin_unlock(&inode->i_lock);
return -ENOMEM;
}
ei->jinode = jinode;
jbd2_journal_init_jbd_inode(ei->jinode, inode);
jinode = NULL;
}
spin_unlock(&inode->i_lock);
if (unlikely(jinode != NULL))
jbd2_free_inode(jinode);
} }
return dquot_file_open(inode, filp); return dquot_file_open(inode, filp);
} }
......
...@@ -3533,6 +3533,18 @@ int ext4_punch_hole(struct inode *inode, loff_t offset, loff_t length) ...@@ -3533,6 +3533,18 @@ int ext4_punch_hole(struct inode *inode, loff_t offset, loff_t length)
offset; offset;
} }
if (offset & (sb->s_blocksize - 1) ||
(offset + length) & (sb->s_blocksize - 1)) {
/*
* Attach jinode to inode for jbd2 if we do any zeroing of
* partial block
*/
ret = ext4_inode_attach_jinode(inode);
if (ret < 0)
goto out_mutex;
}
first_block_offset = round_up(offset, sb->s_blocksize); first_block_offset = round_up(offset, sb->s_blocksize);
last_block_offset = round_down((offset + length), sb->s_blocksize) - 1; last_block_offset = round_down((offset + length), sb->s_blocksize) - 1;
...@@ -3601,6 +3613,31 @@ int ext4_punch_hole(struct inode *inode, loff_t offset, loff_t length) ...@@ -3601,6 +3613,31 @@ int ext4_punch_hole(struct inode *inode, loff_t offset, loff_t length)
return ret; return ret;
} }
int ext4_inode_attach_jinode(struct inode *inode)
{
struct ext4_inode_info *ei = EXT4_I(inode);
struct jbd2_inode *jinode;
if (ei->jinode || !EXT4_SB(inode->i_sb)->s_journal)
return 0;
jinode = jbd2_alloc_inode(GFP_KERNEL);
spin_lock(&inode->i_lock);
if (!ei->jinode) {
if (!jinode) {
spin_unlock(&inode->i_lock);
return -ENOMEM;
}
ei->jinode = jinode;
jbd2_journal_init_jbd_inode(ei->jinode, inode);
jinode = NULL;
}
spin_unlock(&inode->i_lock);
if (unlikely(jinode != NULL))
jbd2_free_inode(jinode);
return 0;
}
/* /*
* ext4_truncate() * ext4_truncate()
* *
...@@ -3661,6 +3698,12 @@ void ext4_truncate(struct inode *inode) ...@@ -3661,6 +3698,12 @@ void ext4_truncate(struct inode *inode)
return; return;
} }
/* If we zero-out tail of the page, we have to create jinode for jbd2 */
if (inode->i_size & (inode->i_sb->s_blocksize - 1)) {
if (ext4_inode_attach_jinode(inode) < 0)
return;
}
if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))
credits = ext4_writepage_trans_blocks(inode); credits = ext4_writepage_trans_blocks(inode);
else else
......
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