diff options
Diffstat (limited to 'fs/ext4/inode.c')
-rw-r--r-- | fs/ext4/inode.c | 143 |
1 files changed, 19 insertions, 124 deletions
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index aa8efa6572d6..feaa82fe629d 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c | |||
@@ -71,6 +71,9 @@ static int ext4_set_bh_endio(struct buffer_head *bh, struct inode *inode); | |||
71 | static void ext4_end_io_buffer_write(struct buffer_head *bh, int uptodate); | 71 | static void ext4_end_io_buffer_write(struct buffer_head *bh, int uptodate); |
72 | static int __ext4_journalled_writepage(struct page *page, unsigned int len); | 72 | static int __ext4_journalled_writepage(struct page *page, unsigned int len); |
73 | static int ext4_bh_delay_or_unwritten(handle_t *handle, struct buffer_head *bh); | 73 | static int ext4_bh_delay_or_unwritten(handle_t *handle, struct buffer_head *bh); |
74 | static int ext4_discard_partial_page_buffers_no_lock(handle_t *handle, | ||
75 | struct inode *inode, struct page *page, loff_t from, | ||
76 | loff_t length, int flags); | ||
74 | 77 | ||
75 | /* | 78 | /* |
76 | * Test whether an inode is a fast symlink. | 79 | * Test whether an inode is a fast symlink. |
@@ -2759,7 +2762,7 @@ static void ext4_end_io_dio(struct kiocb *iocb, loff_t offset, | |||
2759 | if (!io_end || !size) | 2762 | if (!io_end || !size) |
2760 | goto out; | 2763 | goto out; |
2761 | 2764 | ||
2762 | ext_debug("ext4_end_io_dio(): io_end 0x%p" | 2765 | ext_debug("ext4_end_io_dio(): io_end 0x%p " |
2763 | "for inode %lu, iocb 0x%p, offset %llu, size %llu\n", | 2766 | "for inode %lu, iocb 0x%p, offset %llu, size %llu\n", |
2764 | iocb->private, io_end->inode->i_ino, iocb, offset, | 2767 | iocb->private, io_end->inode->i_ino, iocb, offset, |
2765 | size); | 2768 | size); |
@@ -3160,7 +3163,7 @@ int ext4_discard_partial_page_buffers(handle_t *handle, | |||
3160 | * | 3163 | * |
3161 | * Returns zero on sucess or negative on failure. | 3164 | * Returns zero on sucess or negative on failure. |
3162 | */ | 3165 | */ |
3163 | int ext4_discard_partial_page_buffers_no_lock(handle_t *handle, | 3166 | static int ext4_discard_partial_page_buffers_no_lock(handle_t *handle, |
3164 | struct inode *inode, struct page *page, loff_t from, | 3167 | struct inode *inode, struct page *page, loff_t from, |
3165 | loff_t length, int flags) | 3168 | loff_t length, int flags) |
3166 | { | 3169 | { |
@@ -3300,126 +3303,6 @@ next: | |||
3300 | return err; | 3303 | return err; |
3301 | } | 3304 | } |
3302 | 3305 | ||
3303 | /* | ||
3304 | * ext4_block_truncate_page() zeroes out a mapping from file offset `from' | ||
3305 | * up to the end of the block which corresponds to `from'. | ||
3306 | * This required during truncate. We need to physically zero the tail end | ||
3307 | * of that block so it doesn't yield old data if the file is later grown. | ||
3308 | */ | ||
3309 | int ext4_block_truncate_page(handle_t *handle, | ||
3310 | struct address_space *mapping, loff_t from) | ||
3311 | { | ||
3312 | unsigned offset = from & (PAGE_CACHE_SIZE-1); | ||
3313 | unsigned length; | ||
3314 | unsigned blocksize; | ||
3315 | struct inode *inode = mapping->host; | ||
3316 | |||
3317 | blocksize = inode->i_sb->s_blocksize; | ||
3318 | length = blocksize - (offset & (blocksize - 1)); | ||
3319 | |||
3320 | return ext4_block_zero_page_range(handle, mapping, from, length); | ||
3321 | } | ||
3322 | |||
3323 | /* | ||
3324 | * ext4_block_zero_page_range() zeros out a mapping of length 'length' | ||
3325 | * starting from file offset 'from'. The range to be zero'd must | ||
3326 | * be contained with in one block. If the specified range exceeds | ||
3327 | * the end of the block it will be shortened to end of the block | ||
3328 | * that cooresponds to 'from' | ||
3329 | */ | ||
3330 | int ext4_block_zero_page_range(handle_t *handle, | ||
3331 | struct address_space *mapping, loff_t from, loff_t length) | ||
3332 | { | ||
3333 | ext4_fsblk_t index = from >> PAGE_CACHE_SHIFT; | ||
3334 | unsigned offset = from & (PAGE_CACHE_SIZE-1); | ||
3335 | unsigned blocksize, max, pos; | ||
3336 | ext4_lblk_t iblock; | ||
3337 | struct inode *inode = mapping->host; | ||
3338 | struct buffer_head *bh; | ||
3339 | struct page *page; | ||
3340 | int err = 0; | ||
3341 | |||
3342 | page = find_or_create_page(mapping, from >> PAGE_CACHE_SHIFT, | ||
3343 | mapping_gfp_mask(mapping) & ~__GFP_FS); | ||
3344 | if (!page) | ||
3345 | return -ENOMEM; | ||
3346 | |||
3347 | blocksize = inode->i_sb->s_blocksize; | ||
3348 | max = blocksize - (offset & (blocksize - 1)); | ||
3349 | |||
3350 | /* | ||
3351 | * correct length if it does not fall between | ||
3352 | * 'from' and the end of the block | ||
3353 | */ | ||
3354 | if (length > max || length < 0) | ||
3355 | length = max; | ||
3356 | |||
3357 | iblock = index << (PAGE_CACHE_SHIFT - inode->i_sb->s_blocksize_bits); | ||
3358 | |||
3359 | if (!page_has_buffers(page)) | ||
3360 | create_empty_buffers(page, blocksize, 0); | ||
3361 | |||
3362 | /* Find the buffer that contains "offset" */ | ||
3363 | bh = page_buffers(page); | ||
3364 | pos = blocksize; | ||
3365 | while (offset >= pos) { | ||
3366 | bh = bh->b_this_page; | ||
3367 | iblock++; | ||
3368 | pos += blocksize; | ||
3369 | } | ||
3370 | |||
3371 | err = 0; | ||
3372 | if (buffer_freed(bh)) { | ||
3373 | BUFFER_TRACE(bh, "freed: skip"); | ||
3374 | goto unlock; | ||
3375 | } | ||
3376 | |||
3377 | if (!buffer_mapped(bh)) { | ||
3378 | BUFFER_TRACE(bh, "unmapped"); | ||
3379 | ext4_get_block(inode, iblock, bh, 0); | ||
3380 | /* unmapped? It's a hole - nothing to do */ | ||
3381 | if (!buffer_mapped(bh)) { | ||
3382 | BUFFER_TRACE(bh, "still unmapped"); | ||
3383 | goto unlock; | ||
3384 | } | ||
3385 | } | ||
3386 | |||
3387 | /* Ok, it's mapped. Make sure it's up-to-date */ | ||
3388 | if (PageUptodate(page)) | ||
3389 | set_buffer_uptodate(bh); | ||
3390 | |||
3391 | if (!buffer_uptodate(bh)) { | ||
3392 | err = -EIO; | ||
3393 | ll_rw_block(READ, 1, &bh); | ||
3394 | wait_on_buffer(bh); | ||
3395 | /* Uhhuh. Read error. Complain and punt. */ | ||
3396 | if (!buffer_uptodate(bh)) | ||
3397 | goto unlock; | ||
3398 | } | ||
3399 | |||
3400 | if (ext4_should_journal_data(inode)) { | ||
3401 | BUFFER_TRACE(bh, "get write access"); | ||
3402 | err = ext4_journal_get_write_access(handle, bh); | ||
3403 | if (err) | ||
3404 | goto unlock; | ||
3405 | } | ||
3406 | |||
3407 | zero_user(page, offset, length); | ||
3408 | |||
3409 | BUFFER_TRACE(bh, "zeroed end of block"); | ||
3410 | |||
3411 | err = 0; | ||
3412 | if (ext4_should_journal_data(inode)) { | ||
3413 | err = ext4_handle_dirty_metadata(handle, inode, bh); | ||
3414 | } else | ||
3415 | mark_buffer_dirty(bh); | ||
3416 | |||
3417 | unlock: | ||
3418 | unlock_page(page); | ||
3419 | page_cache_release(page); | ||
3420 | return err; | ||
3421 | } | ||
3422 | |||
3423 | int ext4_can_truncate(struct inode *inode) | 3306 | int ext4_can_truncate(struct inode *inode) |
3424 | { | 3307 | { |
3425 | if (S_ISREG(inode->i_mode)) | 3308 | if (S_ISREG(inode->i_mode)) |
@@ -4646,9 +4529,19 @@ int ext4_change_inode_journal_flag(struct inode *inode, int val) | |||
4646 | return 0; | 4529 | return 0; |
4647 | if (is_journal_aborted(journal)) | 4530 | if (is_journal_aborted(journal)) |
4648 | return -EROFS; | 4531 | return -EROFS; |
4532 | /* We have to allocate physical blocks for delalloc blocks | ||
4533 | * before flushing journal. otherwise delalloc blocks can not | ||
4534 | * be allocated any more. even more truncate on delalloc blocks | ||
4535 | * could trigger BUG by flushing delalloc blocks in journal. | ||
4536 | * There is no delalloc block in non-journal data mode. | ||
4537 | */ | ||
4538 | if (val && test_opt(inode->i_sb, DELALLOC)) { | ||
4539 | err = ext4_alloc_da_blocks(inode); | ||
4540 | if (err < 0) | ||
4541 | return err; | ||
4542 | } | ||
4649 | 4543 | ||
4650 | jbd2_journal_lock_updates(journal); | 4544 | jbd2_journal_lock_updates(journal); |
4651 | jbd2_journal_flush(journal); | ||
4652 | 4545 | ||
4653 | /* | 4546 | /* |
4654 | * OK, there are no updates running now, and all cached data is | 4547 | * OK, there are no updates running now, and all cached data is |
@@ -4660,8 +4553,10 @@ int ext4_change_inode_journal_flag(struct inode *inode, int val) | |||
4660 | 4553 | ||
4661 | if (val) | 4554 | if (val) |
4662 | ext4_set_inode_flag(inode, EXT4_INODE_JOURNAL_DATA); | 4555 | ext4_set_inode_flag(inode, EXT4_INODE_JOURNAL_DATA); |
4663 | else | 4556 | else { |
4557 | jbd2_journal_flush(journal); | ||
4664 | ext4_clear_inode_flag(inode, EXT4_INODE_JOURNAL_DATA); | 4558 | ext4_clear_inode_flag(inode, EXT4_INODE_JOURNAL_DATA); |
4559 | } | ||
4665 | ext4_set_aops(inode); | 4560 | ext4_set_aops(inode); |
4666 | 4561 | ||
4667 | jbd2_journal_unlock_updates(journal); | 4562 | jbd2_journal_unlock_updates(journal); |