Skip to content

Commit a361293

Browse files
jankaratytso
authored andcommitted
jbd2: Fix oops in jbd2_journal_file_inode()
Commit 0713ed0 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 <[email protected]> Signed-off-by: Jan Kara <[email protected]> Signed-off-by: "Theodore Ts'o" <[email protected]>
1 parent 91aa11f commit a361293

File tree

3 files changed

+48
-17
lines changed

3 files changed

+48
-17
lines changed

fs/ext4/ext4.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2086,6 +2086,7 @@ extern int ext4_sync_inode(handle_t *, struct inode *);
20862086
extern void ext4_dirty_inode(struct inode *, int);
20872087
extern int ext4_change_inode_journal_flag(struct inode *, int);
20882088
extern int ext4_get_inode_loc(struct inode *, struct ext4_iloc *);
2089+
extern int ext4_inode_attach_jinode(struct inode *inode);
20892090
extern int ext4_can_truncate(struct inode *inode);
20902091
extern void ext4_truncate(struct inode *);
20912092
extern int ext4_punch_hole(struct inode *inode, loff_t offset, loff_t length);

fs/ext4/file.c

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,6 @@ static int ext4_file_open(struct inode * inode, struct file * filp)
219219
{
220220
struct super_block *sb = inode->i_sb;
221221
struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
222-
struct ext4_inode_info *ei = EXT4_I(inode);
223222
struct vfsmount *mnt = filp->f_path.mnt;
224223
struct path path;
225224
char buf[64], *cp;
@@ -259,22 +258,10 @@ static int ext4_file_open(struct inode * inode, struct file * filp)
259258
* Set up the jbd2_inode if we are opening the inode for
260259
* writing and the journal is present
261260
*/
262-
if (sbi->s_journal && !ei->jinode && (filp->f_mode & FMODE_WRITE)) {
263-
struct jbd2_inode *jinode = jbd2_alloc_inode(GFP_KERNEL);
264-
265-
spin_lock(&inode->i_lock);
266-
if (!ei->jinode) {
267-
if (!jinode) {
268-
spin_unlock(&inode->i_lock);
269-
return -ENOMEM;
270-
}
271-
ei->jinode = jinode;
272-
jbd2_journal_init_jbd_inode(ei->jinode, inode);
273-
jinode = NULL;
274-
}
275-
spin_unlock(&inode->i_lock);
276-
if (unlikely(jinode != NULL))
277-
jbd2_free_inode(jinode);
261+
if (filp->f_mode & FMODE_WRITE) {
262+
int ret = ext4_inode_attach_jinode(inode);
263+
if (ret < 0)
264+
return ret;
278265
}
279266
return dquot_file_open(inode, filp);
280267
}

fs/ext4/inode.c

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3533,6 +3533,18 @@ int ext4_punch_hole(struct inode *inode, loff_t offset, loff_t length)
35333533
offset;
35343534
}
35353535

3536+
if (offset & (sb->s_blocksize - 1) ||
3537+
(offset + length) & (sb->s_blocksize - 1)) {
3538+
/*
3539+
* Attach jinode to inode for jbd2 if we do any zeroing of
3540+
* partial block
3541+
*/
3542+
ret = ext4_inode_attach_jinode(inode);
3543+
if (ret < 0)
3544+
goto out_mutex;
3545+
3546+
}
3547+
35363548
first_block_offset = round_up(offset, sb->s_blocksize);
35373549
last_block_offset = round_down((offset + length), sb->s_blocksize) - 1;
35383550

@@ -3601,6 +3613,31 @@ int ext4_punch_hole(struct inode *inode, loff_t offset, loff_t length)
36013613
return ret;
36023614
}
36033615

3616+
int ext4_inode_attach_jinode(struct inode *inode)
3617+
{
3618+
struct ext4_inode_info *ei = EXT4_I(inode);
3619+
struct jbd2_inode *jinode;
3620+
3621+
if (ei->jinode || !EXT4_SB(inode->i_sb)->s_journal)
3622+
return 0;
3623+
3624+
jinode = jbd2_alloc_inode(GFP_KERNEL);
3625+
spin_lock(&inode->i_lock);
3626+
if (!ei->jinode) {
3627+
if (!jinode) {
3628+
spin_unlock(&inode->i_lock);
3629+
return -ENOMEM;
3630+
}
3631+
ei->jinode = jinode;
3632+
jbd2_journal_init_jbd_inode(ei->jinode, inode);
3633+
jinode = NULL;
3634+
}
3635+
spin_unlock(&inode->i_lock);
3636+
if (unlikely(jinode != NULL))
3637+
jbd2_free_inode(jinode);
3638+
return 0;
3639+
}
3640+
36043641
/*
36053642
* ext4_truncate()
36063643
*
@@ -3661,6 +3698,12 @@ void ext4_truncate(struct inode *inode)
36613698
return;
36623699
}
36633700

3701+
/* If we zero-out tail of the page, we have to create jinode for jbd2 */
3702+
if (inode->i_size & (inode->i_sb->s_blocksize - 1)) {
3703+
if (ext4_inode_attach_jinode(inode) < 0)
3704+
return;
3705+
}
3706+
36643707
if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))
36653708
credits = ext4_writepage_trans_blocks(inode);
36663709
else

0 commit comments

Comments
 (0)