diff options
author | Lukas Czerner <lczerner@redhat.com> | 2014-03-18 18:03:51 -0400 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2014-03-18 18:03:51 -0400 |
commit | 0e8b6879f3c234036181526683be2b0231892ae4 (patch) | |
tree | 7fcff688fec8a0da538938830c5ea3cf8964f28f /fs/ext4 | |
parent | f282ac19d86f0507e91759dcf3d15fcb3a964d2a (diff) |
ext4: refactor ext4_fallocate code
Move block allocation out of the ext4_fallocate into separate function
called ext4_alloc_file_blocks(). This will allow us to use the same
allocation code for other allocation operations such as zero range which
is commit in the next patch.
Signed-off-by: Lukas Czerner <lczerner@redhat.com>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Diffstat (limited to 'fs/ext4')
-rw-r--r-- | fs/ext4/extents.c | 129 |
1 files changed, 74 insertions, 55 deletions
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index e4be6b79121d..2db2d77769a2 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c | |||
@@ -4546,6 +4546,64 @@ retry: | |||
4546 | ext4_std_error(inode->i_sb, err); | 4546 | ext4_std_error(inode->i_sb, err); |
4547 | } | 4547 | } |
4548 | 4548 | ||
4549 | static int ext4_alloc_file_blocks(struct file *file, ext4_lblk_t offset, | ||
4550 | ext4_lblk_t len, int flags, int mode) | ||
4551 | { | ||
4552 | struct inode *inode = file_inode(file); | ||
4553 | handle_t *handle; | ||
4554 | int ret = 0; | ||
4555 | int ret2 = 0; | ||
4556 | int retries = 0; | ||
4557 | struct ext4_map_blocks map; | ||
4558 | unsigned int credits; | ||
4559 | |||
4560 | map.m_lblk = offset; | ||
4561 | /* | ||
4562 | * Don't normalize the request if it can fit in one extent so | ||
4563 | * that it doesn't get unnecessarily split into multiple | ||
4564 | * extents. | ||
4565 | */ | ||
4566 | if (len <= EXT_UNINIT_MAX_LEN) | ||
4567 | flags |= EXT4_GET_BLOCKS_NO_NORMALIZE; | ||
4568 | |||
4569 | /* | ||
4570 | * credits to insert 1 extent into extent tree | ||
4571 | */ | ||
4572 | credits = ext4_chunk_trans_blocks(inode, len); | ||
4573 | |||
4574 | retry: | ||
4575 | while (ret >= 0 && ret < len) { | ||
4576 | map.m_lblk = map.m_lblk + ret; | ||
4577 | map.m_len = len = len - ret; | ||
4578 | handle = ext4_journal_start(inode, EXT4_HT_MAP_BLOCKS, | ||
4579 | credits); | ||
4580 | if (IS_ERR(handle)) { | ||
4581 | ret = PTR_ERR(handle); | ||
4582 | break; | ||
4583 | } | ||
4584 | ret = ext4_map_blocks(handle, inode, &map, flags); | ||
4585 | if (ret <= 0) { | ||
4586 | ext4_debug("inode #%lu: block %u: len %u: " | ||
4587 | "ext4_ext_map_blocks returned %d", | ||
4588 | inode->i_ino, map.m_lblk, | ||
4589 | map.m_len, ret); | ||
4590 | ext4_mark_inode_dirty(handle, inode); | ||
4591 | ret2 = ext4_journal_stop(handle); | ||
4592 | break; | ||
4593 | } | ||
4594 | ret2 = ext4_journal_stop(handle); | ||
4595 | if (ret2) | ||
4596 | break; | ||
4597 | } | ||
4598 | if (ret == -ENOSPC && | ||
4599 | ext4_should_retry_alloc(inode->i_sb, &retries)) { | ||
4600 | ret = 0; | ||
4601 | goto retry; | ||
4602 | } | ||
4603 | |||
4604 | return ret > 0 ? ret2 : ret; | ||
4605 | } | ||
4606 | |||
4549 | /* | 4607 | /* |
4550 | * preallocate space for a file. This implements ext4's fallocate file | 4608 | * preallocate space for a file. This implements ext4's fallocate file |
4551 | * operation, which gets called from sys_fallocate system call. | 4609 | * operation, which gets called from sys_fallocate system call. |
@@ -4560,12 +4618,10 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len) | |||
4560 | loff_t new_size = 0; | 4618 | loff_t new_size = 0; |
4561 | unsigned int max_blocks; | 4619 | unsigned int max_blocks; |
4562 | int ret = 0; | 4620 | int ret = 0; |
4563 | int ret2 = 0; | ||
4564 | int retries = 0; | ||
4565 | int flags; | 4621 | int flags; |
4566 | struct ext4_map_blocks map; | 4622 | ext4_lblk_t lblk; |
4567 | struct timespec tv; | 4623 | struct timespec tv; |
4568 | unsigned int credits, blkbits = inode->i_blkbits; | 4624 | unsigned int blkbits = inode->i_blkbits; |
4569 | 4625 | ||
4570 | /* Return error if mode is not supported */ | 4626 | /* Return error if mode is not supported */ |
4571 | if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE | | 4627 | if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE | |
@@ -4590,17 +4646,18 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len) | |||
4590 | return -EOPNOTSUPP; | 4646 | return -EOPNOTSUPP; |
4591 | 4647 | ||
4592 | trace_ext4_fallocate_enter(inode, offset, len, mode); | 4648 | trace_ext4_fallocate_enter(inode, offset, len, mode); |
4593 | map.m_lblk = offset >> blkbits; | 4649 | lblk = offset >> blkbits; |
4594 | /* | 4650 | /* |
4595 | * We can't just convert len to max_blocks because | 4651 | * We can't just convert len to max_blocks because |
4596 | * If blocksize = 4096 offset = 3072 and len = 2048 | 4652 | * If blocksize = 4096 offset = 3072 and len = 2048 |
4597 | */ | 4653 | */ |
4598 | max_blocks = (EXT4_BLOCK_ALIGN(len + offset, blkbits) >> blkbits) | 4654 | max_blocks = (EXT4_BLOCK_ALIGN(len + offset, blkbits) >> blkbits) |
4599 | - map.m_lblk; | 4655 | - lblk; |
4600 | /* | 4656 | |
4601 | * credits to insert 1 extent into extent tree | 4657 | flags = EXT4_GET_BLOCKS_CREATE_UNINIT_EXT; |
4602 | */ | 4658 | if (mode & FALLOC_FL_KEEP_SIZE) |
4603 | credits = ext4_chunk_trans_blocks(inode, max_blocks); | 4659 | flags |= EXT4_GET_BLOCKS_KEEP_SIZE; |
4660 | |||
4604 | mutex_lock(&inode->i_mutex); | 4661 | mutex_lock(&inode->i_mutex); |
4605 | 4662 | ||
4606 | if (!(mode & FALLOC_FL_KEEP_SIZE) && | 4663 | if (!(mode & FALLOC_FL_KEEP_SIZE) && |
@@ -4611,46 +4668,9 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len) | |||
4611 | goto out; | 4668 | goto out; |
4612 | } | 4669 | } |
4613 | 4670 | ||
4614 | flags = EXT4_GET_BLOCKS_CREATE_UNINIT_EXT; | 4671 | ret = ext4_alloc_file_blocks(file, lblk, max_blocks, flags, mode); |
4615 | if (mode & FALLOC_FL_KEEP_SIZE) | 4672 | if (ret) |
4616 | flags |= EXT4_GET_BLOCKS_KEEP_SIZE; | 4673 | goto out; |
4617 | /* | ||
4618 | * Don't normalize the request if it can fit in one extent so | ||
4619 | * that it doesn't get unnecessarily split into multiple | ||
4620 | * extents. | ||
4621 | */ | ||
4622 | if (len <= EXT_UNINIT_MAX_LEN << blkbits) | ||
4623 | flags |= EXT4_GET_BLOCKS_NO_NORMALIZE; | ||
4624 | |||
4625 | retry: | ||
4626 | while (ret >= 0 && ret < max_blocks) { | ||
4627 | map.m_lblk = map.m_lblk + ret; | ||
4628 | map.m_len = max_blocks = max_blocks - ret; | ||
4629 | handle = ext4_journal_start(inode, EXT4_HT_MAP_BLOCKS, | ||
4630 | credits); | ||
4631 | if (IS_ERR(handle)) { | ||
4632 | ret = PTR_ERR(handle); | ||
4633 | break; | ||
4634 | } | ||
4635 | ret = ext4_map_blocks(handle, inode, &map, flags); | ||
4636 | if (ret <= 0) { | ||
4637 | ext4_debug("inode #%lu: block %u: len %u: " | ||
4638 | "ext4_ext_map_blocks returned %d", | ||
4639 | inode->i_ino, map.m_lblk, | ||
4640 | map.m_len, ret); | ||
4641 | ext4_mark_inode_dirty(handle, inode); | ||
4642 | ret2 = ext4_journal_stop(handle); | ||
4643 | break; | ||
4644 | } | ||
4645 | ret2 = ext4_journal_stop(handle); | ||
4646 | if (ret2) | ||
4647 | break; | ||
4648 | } | ||
4649 | if (ret == -ENOSPC && | ||
4650 | ext4_should_retry_alloc(inode->i_sb, &retries)) { | ||
4651 | ret = 0; | ||
4652 | goto retry; | ||
4653 | } | ||
4654 | 4674 | ||
4655 | handle = ext4_journal_start(inode, EXT4_HT_INODE, 2); | 4675 | handle = ext4_journal_start(inode, EXT4_HT_INODE, 2); |
4656 | if (IS_ERR(handle)) | 4676 | if (IS_ERR(handle)) |
@@ -4658,14 +4678,14 @@ retry: | |||
4658 | 4678 | ||
4659 | tv = inode->i_ctime = ext4_current_time(inode); | 4679 | tv = inode->i_ctime = ext4_current_time(inode); |
4660 | 4680 | ||
4661 | if (ret > 0 && new_size) { | 4681 | if (!ret && new_size) { |
4662 | if (new_size > i_size_read(inode)) { | 4682 | if (new_size > i_size_read(inode)) { |
4663 | i_size_write(inode, new_size); | 4683 | i_size_write(inode, new_size); |
4664 | inode->i_mtime = tv; | 4684 | inode->i_mtime = tv; |
4665 | } | 4685 | } |
4666 | if (new_size > EXT4_I(inode)->i_disksize) | 4686 | if (new_size > EXT4_I(inode)->i_disksize) |
4667 | ext4_update_i_disksize(inode, new_size); | 4687 | ext4_update_i_disksize(inode, new_size); |
4668 | } else if (ret > 0 && !new_size) { | 4688 | } else if (!ret && !new_size) { |
4669 | /* | 4689 | /* |
4670 | * Mark that we allocate beyond EOF so the subsequent truncate | 4690 | * Mark that we allocate beyond EOF so the subsequent truncate |
4671 | * can proceed even if the new size is the same as i_size. | 4691 | * can proceed even if the new size is the same as i_size. |
@@ -4680,9 +4700,8 @@ retry: | |||
4680 | ext4_journal_stop(handle); | 4700 | ext4_journal_stop(handle); |
4681 | out: | 4701 | out: |
4682 | mutex_unlock(&inode->i_mutex); | 4702 | mutex_unlock(&inode->i_mutex); |
4683 | trace_ext4_fallocate_exit(inode, offset, max_blocks, | 4703 | trace_ext4_fallocate_exit(inode, offset, max_blocks, ret); |
4684 | ret > 0 ? ret2 : ret); | 4704 | return ret; |
4685 | return ret > 0 ? ret2 : ret; | ||
4686 | } | 4705 | } |
4687 | 4706 | ||
4688 | /* | 4707 | /* |