diff options
Diffstat (limited to 'fs/ext4/inode.c')
-rw-r--r-- | fs/ext4/inode.c | 46 |
1 files changed, 46 insertions, 0 deletions
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index ba0de19fb1ad..60432498acfb 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c | |||
@@ -4191,6 +4191,39 @@ int ext4_update_disksize_before_punch(struct inode *inode, loff_t offset, | |||
4191 | return 0; | 4191 | return 0; |
4192 | } | 4192 | } |
4193 | 4193 | ||
4194 | static void ext4_wait_dax_page(struct ext4_inode_info *ei, bool *did_unlock) | ||
4195 | { | ||
4196 | *did_unlock = true; | ||
4197 | up_write(&ei->i_mmap_sem); | ||
4198 | schedule(); | ||
4199 | down_write(&ei->i_mmap_sem); | ||
4200 | } | ||
4201 | |||
4202 | int ext4_break_layouts(struct inode *inode) | ||
4203 | { | ||
4204 | struct ext4_inode_info *ei = EXT4_I(inode); | ||
4205 | struct page *page; | ||
4206 | bool retry; | ||
4207 | int error; | ||
4208 | |||
4209 | if (WARN_ON_ONCE(!rwsem_is_locked(&ei->i_mmap_sem))) | ||
4210 | return -EINVAL; | ||
4211 | |||
4212 | do { | ||
4213 | retry = false; | ||
4214 | page = dax_layout_busy_page(inode->i_mapping); | ||
4215 | if (!page) | ||
4216 | return 0; | ||
4217 | |||
4218 | error = ___wait_var_event(&page->_refcount, | ||
4219 | atomic_read(&page->_refcount) == 1, | ||
4220 | TASK_INTERRUPTIBLE, 0, 0, | ||
4221 | ext4_wait_dax_page(ei, &retry)); | ||
4222 | } while (error == 0 && retry); | ||
4223 | |||
4224 | return error; | ||
4225 | } | ||
4226 | |||
4194 | /* | 4227 | /* |
4195 | * ext4_punch_hole: punches a hole in a file by releasing the blocks | 4228 | * ext4_punch_hole: punches a hole in a file by releasing the blocks |
4196 | * associated with the given offset and length | 4229 | * associated with the given offset and length |
@@ -4264,6 +4297,11 @@ int ext4_punch_hole(struct inode *inode, loff_t offset, loff_t length) | |||
4264 | * page cache. | 4297 | * page cache. |
4265 | */ | 4298 | */ |
4266 | down_write(&EXT4_I(inode)->i_mmap_sem); | 4299 | down_write(&EXT4_I(inode)->i_mmap_sem); |
4300 | |||
4301 | ret = ext4_break_layouts(inode); | ||
4302 | if (ret) | ||
4303 | goto out_dio; | ||
4304 | |||
4267 | first_block_offset = round_up(offset, sb->s_blocksize); | 4305 | first_block_offset = round_up(offset, sb->s_blocksize); |
4268 | last_block_offset = round_down((offset + length), sb->s_blocksize) - 1; | 4306 | last_block_offset = round_down((offset + length), sb->s_blocksize) - 1; |
4269 | 4307 | ||
@@ -5553,6 +5591,14 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr) | |||
5553 | ext4_wait_for_tail_page_commit(inode); | 5591 | ext4_wait_for_tail_page_commit(inode); |
5554 | } | 5592 | } |
5555 | down_write(&EXT4_I(inode)->i_mmap_sem); | 5593 | down_write(&EXT4_I(inode)->i_mmap_sem); |
5594 | |||
5595 | rc = ext4_break_layouts(inode); | ||
5596 | if (rc) { | ||
5597 | up_write(&EXT4_I(inode)->i_mmap_sem); | ||
5598 | error = rc; | ||
5599 | goto err_out; | ||
5600 | } | ||
5601 | |||
5556 | /* | 5602 | /* |
5557 | * Truncate pagecache after we've waited for commit | 5603 | * Truncate pagecache after we've waited for commit |
5558 | * in data=journal mode to make pages freeable. | 5604 | * in data=journal mode to make pages freeable. |