Commit 0e8b6879 authored by Lukas Czerner's avatar Lukas Czerner Committed by Theodore Ts'o

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: default avatarLukas Czerner <lczerner@redhat.com>
Signed-off-by: default avatar"Theodore Ts'o" <tytso@mit.edu>
parent f282ac19
...@@ -4546,6 +4546,64 @@ void ext4_ext_truncate(handle_t *handle, struct inode *inode) ...@@ -4546,6 +4546,64 @@ void ext4_ext_truncate(handle_t *handle, struct inode *inode)
ext4_std_error(inode->i_sb, err); ext4_std_error(inode->i_sb, err);
} }
static int ext4_alloc_file_blocks(struct file *file, ext4_lblk_t offset,
ext4_lblk_t len, int flags, int mode)
{
struct inode *inode = file_inode(file);
handle_t *handle;
int ret = 0;
int ret2 = 0;
int retries = 0;
struct ext4_map_blocks map;
unsigned int credits;
map.m_lblk = offset;
/*
* Don't normalize the request if it can fit in one extent so
* that it doesn't get unnecessarily split into multiple
* extents.
*/
if (len <= EXT_UNINIT_MAX_LEN)
flags |= EXT4_GET_BLOCKS_NO_NORMALIZE;
/*
* credits to insert 1 extent into extent tree
*/
credits = ext4_chunk_trans_blocks(inode, len);
retry:
while (ret >= 0 && ret < len) {
map.m_lblk = map.m_lblk + ret;
map.m_len = len = len - ret;
handle = ext4_journal_start(inode, EXT4_HT_MAP_BLOCKS,
credits);
if (IS_ERR(handle)) {
ret = PTR_ERR(handle);
break;
}
ret = ext4_map_blocks(handle, inode, &map, flags);
if (ret <= 0) {
ext4_debug("inode #%lu: block %u: len %u: "
"ext4_ext_map_blocks returned %d",
inode->i_ino, map.m_lblk,
map.m_len, ret);
ext4_mark_inode_dirty(handle, inode);
ret2 = ext4_journal_stop(handle);
break;
}
ret2 = ext4_journal_stop(handle);
if (ret2)
break;
}
if (ret == -ENOSPC &&
ext4_should_retry_alloc(inode->i_sb, &retries)) {
ret = 0;
goto retry;
}
return ret > 0 ? ret2 : ret;
}
/* /*
* preallocate space for a file. This implements ext4's fallocate file * preallocate space for a file. This implements ext4's fallocate file
* operation, which gets called from sys_fallocate system call. * 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,12 +4618,10 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
loff_t new_size = 0; loff_t new_size = 0;
unsigned int max_blocks; unsigned int max_blocks;
int ret = 0; int ret = 0;
int ret2 = 0;
int retries = 0;
int flags; int flags;
struct ext4_map_blocks map; ext4_lblk_t lblk;
struct timespec tv; struct timespec tv;
unsigned int credits, blkbits = inode->i_blkbits; unsigned int blkbits = inode->i_blkbits;
/* Return error if mode is not supported */ /* Return error if mode is not supported */
if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE | 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,17 +4646,18 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
return -EOPNOTSUPP; return -EOPNOTSUPP;
trace_ext4_fallocate_enter(inode, offset, len, mode); trace_ext4_fallocate_enter(inode, offset, len, mode);
map.m_lblk = offset >> blkbits; lblk = offset >> blkbits;
/* /*
* We can't just convert len to max_blocks because * We can't just convert len to max_blocks because
* If blocksize = 4096 offset = 3072 and len = 2048 * If blocksize = 4096 offset = 3072 and len = 2048
*/ */
max_blocks = (EXT4_BLOCK_ALIGN(len + offset, blkbits) >> blkbits) max_blocks = (EXT4_BLOCK_ALIGN(len + offset, blkbits) >> blkbits)
- map.m_lblk; - lblk;
/*
* credits to insert 1 extent into extent tree flags = EXT4_GET_BLOCKS_CREATE_UNINIT_EXT;
*/ if (mode & FALLOC_FL_KEEP_SIZE)
credits = ext4_chunk_trans_blocks(inode, max_blocks); flags |= EXT4_GET_BLOCKS_KEEP_SIZE;
mutex_lock(&inode->i_mutex); mutex_lock(&inode->i_mutex);
if (!(mode & FALLOC_FL_KEEP_SIZE) && 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,46 +4668,9 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
goto out; goto out;
} }
flags = EXT4_GET_BLOCKS_CREATE_UNINIT_EXT; ret = ext4_alloc_file_blocks(file, lblk, max_blocks, flags, mode);
if (mode & FALLOC_FL_KEEP_SIZE) if (ret)
flags |= EXT4_GET_BLOCKS_KEEP_SIZE; goto out;
/*
* Don't normalize the request if it can fit in one extent so
* that it doesn't get unnecessarily split into multiple
* extents.
*/
if (len <= EXT_UNINIT_MAX_LEN << blkbits)
flags |= EXT4_GET_BLOCKS_NO_NORMALIZE;
retry:
while (ret >= 0 && ret < max_blocks) {
map.m_lblk = map.m_lblk + ret;
map.m_len = max_blocks = max_blocks - ret;
handle = ext4_journal_start(inode, EXT4_HT_MAP_BLOCKS,
credits);
if (IS_ERR(handle)) {
ret = PTR_ERR(handle);
break;
}
ret = ext4_map_blocks(handle, inode, &map, flags);
if (ret <= 0) {
ext4_debug("inode #%lu: block %u: len %u: "
"ext4_ext_map_blocks returned %d",
inode->i_ino, map.m_lblk,
map.m_len, ret);
ext4_mark_inode_dirty(handle, inode);
ret2 = ext4_journal_stop(handle);
break;
}
ret2 = ext4_journal_stop(handle);
if (ret2)
break;
}
if (ret == -ENOSPC &&
ext4_should_retry_alloc(inode->i_sb, &retries)) {
ret = 0;
goto retry;
}
handle = ext4_journal_start(inode, EXT4_HT_INODE, 2); handle = ext4_journal_start(inode, EXT4_HT_INODE, 2);
if (IS_ERR(handle)) if (IS_ERR(handle))
...@@ -4658,14 +4678,14 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len) ...@@ -4658,14 +4678,14 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
tv = inode->i_ctime = ext4_current_time(inode); tv = inode->i_ctime = ext4_current_time(inode);
if (ret > 0 && new_size) { if (!ret && new_size) {
if (new_size > i_size_read(inode)) { if (new_size > i_size_read(inode)) {
i_size_write(inode, new_size); i_size_write(inode, new_size);
inode->i_mtime = tv; inode->i_mtime = tv;
} }
if (new_size > EXT4_I(inode)->i_disksize) if (new_size > EXT4_I(inode)->i_disksize)
ext4_update_i_disksize(inode, new_size); ext4_update_i_disksize(inode, new_size);
} else if (ret > 0 && !new_size) { } else if (!ret && !new_size) {
/* /*
* Mark that we allocate beyond EOF so the subsequent truncate * Mark that we allocate beyond EOF so the subsequent truncate
* can proceed even if the new size is the same as i_size. * can proceed even if the new size is the same as i_size.
...@@ -4680,9 +4700,8 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len) ...@@ -4680,9 +4700,8 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
ext4_journal_stop(handle); ext4_journal_stop(handle);
out: out:
mutex_unlock(&inode->i_mutex); mutex_unlock(&inode->i_mutex);
trace_ext4_fallocate_exit(inode, offset, max_blocks, trace_ext4_fallocate_exit(inode, offset, max_blocks, ret);
ret > 0 ? ret2 : ret); return ret;
return ret > 0 ? ret2 : ret;
} }
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment