mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-04-01 12:04:08 +00:00
jbd2: Fix oops in jbd2_journal_file_inode()
Commit 0713ed0cde
added
jbd2_journal_file_inode() call into ext4_block_zero_page_range().
However that function gets called from truncate path and thus inode
needn't have jinode attached - that happens in ext4_file_open() but
the file needn't be ever open since mount. Calling
jbd2_journal_file_inode() without jinode attached results in the oops.
We fix the problem by attaching jinode to inode also in ext4_truncate()
and ext4_punch_hole() when we are going to zero out partial blocks.
Reported-by: majianpeng <majianpeng@gmail.com>
Signed-off-by: Jan Kara <jack@suse.cz>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
This commit is contained in:
parent
91aa11fae1
commit
a361293f5f
3 changed files with 48 additions and 17 deletions
|
@ -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);
|
||||||
|
|
|
@ -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)
|
||||||
* 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)
|
||||||
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 @@ out_mutex:
|
||||||
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)
|
||||||
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
|
||||||
|
|
Loading…
Add table
Reference in a new issue