diff options
Diffstat (limited to 'fs/ext4/inode.c')
| -rw-r--r-- | fs/ext4/inode.c | 77 |
1 files changed, 13 insertions, 64 deletions
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index e31d762eedce..06bda0361e7c 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -3587,35 +3587,6 @@ int ext4_can_truncate(struct inode *inode) } /* - * We have to make sure i_disksize gets properly updated before we truncate - * page cache due to hole punching or zero range. Otherwise i_disksize update - * can get lost as it may have been postponed to submission of writeback but - * that will never happen after we truncate page cache. - */ -int ext4_update_disksize_before_punch(struct inode *inode, loff_t offset, - loff_t len) -{ - handle_t *handle; - loff_t size = i_size_read(inode); - - WARN_ON(!mutex_is_locked(&inode->i_mutex)); - if (offset > size || offset + len < size) - return 0; - - if (EXT4_I(inode)->i_disksize >= size) - return 0; - - handle = ext4_journal_start(inode, EXT4_HT_MISC, 1); - if (IS_ERR(handle)) - return PTR_ERR(handle); - ext4_update_i_disksize(inode, size); - ext4_mark_inode_dirty(handle, inode); - ext4_journal_stop(handle); - - return 0; -} - -/* * ext4_punch_hole: punches a hole in a file by releaseing the blocks * associated with the given offset and length * @@ -3680,26 +3651,17 @@ int ext4_punch_hole(struct inode *inode, loff_t offset, loff_t length) } - /* Wait all existing dio workers, newcomers will block on i_mutex */ - ext4_inode_block_unlocked_dio(inode); - inode_dio_wait(inode); - - /* - * Prevent page faults from reinstantiating pages we have released from - * page cache. - */ - down_write(&EXT4_I(inode)->i_mmap_sem); first_block_offset = round_up(offset, sb->s_blocksize); last_block_offset = round_down((offset + length), sb->s_blocksize) - 1; /* Now release the pages and zero block aligned part of pages*/ - if (last_block_offset > first_block_offset) { - ret = ext4_update_disksize_before_punch(inode, offset, length); - if (ret) - goto out_dio; + if (last_block_offset > first_block_offset) truncate_pagecache_range(inode, first_block_offset, last_block_offset); - } + + /* Wait all existing dio workers, newcomers will block on i_mutex */ + ext4_inode_block_unlocked_dio(inode); + inode_dio_wait(inode); if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) credits = ext4_writepage_trans_blocks(inode); @@ -3746,12 +3708,16 @@ int ext4_punch_hole(struct inode *inode, loff_t offset, loff_t length) if (IS_SYNC(inode)) ext4_handle_sync(handle); + /* Now release the pages again to reduce race window */ + if (last_block_offset > first_block_offset) + truncate_pagecache_range(inode, first_block_offset, + last_block_offset); + inode->i_mtime = inode->i_ctime = ext4_current_time(inode); ext4_mark_inode_dirty(handle, inode); out_stop: ext4_journal_stop(handle); out_dio: - up_write(&EXT4_I(inode)->i_mmap_sem); ext4_inode_resume_unlocked_dio(inode); out_mutex: mutex_unlock(&inode->i_mutex); @@ -4885,7 +4851,6 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr) } else ext4_wait_for_tail_page_commit(inode); } - down_write(&EXT4_I(inode)->i_mmap_sem); /* * Truncate pagecache after we've waited for commit * in data=journal mode to make pages freeable. @@ -4893,7 +4858,6 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr) truncate_pagecache(inode, inode->i_size); if (shrink) ext4_truncate(inode); - up_write(&EXT4_I(inode)->i_mmap_sem); } if (!rc) { @@ -5145,8 +5109,6 @@ int ext4_mark_inode_dirty(handle_t *handle, struct inode *inode) might_sleep(); trace_ext4_mark_inode_dirty(inode, _RET_IP_); err = ext4_reserve_inode_write(handle, inode, &iloc); - if (err) - return err; if (ext4_handle_valid(handle) && EXT4_I(inode)->i_extra_isize < sbi->s_want_extra_isize && !ext4_test_inode_state(inode, EXT4_STATE_NO_EXPAND)) { @@ -5177,7 +5139,9 @@ int ext4_mark_inode_dirty(handle_t *handle, struct inode *inode) } } } - return ext4_mark_iloc_dirty(handle, inode, &iloc); + if (!err) + err = ext4_mark_iloc_dirty(handle, inode, &iloc); + return err; } /* @@ -5342,8 +5306,6 @@ int ext4_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) sb_start_pagefault(inode->i_sb); file_update_time(vma->vm_file); - - down_read(&EXT4_I(inode)->i_mmap_sem); /* Delalloc case is easy... */ if (test_opt(inode->i_sb, DELALLOC) && !ext4_should_journal_data(inode) && @@ -5413,19 +5375,6 @@ retry_alloc: out_ret: ret = block_page_mkwrite_return(ret); out: - up_read(&EXT4_I(inode)->i_mmap_sem); sb_end_pagefault(inode->i_sb); return ret; } - -int ext4_filemap_fault(struct vm_area_struct *vma, struct vm_fault *vmf) -{ - struct inode *inode = file_inode(vma->vm_file); - int err; - - down_read(&EXT4_I(inode)->i_mmap_sem); - err = filemap_fault(vma, vmf); - up_read(&EXT4_I(inode)->i_mmap_sem); - - return err; -} |
