2006-10-11 12:21:03 +04:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2003-2006, Cluster File Systems, Inc, info@clusterfs.com
|
|
|
|
* Written by Alex Tomas <alex@clusterfs.com>
|
|
|
|
*
|
|
|
|
* Architecture independence:
|
|
|
|
* Copyright (c) 2005, Bull S.A.
|
|
|
|
* Written by Pierre Peiffer <pierre.peiffer@bull.net>
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
|
|
* published by the Free Software Foundation.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
2016-03-10 07:49:05 +03:00
|
|
|
* You should have received a copy of the GNU General Public License
|
2006-10-11 12:21:03 +04:00
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Extents support for EXT4
|
|
|
|
*
|
|
|
|
* TODO:
|
|
|
|
* - ext4*_error() should be used in some situations
|
|
|
|
* - analyze all BUG()/BUG_ON(), use -EIO where appropriate
|
|
|
|
* - smart tree reduction
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <linux/fs.h>
|
|
|
|
#include <linux/time.h>
|
2007-10-17 02:38:25 +04:00
|
|
|
#include <linux/jbd2.h>
|
2006-10-11 12:21:03 +04:00
|
|
|
#include <linux/highuid.h>
|
|
|
|
#include <linux/pagemap.h>
|
|
|
|
#include <linux/quotaops.h>
|
|
|
|
#include <linux/string.h>
|
|
|
|
#include <linux/slab.h>
|
|
|
|
#include <asm/uaccess.h>
|
2008-10-07 08:46:36 +04:00
|
|
|
#include <linux/fiemap.h>
|
2015-05-23 00:13:32 +03:00
|
|
|
#include <linux/backing-dev.h>
|
2008-04-30 02:13:32 +04:00
|
|
|
#include "ext4_jbd2.h"
|
2012-11-28 22:03:30 +04:00
|
|
|
#include "ext4_extents.h"
|
2012-12-10 23:05:51 +04:00
|
|
|
#include "xattr.h"
|
2006-10-11 12:21:03 +04:00
|
|
|
|
2011-03-22 04:38:05 +03:00
|
|
|
#include <trace/events/ext4.h>
|
|
|
|
|
ext4: rewrite punch hole to use ext4_ext_remove_space()
This commit rewrites ext4 punch hole implementation to use
ext4_ext_remove_space() instead of its home gown way of doing this via
ext4_ext_map_blocks(). There are several reasons for changing this.
Firstly it is quite non obvious that punching hole needs to
ext4_ext_map_blocks() to punch a hole, especially given that this
function should map blocks, not unmap it. It also required a lot of new
code in ext4_ext_map_blocks().
Secondly the design of it is not very effective. The reason is that we
are trying to punch out blocks in ext4_ext_punch_hole() in opposite
direction than in ext4_ext_rm_leaf() which causes the ext4_ext_rm_leaf()
to iterate through the whole tree from the end to the start to find the
requested extent for every extent we are going to punch out.
And finally the current implementation does not use the existing code,
but bring a lot of new code, which is IMO unnecessary since there
already is some infrastructure we can use. Specifically
ext4_ext_remove_space().
This commit changes ext4_ext_remove_space() to accept 'end' parameter so
we can not only truncate to the end of file, but also remove the space
in the middle of the file (punch a hole). Moreover, because the last
block to punch out, might be in the middle of the extent, we have to
split the extent at 'end + 1' so ext4_ext_rm_leaf() can easily either
remove the whole fist part of split extent, or change its size.
ext4_ext_remove_space() is then used to actually remove the space
(extents) from within the hole, instead of ext4_ext_map_blocks().
Note that this also fix the issue with punch hole, where we would forget
to remove empty index blocks from the extent tree, resulting in double
free block error and file system corruption. This is simply because we
now use different code path, where this problem does not exist.
This has been tested with fsx running for several days and xfstests,
plus xfstest #251 with '-o discard' run on the loop image (which
converts discard requestes into punch hole to the backing file). All of
it on 1K and 4K file system block size.
Signed-off-by: Lukas Czerner <lczerner@redhat.com>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
2012-03-20 07:03:19 +04:00
|
|
|
/*
|
|
|
|
* used by extent splitting.
|
|
|
|
*/
|
|
|
|
#define EXT4_EXT_MAY_ZEROOUT 0x1 /* safe to zeroout if split fails \
|
|
|
|
due to ENOSPC */
|
2014-04-21 07:45:47 +04:00
|
|
|
#define EXT4_EXT_MARK_UNWRIT1 0x2 /* mark first half unwritten */
|
|
|
|
#define EXT4_EXT_MARK_UNWRIT2 0x4 /* mark second half unwritten */
|
ext4: rewrite punch hole to use ext4_ext_remove_space()
This commit rewrites ext4 punch hole implementation to use
ext4_ext_remove_space() instead of its home gown way of doing this via
ext4_ext_map_blocks(). There are several reasons for changing this.
Firstly it is quite non obvious that punching hole needs to
ext4_ext_map_blocks() to punch a hole, especially given that this
function should map blocks, not unmap it. It also required a lot of new
code in ext4_ext_map_blocks().
Secondly the design of it is not very effective. The reason is that we
are trying to punch out blocks in ext4_ext_punch_hole() in opposite
direction than in ext4_ext_rm_leaf() which causes the ext4_ext_rm_leaf()
to iterate through the whole tree from the end to the start to find the
requested extent for every extent we are going to punch out.
And finally the current implementation does not use the existing code,
but bring a lot of new code, which is IMO unnecessary since there
already is some infrastructure we can use. Specifically
ext4_ext_remove_space().
This commit changes ext4_ext_remove_space() to accept 'end' parameter so
we can not only truncate to the end of file, but also remove the space
in the middle of the file (punch a hole). Moreover, because the last
block to punch out, might be in the middle of the extent, we have to
split the extent at 'end + 1' so ext4_ext_rm_leaf() can easily either
remove the whole fist part of split extent, or change its size.
ext4_ext_remove_space() is then used to actually remove the space
(extents) from within the hole, instead of ext4_ext_map_blocks().
Note that this also fix the issue with punch hole, where we would forget
to remove empty index blocks from the extent tree, resulting in double
free block error and file system corruption. This is simply because we
now use different code path, where this problem does not exist.
This has been tested with fsx running for several days and xfstests,
plus xfstest #251 with '-o discard' run on the loop image (which
converts discard requestes into punch hole to the backing file). All of
it on 1K and 4K file system block size.
Signed-off-by: Lukas Czerner <lczerner@redhat.com>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
2012-03-20 07:03:19 +04:00
|
|
|
|
2012-10-10 09:04:58 +04:00
|
|
|
#define EXT4_EXT_DATA_VALID1 0x8 /* first half contains valid data */
|
|
|
|
#define EXT4_EXT_DATA_VALID2 0x10 /* second half contains valid data */
|
|
|
|
|
2012-04-30 02:37:10 +04:00
|
|
|
static __le32 ext4_extent_block_csum(struct inode *inode,
|
|
|
|
struct ext4_extent_header *eh)
|
|
|
|
{
|
|
|
|
struct ext4_inode_info *ei = EXT4_I(inode);
|
|
|
|
struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
|
|
|
|
__u32 csum;
|
|
|
|
|
|
|
|
csum = ext4_chksum(sbi, ei->i_csum_seed, (__u8 *)eh,
|
|
|
|
EXT4_EXTENT_TAIL_OFFSET(eh));
|
|
|
|
return cpu_to_le32(csum);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int ext4_extent_block_csum_verify(struct inode *inode,
|
|
|
|
struct ext4_extent_header *eh)
|
|
|
|
{
|
|
|
|
struct ext4_extent_tail *et;
|
|
|
|
|
2014-10-13 11:36:16 +04:00
|
|
|
if (!ext4_has_metadata_csum(inode->i_sb))
|
2012-04-30 02:37:10 +04:00
|
|
|
return 1;
|
|
|
|
|
|
|
|
et = find_ext4_extent_tail(eh);
|
|
|
|
if (et->et_checksum != ext4_extent_block_csum(inode, eh))
|
|
|
|
return 0;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ext4_extent_block_csum_set(struct inode *inode,
|
|
|
|
struct ext4_extent_header *eh)
|
|
|
|
{
|
|
|
|
struct ext4_extent_tail *et;
|
|
|
|
|
2014-10-13 11:36:16 +04:00
|
|
|
if (!ext4_has_metadata_csum(inode->i_sb))
|
2012-04-30 02:37:10 +04:00
|
|
|
return;
|
|
|
|
|
|
|
|
et = find_ext4_extent_tail(eh);
|
|
|
|
et->et_checksum = ext4_extent_block_csum(inode, eh);
|
|
|
|
}
|
|
|
|
|
2011-05-25 15:41:43 +04:00
|
|
|
static int ext4_split_extent(handle_t *handle,
|
|
|
|
struct inode *inode,
|
2014-09-01 22:37:09 +04:00
|
|
|
struct ext4_ext_path **ppath,
|
2011-05-25 15:41:43 +04:00
|
|
|
struct ext4_map_blocks *map,
|
|
|
|
int split_flag,
|
|
|
|
int flags);
|
|
|
|
|
ext4: rewrite punch hole to use ext4_ext_remove_space()
This commit rewrites ext4 punch hole implementation to use
ext4_ext_remove_space() instead of its home gown way of doing this via
ext4_ext_map_blocks(). There are several reasons for changing this.
Firstly it is quite non obvious that punching hole needs to
ext4_ext_map_blocks() to punch a hole, especially given that this
function should map blocks, not unmap it. It also required a lot of new
code in ext4_ext_map_blocks().
Secondly the design of it is not very effective. The reason is that we
are trying to punch out blocks in ext4_ext_punch_hole() in opposite
direction than in ext4_ext_rm_leaf() which causes the ext4_ext_rm_leaf()
to iterate through the whole tree from the end to the start to find the
requested extent for every extent we are going to punch out.
And finally the current implementation does not use the existing code,
but bring a lot of new code, which is IMO unnecessary since there
already is some infrastructure we can use. Specifically
ext4_ext_remove_space().
This commit changes ext4_ext_remove_space() to accept 'end' parameter so
we can not only truncate to the end of file, but also remove the space
in the middle of the file (punch a hole). Moreover, because the last
block to punch out, might be in the middle of the extent, we have to
split the extent at 'end + 1' so ext4_ext_rm_leaf() can easily either
remove the whole fist part of split extent, or change its size.
ext4_ext_remove_space() is then used to actually remove the space
(extents) from within the hole, instead of ext4_ext_map_blocks().
Note that this also fix the issue with punch hole, where we would forget
to remove empty index blocks from the extent tree, resulting in double
free block error and file system corruption. This is simply because we
now use different code path, where this problem does not exist.
This has been tested with fsx running for several days and xfstests,
plus xfstest #251 with '-o discard' run on the loop image (which
converts discard requestes into punch hole to the backing file). All of
it on 1K and 4K file system block size.
Signed-off-by: Lukas Czerner <lczerner@redhat.com>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
2012-03-20 07:03:19 +04:00
|
|
|
static int ext4_split_extent_at(handle_t *handle,
|
|
|
|
struct inode *inode,
|
2014-09-01 22:37:09 +04:00
|
|
|
struct ext4_ext_path **ppath,
|
ext4: rewrite punch hole to use ext4_ext_remove_space()
This commit rewrites ext4 punch hole implementation to use
ext4_ext_remove_space() instead of its home gown way of doing this via
ext4_ext_map_blocks(). There are several reasons for changing this.
Firstly it is quite non obvious that punching hole needs to
ext4_ext_map_blocks() to punch a hole, especially given that this
function should map blocks, not unmap it. It also required a lot of new
code in ext4_ext_map_blocks().
Secondly the design of it is not very effective. The reason is that we
are trying to punch out blocks in ext4_ext_punch_hole() in opposite
direction than in ext4_ext_rm_leaf() which causes the ext4_ext_rm_leaf()
to iterate through the whole tree from the end to the start to find the
requested extent for every extent we are going to punch out.
And finally the current implementation does not use the existing code,
but bring a lot of new code, which is IMO unnecessary since there
already is some infrastructure we can use. Specifically
ext4_ext_remove_space().
This commit changes ext4_ext_remove_space() to accept 'end' parameter so
we can not only truncate to the end of file, but also remove the space
in the middle of the file (punch a hole). Moreover, because the last
block to punch out, might be in the middle of the extent, we have to
split the extent at 'end + 1' so ext4_ext_rm_leaf() can easily either
remove the whole fist part of split extent, or change its size.
ext4_ext_remove_space() is then used to actually remove the space
(extents) from within the hole, instead of ext4_ext_map_blocks().
Note that this also fix the issue with punch hole, where we would forget
to remove empty index blocks from the extent tree, resulting in double
free block error and file system corruption. This is simply because we
now use different code path, where this problem does not exist.
This has been tested with fsx running for several days and xfstests,
plus xfstest #251 with '-o discard' run on the loop image (which
converts discard requestes into punch hole to the backing file). All of
it on 1K and 4K file system block size.
Signed-off-by: Lukas Czerner <lczerner@redhat.com>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
2012-03-20 07:03:19 +04:00
|
|
|
ext4_lblk_t split,
|
|
|
|
int split_flag,
|
|
|
|
int flags);
|
|
|
|
|
2012-11-28 21:32:26 +04:00
|
|
|
static int ext4_find_delayed_extent(struct inode *inode,
|
2013-02-18 09:31:07 +04:00
|
|
|
struct extent_status *newes);
|
2012-11-28 21:32:26 +04:00
|
|
|
|
2009-08-18 06:17:20 +04:00
|
|
|
static int ext4_ext_truncate_extend_restart(handle_t *handle,
|
|
|
|
struct inode *inode,
|
|
|
|
int needed)
|
2006-10-11 12:21:03 +04:00
|
|
|
{
|
|
|
|
int err;
|
|
|
|
|
2009-01-07 08:06:22 +03:00
|
|
|
if (!ext4_handle_valid(handle))
|
|
|
|
return 0;
|
2006-10-11 12:21:03 +04:00
|
|
|
if (handle->h_buffer_credits > needed)
|
2008-07-12 03:27:31 +04:00
|
|
|
return 0;
|
|
|
|
err = ext4_journal_extend(handle, needed);
|
2008-08-02 04:57:54 +04:00
|
|
|
if (err <= 0)
|
2008-07-12 03:27:31 +04:00
|
|
|
return err;
|
2009-08-18 06:17:20 +04:00
|
|
|
err = ext4_truncate_restart_trans(handle, inode, needed);
|
2010-05-17 09:00:00 +04:00
|
|
|
if (err == 0)
|
|
|
|
err = -EAGAIN;
|
2009-08-18 06:17:20 +04:00
|
|
|
|
|
|
|
return err;
|
2006-10-11 12:21:03 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* could return:
|
|
|
|
* - EROFS
|
|
|
|
* - ENOMEM
|
|
|
|
*/
|
|
|
|
static int ext4_ext_get_access(handle_t *handle, struct inode *inode,
|
|
|
|
struct ext4_ext_path *path)
|
|
|
|
{
|
|
|
|
if (path->p_bh) {
|
|
|
|
/* path points to block */
|
2014-05-13 06:06:43 +04:00
|
|
|
BUFFER_TRACE(path->p_bh, "get_write_access");
|
2006-10-11 12:21:03 +04:00
|
|
|
return ext4_journal_get_write_access(handle, path->p_bh);
|
|
|
|
}
|
|
|
|
/* path points to leaf/index in inode body */
|
|
|
|
/* we use in-core data, no need to protect them */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* could return:
|
|
|
|
* - EROFS
|
|
|
|
* - ENOMEM
|
|
|
|
* - EIO
|
|
|
|
*/
|
2013-04-19 22:04:12 +04:00
|
|
|
int __ext4_ext_dirty(const char *where, unsigned int line, handle_t *handle,
|
|
|
|
struct inode *inode, struct ext4_ext_path *path)
|
2006-10-11 12:21:03 +04:00
|
|
|
{
|
|
|
|
int err;
|
2014-07-28 06:28:15 +04:00
|
|
|
|
|
|
|
WARN_ON(!rwsem_is_locked(&EXT4_I(inode)->i_data_sem));
|
2006-10-11 12:21:03 +04:00
|
|
|
if (path->p_bh) {
|
2012-04-30 02:37:10 +04:00
|
|
|
ext4_extent_block_csum_set(inode, ext_block_hdr(path->p_bh));
|
2006-10-11 12:21:03 +04:00
|
|
|
/* path points to block */
|
2011-09-04 18:18:14 +04:00
|
|
|
err = __ext4_handle_dirty_metadata(where, line, handle,
|
|
|
|
inode, path->p_bh);
|
2006-10-11 12:21:03 +04:00
|
|
|
} else {
|
|
|
|
/* path points to leaf/index in inode body */
|
|
|
|
err = ext4_mark_inode_dirty(handle, inode);
|
|
|
|
}
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2006-10-11 12:21:05 +04:00
|
|
|
static ext4_fsblk_t ext4_ext_find_goal(struct inode *inode,
|
2006-10-11 12:21:03 +04:00
|
|
|
struct ext4_ext_path *path,
|
2008-01-29 07:58:27 +03:00
|
|
|
ext4_lblk_t block)
|
2006-10-11 12:21:03 +04:00
|
|
|
{
|
|
|
|
if (path) {
|
2011-10-29 17:23:38 +04:00
|
|
|
int depth = path->p_depth;
|
2006-10-11 12:21:03 +04:00
|
|
|
struct ext4_extent *ex;
|
|
|
|
|
2011-01-10 20:12:28 +03:00
|
|
|
/*
|
|
|
|
* Try to predict block placement assuming that we are
|
|
|
|
* filling in a file which will eventually be
|
|
|
|
* non-sparse --- i.e., in the case of libbfd writing
|
|
|
|
* an ELF object sections out-of-order but in a way
|
|
|
|
* the eventually results in a contiguous object or
|
|
|
|
* executable file, or some database extending a table
|
|
|
|
* space file. However, this is actually somewhat
|
|
|
|
* non-ideal if we are writing a sparse file such as
|
|
|
|
* qemu or KVM writing a raw image file that is going
|
|
|
|
* to stay fairly sparse, since it will end up
|
|
|
|
* fragmenting the file system's free space. Maybe we
|
|
|
|
* should have some hueristics or some way to allow
|
|
|
|
* userspace to pass a hint to file system,
|
2011-01-21 18:21:31 +03:00
|
|
|
* especially if the latter case turns out to be
|
2011-01-10 20:12:28 +03:00
|
|
|
* common.
|
|
|
|
*/
|
2006-12-07 07:41:33 +03:00
|
|
|
ex = path[depth].p_ext;
|
2011-01-10 20:12:28 +03:00
|
|
|
if (ex) {
|
|
|
|
ext4_fsblk_t ext_pblk = ext4_ext_pblock(ex);
|
|
|
|
ext4_lblk_t ext_block = le32_to_cpu(ex->ee_block);
|
|
|
|
|
|
|
|
if (block > ext_block)
|
|
|
|
return ext_pblk + (block - ext_block);
|
|
|
|
else
|
|
|
|
return ext_pblk - (ext_block - block);
|
|
|
|
}
|
2006-10-11 12:21:03 +04:00
|
|
|
|
2006-10-11 12:21:07 +04:00
|
|
|
/* it looks like index is empty;
|
|
|
|
* try to find starting block from index itself */
|
2006-10-11 12:21:03 +04:00
|
|
|
if (path[depth].p_bh)
|
|
|
|
return path[depth].p_bh->b_blocknr;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* OK. use inode's group */
|
2011-06-28 18:01:31 +04:00
|
|
|
return ext4_inode_to_goal_block(inode);
|
2006-10-11 12:21:03 +04:00
|
|
|
}
|
|
|
|
|
2008-07-12 03:27:31 +04:00
|
|
|
/*
|
|
|
|
* Allocation for a meta data block
|
|
|
|
*/
|
2006-10-11 12:21:05 +04:00
|
|
|
static ext4_fsblk_t
|
2008-07-12 03:27:31 +04:00
|
|
|
ext4_ext_new_meta_block(handle_t *handle, struct inode *inode,
|
2006-10-11 12:21:03 +04:00
|
|
|
struct ext4_ext_path *path,
|
2011-05-25 15:41:26 +04:00
|
|
|
struct ext4_extent *ex, int *err, unsigned int flags)
|
2006-10-11 12:21:03 +04:00
|
|
|
{
|
2006-10-11 12:21:05 +04:00
|
|
|
ext4_fsblk_t goal, newblock;
|
2006-10-11 12:21:03 +04:00
|
|
|
|
|
|
|
goal = ext4_ext_find_goal(inode, path, le32_to_cpu(ex->ee_block));
|
2011-05-25 15:41:26 +04:00
|
|
|
newblock = ext4_new_meta_blocks(handle, inode, goal, flags,
|
|
|
|
NULL, err);
|
2006-10-11 12:21:03 +04:00
|
|
|
return newblock;
|
|
|
|
}
|
|
|
|
|
2009-08-28 18:40:33 +04:00
|
|
|
static inline int ext4_ext_space_block(struct inode *inode, int check)
|
2006-10-11 12:21:03 +04:00
|
|
|
{
|
|
|
|
int size;
|
|
|
|
|
|
|
|
size = (inode->i_sb->s_blocksize - sizeof(struct ext4_extent_header))
|
|
|
|
/ sizeof(struct ext4_extent);
|
2007-02-17 21:20:16 +03:00
|
|
|
#ifdef AGGRESSIVE_TEST
|
2011-10-29 17:29:11 +04:00
|
|
|
if (!check && size > 6)
|
|
|
|
size = 6;
|
2006-10-11 12:21:03 +04:00
|
|
|
#endif
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2009-08-28 18:40:33 +04:00
|
|
|
static inline int ext4_ext_space_block_idx(struct inode *inode, int check)
|
2006-10-11 12:21:03 +04:00
|
|
|
{
|
|
|
|
int size;
|
|
|
|
|
|
|
|
size = (inode->i_sb->s_blocksize - sizeof(struct ext4_extent_header))
|
|
|
|
/ sizeof(struct ext4_extent_idx);
|
2007-02-17 21:20:16 +03:00
|
|
|
#ifdef AGGRESSIVE_TEST
|
2011-10-29 17:29:11 +04:00
|
|
|
if (!check && size > 5)
|
|
|
|
size = 5;
|
2006-10-11 12:21:03 +04:00
|
|
|
#endif
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2009-08-28 18:40:33 +04:00
|
|
|
static inline int ext4_ext_space_root(struct inode *inode, int check)
|
2006-10-11 12:21:03 +04:00
|
|
|
{
|
|
|
|
int size;
|
|
|
|
|
|
|
|
size = sizeof(EXT4_I(inode)->i_data);
|
|
|
|
size -= sizeof(struct ext4_extent_header);
|
|
|
|
size /= sizeof(struct ext4_extent);
|
2007-02-17 21:20:16 +03:00
|
|
|
#ifdef AGGRESSIVE_TEST
|
2011-10-29 17:29:11 +04:00
|
|
|
if (!check && size > 3)
|
|
|
|
size = 3;
|
2006-10-11 12:21:03 +04:00
|
|
|
#endif
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2009-08-28 18:40:33 +04:00
|
|
|
static inline int ext4_ext_space_root_idx(struct inode *inode, int check)
|
2006-10-11 12:21:03 +04:00
|
|
|
{
|
|
|
|
int size;
|
|
|
|
|
|
|
|
size = sizeof(EXT4_I(inode)->i_data);
|
|
|
|
size -= sizeof(struct ext4_extent_header);
|
|
|
|
size /= sizeof(struct ext4_extent_idx);
|
2007-02-17 21:20:16 +03:00
|
|
|
#ifdef AGGRESSIVE_TEST
|
2011-10-29 17:29:11 +04:00
|
|
|
if (!check && size > 4)
|
|
|
|
size = 4;
|
2006-10-11 12:21:03 +04:00
|
|
|
#endif
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2014-08-31 07:52:19 +04:00
|
|
|
static inline int
|
|
|
|
ext4_force_split_extent_at(handle_t *handle, struct inode *inode,
|
2014-09-01 22:37:09 +04:00
|
|
|
struct ext4_ext_path **ppath, ext4_lblk_t lblk,
|
2014-08-31 07:52:19 +04:00
|
|
|
int nofail)
|
|
|
|
{
|
2014-09-01 22:37:09 +04:00
|
|
|
struct ext4_ext_path *path = *ppath;
|
2014-08-31 07:52:19 +04:00
|
|
|
int unwritten = ext4_ext_is_unwritten(path[path->p_depth].p_ext);
|
|
|
|
|
2014-09-01 22:37:09 +04:00
|
|
|
return ext4_split_extent_at(handle, inode, ppath, lblk, unwritten ?
|
2014-08-31 07:52:19 +04:00
|
|
|
EXT4_EXT_MARK_UNWRIT1|EXT4_EXT_MARK_UNWRIT2 : 0,
|
|
|
|
EXT4_EX_NOCACHE | EXT4_GET_BLOCKS_PRE_IO |
|
|
|
|
(nofail ? EXT4_GET_BLOCKS_METADATA_NOFAIL:0));
|
|
|
|
}
|
|
|
|
|
2008-07-15 01:52:37 +04:00
|
|
|
/*
|
|
|
|
* Calculate the number of metadata blocks needed
|
|
|
|
* to allocate @blocks
|
|
|
|
* Worse case is one block per extent
|
|
|
|
*/
|
2011-01-10 20:13:03 +03:00
|
|
|
int ext4_ext_calc_metadata_amount(struct inode *inode, ext4_lblk_t lblock)
|
2008-07-15 01:52:37 +04:00
|
|
|
{
|
2010-01-01 10:41:30 +03:00
|
|
|
struct ext4_inode_info *ei = EXT4_I(inode);
|
2011-10-29 17:23:38 +04:00
|
|
|
int idxs;
|
2008-07-15 01:52:37 +04:00
|
|
|
|
2010-01-01 10:41:30 +03:00
|
|
|
idxs = ((inode->i_sb->s_blocksize - sizeof(struct ext4_extent_header))
|
|
|
|
/ sizeof(struct ext4_extent_idx));
|
2008-07-15 01:52:37 +04:00
|
|
|
|
|
|
|
/*
|
2010-01-01 10:41:30 +03:00
|
|
|
* If the new delayed allocation block is contiguous with the
|
|
|
|
* previous da block, it can share index blocks with the
|
|
|
|
* previous block, so we only need to allocate a new index
|
|
|
|
* block every idxs leaf blocks. At ldxs**2 blocks, we need
|
|
|
|
* an additional index block, and at ldxs**3 blocks, yet
|
|
|
|
* another index blocks.
|
2008-07-15 01:52:37 +04:00
|
|
|
*/
|
2010-01-01 10:41:30 +03:00
|
|
|
if (ei->i_da_metadata_calc_len &&
|
|
|
|
ei->i_da_metadata_calc_last_lblock+1 == lblock) {
|
2011-10-29 17:23:38 +04:00
|
|
|
int num = 0;
|
|
|
|
|
2010-01-01 10:41:30 +03:00
|
|
|
if ((ei->i_da_metadata_calc_len % idxs) == 0)
|
|
|
|
num++;
|
|
|
|
if ((ei->i_da_metadata_calc_len % (idxs*idxs)) == 0)
|
|
|
|
num++;
|
|
|
|
if ((ei->i_da_metadata_calc_len % (idxs*idxs*idxs)) == 0) {
|
|
|
|
num++;
|
|
|
|
ei->i_da_metadata_calc_len = 0;
|
|
|
|
} else
|
|
|
|
ei->i_da_metadata_calc_len++;
|
|
|
|
ei->i_da_metadata_calc_last_lblock++;
|
|
|
|
return num;
|
|
|
|
}
|
2008-07-15 01:52:37 +04:00
|
|
|
|
2010-01-01 10:41:30 +03:00
|
|
|
/*
|
|
|
|
* In the worst case we need a new set of index blocks at
|
|
|
|
* every level of the inode's extent tree.
|
|
|
|
*/
|
|
|
|
ei->i_da_metadata_calc_len = 1;
|
|
|
|
ei->i_da_metadata_calc_last_lblock = lblock;
|
|
|
|
return ext_depth(inode) + 1;
|
2008-07-15 01:52:37 +04:00
|
|
|
}
|
|
|
|
|
2007-07-18 17:19:09 +04:00
|
|
|
static int
|
|
|
|
ext4_ext_max_entries(struct inode *inode, int depth)
|
|
|
|
{
|
|
|
|
int max;
|
|
|
|
|
|
|
|
if (depth == ext_depth(inode)) {
|
|
|
|
if (depth == 0)
|
2009-08-28 18:40:33 +04:00
|
|
|
max = ext4_ext_space_root(inode, 1);
|
2007-07-18 17:19:09 +04:00
|
|
|
else
|
2009-08-28 18:40:33 +04:00
|
|
|
max = ext4_ext_space_root_idx(inode, 1);
|
2007-07-18 17:19:09 +04:00
|
|
|
} else {
|
|
|
|
if (depth == 0)
|
2009-08-28 18:40:33 +04:00
|
|
|
max = ext4_ext_space_block(inode, 1);
|
2007-07-18 17:19:09 +04:00
|
|
|
else
|
2009-08-28 18:40:33 +04:00
|
|
|
max = ext4_ext_space_block_idx(inode, 1);
|
2007-07-18 17:19:09 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
return max;
|
|
|
|
}
|
|
|
|
|
2009-03-12 16:51:20 +03:00
|
|
|
static int ext4_valid_extent(struct inode *inode, struct ext4_extent *ext)
|
|
|
|
{
|
2010-10-28 05:30:14 +04:00
|
|
|
ext4_fsblk_t block = ext4_ext_pblock(ext);
|
2009-03-12 16:51:20 +03:00
|
|
|
int len = ext4_ext_get_actual_len(ext);
|
2013-12-04 06:22:21 +04:00
|
|
|
ext4_lblk_t lblock = le32_to_cpu(ext->ee_block);
|
|
|
|
ext4_lblk_t last = lblock + len - 1;
|
2009-04-23 04:52:25 +04:00
|
|
|
|
2015-05-15 02:00:45 +03:00
|
|
|
if (len == 0 || lblock > last)
|
2012-03-12 07:30:16 +04:00
|
|
|
return 0;
|
2009-05-17 23:38:01 +04:00
|
|
|
return ext4_data_block_valid(EXT4_SB(inode->i_sb), block, len);
|
2009-03-12 16:51:20 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static int ext4_valid_extent_idx(struct inode *inode,
|
|
|
|
struct ext4_extent_idx *ext_idx)
|
|
|
|
{
|
2010-10-28 05:30:14 +04:00
|
|
|
ext4_fsblk_t block = ext4_idx_pblock(ext_idx);
|
2009-04-23 04:52:25 +04:00
|
|
|
|
2009-05-17 23:38:01 +04:00
|
|
|
return ext4_data_block_valid(EXT4_SB(inode->i_sb), block, 1);
|
2009-03-12 16:51:20 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static int ext4_valid_extent_entries(struct inode *inode,
|
|
|
|
struct ext4_extent_header *eh,
|
|
|
|
int depth)
|
|
|
|
{
|
|
|
|
unsigned short entries;
|
|
|
|
if (eh->eh_entries == 0)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
entries = le16_to_cpu(eh->eh_entries);
|
|
|
|
|
|
|
|
if (depth == 0) {
|
|
|
|
/* leaf entries */
|
2011-10-29 17:23:38 +04:00
|
|
|
struct ext4_extent *ext = EXT_FIRST_EXTENT(eh);
|
2013-12-04 06:22:21 +04:00
|
|
|
struct ext4_super_block *es = EXT4_SB(inode->i_sb)->s_es;
|
|
|
|
ext4_fsblk_t pblock = 0;
|
|
|
|
ext4_lblk_t lblock = 0;
|
|
|
|
ext4_lblk_t prev = 0;
|
|
|
|
int len = 0;
|
2009-03-12 16:51:20 +03:00
|
|
|
while (entries) {
|
|
|
|
if (!ext4_valid_extent(inode, ext))
|
|
|
|
return 0;
|
2013-12-04 06:22:21 +04:00
|
|
|
|
|
|
|
/* Check for overlapping extents */
|
|
|
|
lblock = le32_to_cpu(ext->ee_block);
|
|
|
|
len = ext4_ext_get_actual_len(ext);
|
|
|
|
if ((lblock <= prev) && prev) {
|
|
|
|
pblock = ext4_ext_pblock(ext);
|
|
|
|
es->s_last_error_block = cpu_to_le64(pblock);
|
|
|
|
return 0;
|
|
|
|
}
|
2009-03-12 16:51:20 +03:00
|
|
|
ext++;
|
|
|
|
entries--;
|
2013-12-04 06:22:21 +04:00
|
|
|
prev = lblock + len - 1;
|
2009-03-12 16:51:20 +03:00
|
|
|
}
|
|
|
|
} else {
|
2011-10-29 17:23:38 +04:00
|
|
|
struct ext4_extent_idx *ext_idx = EXT_FIRST_INDEX(eh);
|
2009-03-12 16:51:20 +03:00
|
|
|
while (entries) {
|
|
|
|
if (!ext4_valid_extent_idx(inode, ext_idx))
|
|
|
|
return 0;
|
|
|
|
ext_idx++;
|
|
|
|
entries--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2010-07-27 19:56:40 +04:00
|
|
|
static int __ext4_ext_check(const char *function, unsigned int line,
|
|
|
|
struct inode *inode, struct ext4_extent_header *eh,
|
2013-08-17 05:21:41 +04:00
|
|
|
int depth, ext4_fsblk_t pblk)
|
2007-07-18 17:19:09 +04:00
|
|
|
{
|
|
|
|
const char *error_msg;
|
2015-10-17 23:16:04 +03:00
|
|
|
int max = 0, err = -EFSCORRUPTED;
|
2007-07-18 17:19:09 +04:00
|
|
|
|
|
|
|
if (unlikely(eh->eh_magic != EXT4_EXT_MAGIC)) {
|
|
|
|
error_msg = "invalid magic";
|
|
|
|
goto corrupted;
|
|
|
|
}
|
|
|
|
if (unlikely(le16_to_cpu(eh->eh_depth) != depth)) {
|
|
|
|
error_msg = "unexpected eh_depth";
|
|
|
|
goto corrupted;
|
|
|
|
}
|
|
|
|
if (unlikely(eh->eh_max == 0)) {
|
|
|
|
error_msg = "invalid eh_max";
|
|
|
|
goto corrupted;
|
|
|
|
}
|
|
|
|
max = ext4_ext_max_entries(inode, depth);
|
|
|
|
if (unlikely(le16_to_cpu(eh->eh_max) > max)) {
|
|
|
|
error_msg = "too large eh_max";
|
|
|
|
goto corrupted;
|
|
|
|
}
|
|
|
|
if (unlikely(le16_to_cpu(eh->eh_entries) > le16_to_cpu(eh->eh_max))) {
|
|
|
|
error_msg = "invalid eh_entries";
|
|
|
|
goto corrupted;
|
|
|
|
}
|
2009-03-12 16:51:20 +03:00
|
|
|
if (!ext4_valid_extent_entries(inode, eh, depth)) {
|
|
|
|
error_msg = "invalid extent entries";
|
|
|
|
goto corrupted;
|
|
|
|
}
|
2012-04-30 02:37:10 +04:00
|
|
|
/* Verify checksum on non-root extent tree nodes */
|
|
|
|
if (ext_depth(inode) != depth &&
|
|
|
|
!ext4_extent_block_csum_verify(inode, eh)) {
|
|
|
|
error_msg = "extent tree corrupted";
|
2015-10-17 23:16:04 +03:00
|
|
|
err = -EFSBADCRC;
|
2012-04-30 02:37:10 +04:00
|
|
|
goto corrupted;
|
|
|
|
}
|
2007-07-18 17:19:09 +04:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
corrupted:
|
2010-07-27 19:56:40 +04:00
|
|
|
ext4_error_inode(inode, function, line, 0,
|
2013-08-17 05:21:41 +04:00
|
|
|
"pblk %llu bad header/extent: %s - magic %x, "
|
|
|
|
"entries %u, max %u(%u), depth %u(%u)",
|
|
|
|
(unsigned long long) pblk, error_msg,
|
|
|
|
le16_to_cpu(eh->eh_magic),
|
|
|
|
le16_to_cpu(eh->eh_entries), le16_to_cpu(eh->eh_max),
|
|
|
|
max, le16_to_cpu(eh->eh_depth), depth);
|
2015-10-17 23:16:04 +03:00
|
|
|
return err;
|
2007-07-18 17:19:09 +04:00
|
|
|
}
|
|
|
|
|
2013-08-17 05:21:41 +04:00
|
|
|
#define ext4_ext_check(inode, eh, depth, pblk) \
|
|
|
|
__ext4_ext_check(__func__, __LINE__, (inode), (eh), (depth), (pblk))
|
2007-07-18 17:19:09 +04:00
|
|
|
|
2009-03-27 23:39:58 +03:00
|
|
|
int ext4_ext_check_inode(struct inode *inode)
|
|
|
|
{
|
2013-08-17 05:21:41 +04:00
|
|
|
return ext4_ext_check(inode, ext_inode_hdr(inode), ext_depth(inode), 0);
|
2009-03-27 23:39:58 +03:00
|
|
|
}
|
|
|
|
|
2013-08-17 05:20:41 +04:00
|
|
|
static struct buffer_head *
|
|
|
|
__read_extent_tree_block(const char *function, unsigned int line,
|
2013-08-17 05:23:41 +04:00
|
|
|
struct inode *inode, ext4_fsblk_t pblk, int depth,
|
|
|
|
int flags)
|
2012-04-30 02:21:10 +04:00
|
|
|
{
|
2013-08-17 05:20:41 +04:00
|
|
|
struct buffer_head *bh;
|
|
|
|
int err;
|
|
|
|
|
2015-07-02 08:34:07 +03:00
|
|
|
bh = sb_getblk_gfp(inode->i_sb, pblk, __GFP_MOVABLE | GFP_NOFS);
|
2013-08-17 05:20:41 +04:00
|
|
|
if (unlikely(!bh))
|
|
|
|
return ERR_PTR(-ENOMEM);
|
2012-04-30 02:21:10 +04:00
|
|
|
|
2013-08-17 05:20:41 +04:00
|
|
|
if (!bh_uptodate_or_lock(bh)) {
|
|
|
|
trace_ext4_ext_load_extent(inode, pblk, _RET_IP_);
|
|
|
|
err = bh_submit_read(bh);
|
|
|
|
if (err < 0)
|
|
|
|
goto errout;
|
|
|
|
}
|
2013-08-17 06:05:14 +04:00
|
|
|
if (buffer_verified(bh) && !(flags & EXT4_EX_FORCE_CACHE))
|
2013-08-17 05:20:41 +04:00
|
|
|
return bh;
|
|
|
|
err = __ext4_ext_check(function, line, inode,
|
2013-08-17 05:21:41 +04:00
|
|
|
ext_block_hdr(bh), depth, pblk);
|
2013-08-17 05:20:41 +04:00
|
|
|
if (err)
|
|
|
|
goto errout;
|
2012-04-30 02:21:10 +04:00
|
|
|
set_buffer_verified(bh);
|
2013-08-17 05:23:41 +04:00
|
|
|
/*
|
|
|
|
* If this is a leaf block, cache all of its entries
|
|
|
|
*/
|
|
|
|
if (!(flags & EXT4_EX_NOCACHE) && depth == 0) {
|
|
|
|
struct ext4_extent_header *eh = ext_block_hdr(bh);
|
|
|
|
struct ext4_extent *ex = EXT_FIRST_EXTENT(eh);
|
|
|
|
ext4_lblk_t prev = 0;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = le16_to_cpu(eh->eh_entries); i > 0; i--, ex++) {
|
|
|
|
unsigned int status = EXTENT_STATUS_WRITTEN;
|
|
|
|
ext4_lblk_t lblk = le32_to_cpu(ex->ee_block);
|
|
|
|
int len = ext4_ext_get_actual_len(ex);
|
|
|
|
|
|
|
|
if (prev && (prev != lblk))
|
|
|
|
ext4_es_cache_extent(inode, prev,
|
|
|
|
lblk - prev, ~0,
|
|
|
|
EXTENT_STATUS_HOLE);
|
|
|
|
|
2014-04-21 07:45:47 +04:00
|
|
|
if (ext4_ext_is_unwritten(ex))
|
2013-08-17 05:23:41 +04:00
|
|
|
status = EXTENT_STATUS_UNWRITTEN;
|
|
|
|
ext4_es_cache_extent(inode, lblk, len,
|
|
|
|
ext4_ext_pblock(ex), status);
|
|
|
|
prev = lblk + len;
|
|
|
|
}
|
|
|
|
}
|
2013-08-17 05:20:41 +04:00
|
|
|
return bh;
|
|
|
|
errout:
|
|
|
|
put_bh(bh);
|
|
|
|
return ERR_PTR(err);
|
|
|
|
|
2012-04-30 02:21:10 +04:00
|
|
|
}
|
|
|
|
|
2013-08-17 05:23:41 +04:00
|
|
|
#define read_extent_tree_block(inode, pblk, depth, flags) \
|
|
|
|
__read_extent_tree_block(__func__, __LINE__, (inode), (pblk), \
|
|
|
|
(depth), (flags))
|
2012-04-30 02:21:10 +04:00
|
|
|
|
2013-08-17 06:05:14 +04:00
|
|
|
/*
|
|
|
|
* This function is called to cache a file's extent information in the
|
|
|
|
* extent status tree
|
|
|
|
*/
|
|
|
|
int ext4_ext_precache(struct inode *inode)
|
|
|
|
{
|
|
|
|
struct ext4_inode_info *ei = EXT4_I(inode);
|
|
|
|
struct ext4_ext_path *path = NULL;
|
|
|
|
struct buffer_head *bh;
|
|
|
|
int i = 0, depth, ret = 0;
|
|
|
|
|
|
|
|
if (!ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))
|
|
|
|
return 0; /* not an extent-mapped inode */
|
|
|
|
|
|
|
|
down_read(&ei->i_data_sem);
|
|
|
|
depth = ext_depth(inode);
|
|
|
|
|
|
|
|
path = kzalloc(sizeof(struct ext4_ext_path) * (depth + 1),
|
|
|
|
GFP_NOFS);
|
|
|
|
if (path == NULL) {
|
|
|
|
up_read(&ei->i_data_sem);
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Don't cache anything if there are no external extent blocks */
|
|
|
|
if (depth == 0)
|
|
|
|
goto out;
|
|
|
|
path[0].p_hdr = ext_inode_hdr(inode);
|
|
|
|
ret = ext4_ext_check(inode, path[0].p_hdr, depth, 0);
|
|
|
|
if (ret)
|
|
|
|
goto out;
|
|
|
|
path[0].p_idx = EXT_FIRST_INDEX(path[0].p_hdr);
|
|
|
|
while (i >= 0) {
|
|
|
|
/*
|
|
|
|
* If this is a leaf block or we've reached the end of
|
|
|
|
* the index block, go up
|
|
|
|
*/
|
|
|
|
if ((i == depth) ||
|
|
|
|
path[i].p_idx > EXT_LAST_INDEX(path[i].p_hdr)) {
|
|
|
|
brelse(path[i].p_bh);
|
|
|
|
path[i].p_bh = NULL;
|
|
|
|
i--;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
bh = read_extent_tree_block(inode,
|
|
|
|
ext4_idx_pblock(path[i].p_idx++),
|
|
|
|
depth - i - 1,
|
|
|
|
EXT4_EX_FORCE_CACHE);
|
|
|
|
if (IS_ERR(bh)) {
|
|
|
|
ret = PTR_ERR(bh);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
i++;
|
|
|
|
path[i].p_bh = bh;
|
|
|
|
path[i].p_hdr = ext_block_hdr(bh);
|
|
|
|
path[i].p_idx = EXT_FIRST_INDEX(path[i].p_hdr);
|
|
|
|
}
|
|
|
|
ext4_set_inode_state(inode, EXT4_STATE_EXT_PRECACHED);
|
|
|
|
out:
|
|
|
|
up_read(&ei->i_data_sem);
|
|
|
|
ext4_ext_drop_refs(path);
|
|
|
|
kfree(path);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2006-10-11 12:21:03 +04:00
|
|
|
#ifdef EXT_DEBUG
|
|
|
|
static void ext4_ext_show_path(struct inode *inode, struct ext4_ext_path *path)
|
|
|
|
{
|
|
|
|
int k, l = path->p_depth;
|
|
|
|
|
|
|
|
ext_debug("path:");
|
|
|
|
for (k = 0; k <= l; k++, path++) {
|
|
|
|
if (path->p_idx) {
|
2006-10-11 12:21:11 +04:00
|
|
|
ext_debug(" %d->%llu", le32_to_cpu(path->p_idx->ei_block),
|
2010-10-28 05:30:14 +04:00
|
|
|
ext4_idx_pblock(path->p_idx));
|
2006-10-11 12:21:03 +04:00
|
|
|
} else if (path->p_ext) {
|
2009-09-18 21:34:55 +04:00
|
|
|
ext_debug(" %d:[%d]%d:%llu ",
|
2006-10-11 12:21:03 +04:00
|
|
|
le32_to_cpu(path->p_ext->ee_block),
|
2014-04-21 07:45:47 +04:00
|
|
|
ext4_ext_is_unwritten(path->p_ext),
|
2007-07-18 05:42:41 +04:00
|
|
|
ext4_ext_get_actual_len(path->p_ext),
|
2010-10-28 05:30:14 +04:00
|
|
|
ext4_ext_pblock(path->p_ext));
|
2006-10-11 12:21:03 +04:00
|
|
|
} else
|
|
|
|
ext_debug(" []");
|
|
|
|
}
|
|
|
|
ext_debug("\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ext4_ext_show_leaf(struct inode *inode, struct ext4_ext_path *path)
|
|
|
|
{
|
|
|
|
int depth = ext_depth(inode);
|
|
|
|
struct ext4_extent_header *eh;
|
|
|
|
struct ext4_extent *ex;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (!path)
|
|
|
|
return;
|
|
|
|
|
|
|
|
eh = path[depth].p_hdr;
|
|
|
|
ex = EXT_FIRST_EXTENT(eh);
|
|
|
|
|
2009-09-18 21:34:55 +04:00
|
|
|
ext_debug("Displaying leaf extents for inode %lu\n", inode->i_ino);
|
|
|
|
|
2006-10-11 12:21:03 +04:00
|
|
|
for (i = 0; i < le16_to_cpu(eh->eh_entries); i++, ex++) {
|
2009-09-18 21:34:55 +04:00
|
|
|
ext_debug("%d:[%d]%d:%llu ", le32_to_cpu(ex->ee_block),
|
2014-04-21 07:45:47 +04:00
|
|
|
ext4_ext_is_unwritten(ex),
|
2010-10-28 05:30:14 +04:00
|
|
|
ext4_ext_get_actual_len(ex), ext4_ext_pblock(ex));
|
2006-10-11 12:21:03 +04:00
|
|
|
}
|
|
|
|
ext_debug("\n");
|
|
|
|
}
|
2011-05-26 01:41:48 +04:00
|
|
|
|
|
|
|
static void ext4_ext_show_move(struct inode *inode, struct ext4_ext_path *path,
|
|
|
|
ext4_fsblk_t newblock, int level)
|
|
|
|
{
|
|
|
|
int depth = ext_depth(inode);
|
|
|
|
struct ext4_extent *ex;
|
|
|
|
|
|
|
|
if (depth != level) {
|
|
|
|
struct ext4_extent_idx *idx;
|
|
|
|
idx = path[level].p_idx;
|
|
|
|
while (idx <= EXT_MAX_INDEX(path[level].p_hdr)) {
|
|
|
|
ext_debug("%d: move %d:%llu in new index %llu\n", level,
|
|
|
|
le32_to_cpu(idx->ei_block),
|
|
|
|
ext4_idx_pblock(idx),
|
|
|
|
newblock);
|
|
|
|
idx++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ex = path[depth].p_ext;
|
|
|
|
while (ex <= EXT_MAX_EXTENT(path[depth].p_hdr)) {
|
|
|
|
ext_debug("move %d:%llu:[%d]%d in new leaf %llu\n",
|
|
|
|
le32_to_cpu(ex->ee_block),
|
|
|
|
ext4_ext_pblock(ex),
|
2014-04-21 07:45:47 +04:00
|
|
|
ext4_ext_is_unwritten(ex),
|
2011-05-26 01:41:48 +04:00
|
|
|
ext4_ext_get_actual_len(ex),
|
|
|
|
newblock);
|
|
|
|
ex++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-10-11 12:21:03 +04:00
|
|
|
#else
|
2008-09-09 06:25:24 +04:00
|
|
|
#define ext4_ext_show_path(inode, path)
|
|
|
|
#define ext4_ext_show_leaf(inode, path)
|
2011-05-26 01:41:48 +04:00
|
|
|
#define ext4_ext_show_move(inode, path, newblock, level)
|
2006-10-11 12:21:03 +04:00
|
|
|
#endif
|
|
|
|
|
2008-02-26 00:54:37 +03:00
|
|
|
void ext4_ext_drop_refs(struct ext4_ext_path *path)
|
2006-10-11 12:21:03 +04:00
|
|
|
{
|
2014-09-01 22:39:09 +04:00
|
|
|
int depth, i;
|
2006-10-11 12:21:03 +04:00
|
|
|
|
2014-09-01 22:39:09 +04:00
|
|
|
if (!path)
|
|
|
|
return;
|
|
|
|
depth = path->p_depth;
|
2006-10-11 12:21:03 +04:00
|
|
|
for (i = 0; i <= depth; i++, path++)
|
|
|
|
if (path->p_bh) {
|
|
|
|
brelse(path->p_bh);
|
|
|
|
path->p_bh = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2006-10-11 12:21:07 +04:00
|
|
|
* ext4_ext_binsearch_idx:
|
|
|
|
* binary search for the closest index of the given block
|
2007-07-18 17:19:09 +04:00
|
|
|
* the header must be checked before calling this
|
2006-10-11 12:21:03 +04:00
|
|
|
*/
|
|
|
|
static void
|
2008-01-29 07:58:27 +03:00
|
|
|
ext4_ext_binsearch_idx(struct inode *inode,
|
|
|
|
struct ext4_ext_path *path, ext4_lblk_t block)
|
2006-10-11 12:21:03 +04:00
|
|
|
{
|
|
|
|
struct ext4_extent_header *eh = path->p_hdr;
|
|
|
|
struct ext4_extent_idx *r, *l, *m;
|
|
|
|
|
|
|
|
|
2008-01-29 07:58:27 +03:00
|
|
|
ext_debug("binsearch for %u(idx): ", block);
|
2006-10-11 12:21:03 +04:00
|
|
|
|
|
|
|
l = EXT_FIRST_INDEX(eh) + 1;
|
2007-07-18 17:09:15 +04:00
|
|
|
r = EXT_LAST_INDEX(eh);
|
2006-10-11 12:21:03 +04:00
|
|
|
while (l <= r) {
|
|
|
|
m = l + (r - l) / 2;
|
|
|
|
if (block < le32_to_cpu(m->ei_block))
|
|
|
|
r = m - 1;
|
|
|
|
else
|
|
|
|
l = m + 1;
|
2007-07-18 16:33:37 +04:00
|
|
|
ext_debug("%p(%u):%p(%u):%p(%u) ", l, le32_to_cpu(l->ei_block),
|
|
|
|
m, le32_to_cpu(m->ei_block),
|
|
|
|
r, le32_to_cpu(r->ei_block));
|
2006-10-11 12:21:03 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
path->p_idx = l - 1;
|
2012-05-29 01:55:16 +04:00
|
|
|
ext_debug(" -> %u->%lld ", le32_to_cpu(path->p_idx->ei_block),
|
2010-10-28 05:30:14 +04:00
|
|
|
ext4_idx_pblock(path->p_idx));
|
2006-10-11 12:21:03 +04:00
|
|
|
|
|
|
|
#ifdef CHECK_BINSEARCH
|
|
|
|
{
|
|
|
|
struct ext4_extent_idx *chix, *ix;
|
|
|
|
int k;
|
|
|
|
|
|
|
|
chix = ix = EXT_FIRST_INDEX(eh);
|
|
|
|
for (k = 0; k < le16_to_cpu(eh->eh_entries); k++, ix++) {
|
|
|
|
if (k != 0 &&
|
|
|
|
le32_to_cpu(ix->ei_block) <= le32_to_cpu(ix[-1].ei_block)) {
|
2008-09-09 07:00:52 +04:00
|
|
|
printk(KERN_DEBUG "k=%d, ix=0x%p, "
|
|
|
|
"first=0x%p\n", k,
|
|
|
|
ix, EXT_FIRST_INDEX(eh));
|
|
|
|
printk(KERN_DEBUG "%u <= %u\n",
|
2006-10-11 12:21:03 +04:00
|
|
|
le32_to_cpu(ix->ei_block),
|
|
|
|
le32_to_cpu(ix[-1].ei_block));
|
|
|
|
}
|
|
|
|
BUG_ON(k && le32_to_cpu(ix->ei_block)
|
2007-05-24 21:04:54 +04:00
|
|
|
<= le32_to_cpu(ix[-1].ei_block));
|
2006-10-11 12:21:03 +04:00
|
|
|
if (block < le32_to_cpu(ix->ei_block))
|
|
|
|
break;
|
|
|
|
chix = ix;
|
|
|
|
}
|
|
|
|
BUG_ON(chix != path->p_idx);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2006-10-11 12:21:07 +04:00
|
|
|
* ext4_ext_binsearch:
|
|
|
|
* binary search for closest extent of the given block
|
2007-07-18 17:19:09 +04:00
|
|
|
* the header must be checked before calling this
|
2006-10-11 12:21:03 +04:00
|
|
|
*/
|
|
|
|
static void
|
2008-01-29 07:58:27 +03:00
|
|
|
ext4_ext_binsearch(struct inode *inode,
|
|
|
|
struct ext4_ext_path *path, ext4_lblk_t block)
|
2006-10-11 12:21:03 +04:00
|
|
|
{
|
|
|
|
struct ext4_extent_header *eh = path->p_hdr;
|
|
|
|
struct ext4_extent *r, *l, *m;
|
|
|
|
|
|
|
|
if (eh->eh_entries == 0) {
|
|
|
|
/*
|
2006-10-11 12:21:07 +04:00
|
|
|
* this leaf is empty:
|
|
|
|
* we get such a leaf in split/add case
|
2006-10-11 12:21:03 +04:00
|
|
|
*/
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2008-01-29 07:58:27 +03:00
|
|
|
ext_debug("binsearch for %u: ", block);
|
2006-10-11 12:21:03 +04:00
|
|
|
|
|
|
|
l = EXT_FIRST_EXTENT(eh) + 1;
|
2007-07-18 17:09:15 +04:00
|
|
|
r = EXT_LAST_EXTENT(eh);
|
2006-10-11 12:21:03 +04:00
|
|
|
|
|
|
|
while (l <= r) {
|
|
|
|
m = l + (r - l) / 2;
|
|
|
|
if (block < le32_to_cpu(m->ee_block))
|
|
|
|
r = m - 1;
|
|
|
|
else
|
|
|
|
l = m + 1;
|
2007-07-18 16:33:37 +04:00
|
|
|
ext_debug("%p(%u):%p(%u):%p(%u) ", l, le32_to_cpu(l->ee_block),
|
|
|
|
m, le32_to_cpu(m->ee_block),
|
|
|
|
r, le32_to_cpu(r->ee_block));
|
2006-10-11 12:21:03 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
path->p_ext = l - 1;
|
2009-09-18 21:34:55 +04:00
|
|
|
ext_debug(" -> %d:%llu:[%d]%d ",
|
2007-05-24 21:04:54 +04:00
|
|
|
le32_to_cpu(path->p_ext->ee_block),
|
2010-10-28 05:30:14 +04:00
|
|
|
ext4_ext_pblock(path->p_ext),
|
2014-04-21 07:45:47 +04:00
|
|
|
ext4_ext_is_unwritten(path->p_ext),
|
2007-07-18 05:42:41 +04:00
|
|
|
ext4_ext_get_actual_len(path->p_ext));
|
2006-10-11 12:21:03 +04:00
|
|
|
|
|
|
|
#ifdef CHECK_BINSEARCH
|
|
|
|
{
|
|
|
|
struct ext4_extent *chex, *ex;
|
|
|
|
int k;
|
|
|
|
|
|
|
|
chex = ex = EXT_FIRST_EXTENT(eh);
|
|
|
|
for (k = 0; k < le16_to_cpu(eh->eh_entries); k++, ex++) {
|
|
|
|
BUG_ON(k && le32_to_cpu(ex->ee_block)
|
2007-05-24 21:04:54 +04:00
|
|
|
<= le32_to_cpu(ex[-1].ee_block));
|
2006-10-11 12:21:03 +04:00
|
|
|
if (block < le32_to_cpu(ex->ee_block))
|
|
|
|
break;
|
|
|
|
chex = ex;
|
|
|
|
}
|
|
|
|
BUG_ON(chex != path->p_ext);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
int ext4_ext_tree_init(handle_t *handle, struct inode *inode)
|
|
|
|
{
|
|
|
|
struct ext4_extent_header *eh;
|
|
|
|
|
|
|
|
eh = ext_inode_hdr(inode);
|
|
|
|
eh->eh_depth = 0;
|
|
|
|
eh->eh_entries = 0;
|
|
|
|
eh->eh_magic = EXT4_EXT_MAGIC;
|
2009-08-28 18:40:33 +04:00
|
|
|
eh->eh_max = cpu_to_le16(ext4_ext_space_root(inode, 0));
|
2006-10-11 12:21:03 +04:00
|
|
|
ext4_mark_inode_dirty(handle, inode);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct ext4_ext_path *
|
2014-09-01 22:43:09 +04:00
|
|
|
ext4_find_extent(struct inode *inode, ext4_lblk_t block,
|
|
|
|
struct ext4_ext_path **orig_path, int flags)
|
2006-10-11 12:21:03 +04:00
|
|
|
{
|
|
|
|
struct ext4_extent_header *eh;
|
|
|
|
struct buffer_head *bh;
|
ext4: teach ext4_ext_find_extent() to free path on error
Right now, there are a places where it is all to easy to leak memory
on an error path, via a usage like this:
struct ext4_ext_path *path = NULL
while (...) {
...
path = ext4_ext_find_extent(inode, block, path, 0);
if (IS_ERR(path)) {
/* oops, if path was non-NULL before the call to
ext4_ext_find_extent, we've leaked it! :-( */
...
return PTR_ERR(path);
}
...
}
Unfortunately, there some code paths where we are doing the following
instead:
path = ext4_ext_find_extent(inode, block, orig_path, 0);
and where it's important that we _not_ free orig_path in the case
where ext4_ext_find_extent() returns an error.
So change the function signature of ext4_ext_find_extent() so that it
takes a struct ext4_ext_path ** for its third argument, and by
default, on an error, it will free the struct ext4_ext_path, and then
zero out the struct ext4_ext_path * pointer. In order to avoid
causing problems, we add a flag EXT4_EX_NOFREE_ON_ERR which causes
ext4_ext_find_extent() to use the original behavior of forcing the
caller to deal with freeing the original path pointer on the error
case.
The goal is to get rid of EXT4_EX_NOFREE_ON_ERR entirely, but this
allows for a gentle transition and makes the patches easier to verify.
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
2014-09-01 22:34:09 +04:00
|
|
|
struct ext4_ext_path *path = orig_path ? *orig_path : NULL;
|
|
|
|
short int depth, i, ppos = 0;
|
2013-01-13 01:19:36 +04:00
|
|
|
int ret;
|
2006-10-11 12:21:03 +04:00
|
|
|
|
|
|
|
eh = ext_inode_hdr(inode);
|
2007-07-18 17:19:09 +04:00
|
|
|
depth = ext_depth(inode);
|
2006-10-11 12:21:03 +04:00
|
|
|
|
2014-09-01 22:40:09 +04:00
|
|
|
if (path) {
|
2014-09-01 22:38:09 +04:00
|
|
|
ext4_ext_drop_refs(path);
|
2014-09-01 22:40:09 +04:00
|
|
|
if (depth > path[0].p_maxdepth) {
|
|
|
|
kfree(path);
|
|
|
|
*orig_path = path = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!path) {
|
2014-09-01 22:38:09 +04:00
|
|
|
/* account possible depth increase */
|
2006-12-07 07:41:35 +03:00
|
|
|
path = kzalloc(sizeof(struct ext4_ext_path) * (depth + 2),
|
2006-10-11 12:21:03 +04:00
|
|
|
GFP_NOFS);
|
2014-08-31 23:03:14 +04:00
|
|
|
if (unlikely(!path))
|
2006-10-11 12:21:03 +04:00
|
|
|
return ERR_PTR(-ENOMEM);
|
2014-09-01 22:40:09 +04:00
|
|
|
path[0].p_maxdepth = depth + 1;
|
2006-10-11 12:21:03 +04:00
|
|
|
}
|
|
|
|
path[0].p_hdr = eh;
|
2008-07-12 03:27:31 +04:00
|
|
|
path[0].p_bh = NULL;
|
2006-10-11 12:21:03 +04:00
|
|
|
|
2007-07-18 17:19:09 +04:00
|
|
|
i = depth;
|
2006-10-11 12:21:03 +04:00
|
|
|
/* walk through the tree */
|
|
|
|
while (i) {
|
|
|
|
ext_debug("depth %d: num %d, max %d\n",
|
|
|
|
ppos, le16_to_cpu(eh->eh_entries), le16_to_cpu(eh->eh_max));
|
2007-07-18 17:19:09 +04:00
|
|
|
|
2006-10-11 12:21:03 +04:00
|
|
|
ext4_ext_binsearch_idx(inode, path + ppos, block);
|
2010-10-28 05:30:14 +04:00
|
|
|
path[ppos].p_block = ext4_idx_pblock(path[ppos].p_idx);
|
2006-10-11 12:21:03 +04:00
|
|
|
path[ppos].p_depth = i;
|
|
|
|
path[ppos].p_ext = NULL;
|
|
|
|
|
2013-08-17 05:23:41 +04:00
|
|
|
bh = read_extent_tree_block(inode, path[ppos].p_block, --i,
|
|
|
|
flags);
|
2015-08-12 13:29:44 +03:00
|
|
|
if (IS_ERR(bh)) {
|
2013-08-17 05:20:41 +04:00
|
|
|
ret = PTR_ERR(bh);
|
2006-10-11 12:21:03 +04:00
|
|
|
goto err;
|
2013-01-13 01:19:36 +04:00
|
|
|
}
|
2013-08-17 05:20:41 +04:00
|
|
|
|
2006-10-11 12:21:03 +04:00
|
|
|
eh = ext_block_hdr(bh);
|
|
|
|
ppos++;
|
2010-03-02 19:46:09 +03:00
|
|
|
if (unlikely(ppos > depth)) {
|
|
|
|
put_bh(bh);
|
|
|
|
EXT4_ERROR_INODE(inode,
|
|
|
|
"ppos %d > depth %d", ppos, depth);
|
2015-10-17 23:16:04 +03:00
|
|
|
ret = -EFSCORRUPTED;
|
2010-03-02 19:46:09 +03:00
|
|
|
goto err;
|
|
|
|
}
|
2006-10-11 12:21:03 +04:00
|
|
|
path[ppos].p_bh = bh;
|
|
|
|
path[ppos].p_hdr = eh;
|
|
|
|
}
|
|
|
|
|
|
|
|
path[ppos].p_depth = i;
|
|
|
|
path[ppos].p_ext = NULL;
|
|
|
|
path[ppos].p_idx = NULL;
|
|
|
|
|
|
|
|
/* find extent */
|
|
|
|
ext4_ext_binsearch(inode, path + ppos, block);
|
2008-07-12 03:27:31 +04:00
|
|
|
/* if not an empty leaf */
|
|
|
|
if (path[ppos].p_ext)
|
2010-10-28 05:30:14 +04:00
|
|
|
path[ppos].p_block = ext4_ext_pblock(path[ppos].p_ext);
|
2006-10-11 12:21:03 +04:00
|
|
|
|
|
|
|
ext4_ext_show_path(inode, path);
|
|
|
|
|
|
|
|
return path;
|
|
|
|
|
|
|
|
err:
|
|
|
|
ext4_ext_drop_refs(path);
|
2014-09-01 22:37:09 +04:00
|
|
|
kfree(path);
|
|
|
|
if (orig_path)
|
|
|
|
*orig_path = NULL;
|
2013-01-13 01:19:36 +04:00
|
|
|
return ERR_PTR(ret);
|
2006-10-11 12:21:03 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2006-10-11 12:21:07 +04:00
|
|
|
* ext4_ext_insert_index:
|
|
|
|
* insert new index [@logical;@ptr] into the block at @curp;
|
|
|
|
* check where to insert: before @curp or after @curp
|
2006-10-11 12:21:03 +04:00
|
|
|
*/
|
2010-10-28 05:30:14 +04:00
|
|
|
static int ext4_ext_insert_index(handle_t *handle, struct inode *inode,
|
|
|
|
struct ext4_ext_path *curp,
|
|
|
|
int logical, ext4_fsblk_t ptr)
|
2006-10-11 12:21:03 +04:00
|
|
|
{
|
|
|
|
struct ext4_extent_idx *ix;
|
|
|
|
int len, err;
|
|
|
|
|
2006-12-07 07:41:33 +03:00
|
|
|
err = ext4_ext_get_access(handle, inode, curp);
|
|
|
|
if (err)
|
2006-10-11 12:21:03 +04:00
|
|
|
return err;
|
|
|
|
|
2010-03-02 19:46:09 +03:00
|
|
|
if (unlikely(logical == le32_to_cpu(curp->p_idx->ei_block))) {
|
|
|
|
EXT4_ERROR_INODE(inode,
|
|
|
|
"logical %d == ei_block %d!",
|
|
|
|
logical, le32_to_cpu(curp->p_idx->ei_block));
|
2015-10-17 23:16:04 +03:00
|
|
|
return -EFSCORRUPTED;
|
2010-03-02 19:46:09 +03:00
|
|
|
}
|
2011-07-18 07:43:42 +04:00
|
|
|
|
|
|
|
if (unlikely(le16_to_cpu(curp->p_hdr->eh_entries)
|
|
|
|
>= le16_to_cpu(curp->p_hdr->eh_max))) {
|
|
|
|
EXT4_ERROR_INODE(inode,
|
|
|
|
"eh_entries %d >= eh_max %d!",
|
|
|
|
le16_to_cpu(curp->p_hdr->eh_entries),
|
|
|
|
le16_to_cpu(curp->p_hdr->eh_max));
|
2015-10-17 23:16:04 +03:00
|
|
|
return -EFSCORRUPTED;
|
2011-07-18 07:43:42 +04:00
|
|
|
}
|
|
|
|
|
2006-10-11 12:21:03 +04:00
|
|
|
if (logical > le32_to_cpu(curp->p_idx->ei_block)) {
|
|
|
|
/* insert after */
|
2011-10-27 19:52:18 +04:00
|
|
|
ext_debug("insert new index %d after: %llu\n", logical, ptr);
|
2006-10-11 12:21:03 +04:00
|
|
|
ix = curp->p_idx + 1;
|
|
|
|
} else {
|
|
|
|
/* insert before */
|
2011-10-27 19:52:18 +04:00
|
|
|
ext_debug("insert new index %d before: %llu\n", logical, ptr);
|
2006-10-11 12:21:03 +04:00
|
|
|
ix = curp->p_idx;
|
|
|
|
}
|
|
|
|
|
2011-10-27 19:52:18 +04:00
|
|
|
len = EXT_LAST_INDEX(curp->p_hdr) - ix + 1;
|
|
|
|
BUG_ON(len < 0);
|
|
|
|
if (len > 0) {
|
|
|
|
ext_debug("insert new index %d: "
|
|
|
|
"move %d indices from 0x%p to 0x%p\n",
|
|
|
|
logical, len, ix, ix + 1);
|
|
|
|
memmove(ix + 1, ix, len * sizeof(struct ext4_extent_idx));
|
|
|
|
}
|
|
|
|
|
2011-10-17 18:13:46 +04:00
|
|
|
if (unlikely(ix > EXT_MAX_INDEX(curp->p_hdr))) {
|
|
|
|
EXT4_ERROR_INODE(inode, "ix > EXT_MAX_INDEX!");
|
2015-10-17 23:16:04 +03:00
|
|
|
return -EFSCORRUPTED;
|
2011-10-17 18:13:46 +04:00
|
|
|
}
|
|
|
|
|
2006-10-11 12:21:03 +04:00
|
|
|
ix->ei_block = cpu_to_le32(logical);
|
2006-10-11 12:21:05 +04:00
|
|
|
ext4_idx_store_pblock(ix, ptr);
|
2008-04-17 18:38:59 +04:00
|
|
|
le16_add_cpu(&curp->p_hdr->eh_entries, 1);
|
2006-10-11 12:21:03 +04:00
|
|
|
|
2010-03-02 19:46:09 +03:00
|
|
|
if (unlikely(ix > EXT_LAST_INDEX(curp->p_hdr))) {
|
|
|
|
EXT4_ERROR_INODE(inode, "ix > EXT_LAST_INDEX!");
|
2015-10-17 23:16:04 +03:00
|
|
|
return -EFSCORRUPTED;
|
2010-03-02 19:46:09 +03:00
|
|
|
}
|
2006-10-11 12:21:03 +04:00
|
|
|
|
|
|
|
err = ext4_ext_dirty(handle, inode, curp);
|
|
|
|
ext4_std_error(inode->i_sb, err);
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2006-10-11 12:21:07 +04:00
|
|
|
* ext4_ext_split:
|
|
|
|
* inserts new subtree into the path, using free index entry
|
|
|
|
* at depth @at:
|
|
|
|
* - allocates all needed blocks (new leaf and all intermediate index blocks)
|
|
|
|
* - makes decision where to split
|
|
|
|
* - moves remaining extents and index entries (right to the split point)
|
|
|
|
* into the newly allocated blocks
|
|
|
|
* - initializes subtree
|
2006-10-11 12:21:03 +04:00
|
|
|
*/
|
|
|
|
static int ext4_ext_split(handle_t *handle, struct inode *inode,
|
2011-05-25 15:41:26 +04:00
|
|
|
unsigned int flags,
|
|
|
|
struct ext4_ext_path *path,
|
|
|
|
struct ext4_extent *newext, int at)
|
2006-10-11 12:21:03 +04:00
|
|
|
{
|
|
|
|
struct buffer_head *bh = NULL;
|
|
|
|
int depth = ext_depth(inode);
|
|
|
|
struct ext4_extent_header *neh;
|
|
|
|
struct ext4_extent_idx *fidx;
|
|
|
|
int i = at, k, m, a;
|
2006-10-11 12:21:05 +04:00
|
|
|
ext4_fsblk_t newblock, oldblock;
|
2006-10-11 12:21:03 +04:00
|
|
|
__le32 border;
|
2006-10-11 12:21:05 +04:00
|
|
|
ext4_fsblk_t *ablocks = NULL; /* array of allocated blocks */
|
2006-10-11 12:21:03 +04:00
|
|
|
int err = 0;
|
|
|
|
|
|
|
|
/* make decision: where to split? */
|
2006-10-11 12:21:07 +04:00
|
|
|
/* FIXME: now decision is simplest: at current extent */
|
2006-10-11 12:21:03 +04:00
|
|
|
|
2006-10-11 12:21:07 +04:00
|
|
|
/* if current leaf will be split, then we should use
|
2006-10-11 12:21:03 +04:00
|
|
|
* border from split point */
|
2010-03-02 19:46:09 +03:00
|
|
|
if (unlikely(path[depth].p_ext > EXT_MAX_EXTENT(path[depth].p_hdr))) {
|
|
|
|
EXT4_ERROR_INODE(inode, "p_ext > EXT_MAX_EXTENT!");
|
2015-10-17 23:16:04 +03:00
|
|
|
return -EFSCORRUPTED;
|
2010-03-02 19:46:09 +03:00
|
|
|
}
|
2006-10-11 12:21:03 +04:00
|
|
|
if (path[depth].p_ext != EXT_MAX_EXTENT(path[depth].p_hdr)) {
|
|
|
|
border = path[depth].p_ext[1].ee_block;
|
2006-10-11 12:21:07 +04:00
|
|
|
ext_debug("leaf will be split."
|
2006-10-11 12:21:03 +04:00
|
|
|
" next leaf starts at %d\n",
|
2007-05-24 21:04:54 +04:00
|
|
|
le32_to_cpu(border));
|
2006-10-11 12:21:03 +04:00
|
|
|
} else {
|
|
|
|
border = newext->ee_block;
|
|
|
|
ext_debug("leaf will be added."
|
|
|
|
" next leaf starts at %d\n",
|
2007-05-24 21:04:54 +04:00
|
|
|
le32_to_cpu(border));
|
2006-10-11 12:21:03 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2006-10-11 12:21:07 +04:00
|
|
|
* If error occurs, then we break processing
|
|
|
|
* and mark filesystem read-only. index won't
|
2006-10-11 12:21:03 +04:00
|
|
|
* be inserted and tree will be in consistent
|
2006-10-11 12:21:07 +04:00
|
|
|
* state. Next mount will repair buffers too.
|
2006-10-11 12:21:03 +04:00
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2006-10-11 12:21:07 +04:00
|
|
|
* Get array to track all allocated blocks.
|
|
|
|
* We need this to handle errors and free blocks
|
|
|
|
* upon them.
|
2006-10-11 12:21:03 +04:00
|
|
|
*/
|
2006-12-07 07:41:35 +03:00
|
|
|
ablocks = kzalloc(sizeof(ext4_fsblk_t) * depth, GFP_NOFS);
|
2006-10-11 12:21:03 +04:00
|
|
|
if (!ablocks)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
/* allocate all needed blocks */
|
|
|
|
ext_debug("allocate %d blocks for indexes/leaf\n", depth - at);
|
|
|
|
for (a = 0; a < depth - at; a++) {
|
2008-07-12 03:27:31 +04:00
|
|
|
newblock = ext4_ext_new_meta_block(handle, inode, path,
|
2011-05-25 15:41:26 +04:00
|
|
|
newext, &err, flags);
|
2006-10-11 12:21:03 +04:00
|
|
|
if (newblock == 0)
|
|
|
|
goto cleanup;
|
|
|
|
ablocks[a] = newblock;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* initialize new leaf */
|
|
|
|
newblock = ablocks[--a];
|
2010-03-02 19:46:09 +03:00
|
|
|
if (unlikely(newblock == 0)) {
|
|
|
|
EXT4_ERROR_INODE(inode, "newblock == 0!");
|
2015-10-17 23:16:04 +03:00
|
|
|
err = -EFSCORRUPTED;
|
2010-03-02 19:46:09 +03:00
|
|
|
goto cleanup;
|
|
|
|
}
|
2015-07-02 08:34:07 +03:00
|
|
|
bh = sb_getblk_gfp(inode->i_sb, newblock, __GFP_MOVABLE | GFP_NOFS);
|
2013-01-13 01:28:47 +04:00
|
|
|
if (unlikely(!bh)) {
|
2013-01-13 01:19:36 +04:00
|
|
|
err = -ENOMEM;
|
2006-10-11 12:21:03 +04:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
lock_buffer(bh);
|
|
|
|
|
2006-12-07 07:41:33 +03:00
|
|
|
err = ext4_journal_get_create_access(handle, bh);
|
|
|
|
if (err)
|
2006-10-11 12:21:03 +04:00
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
neh = ext_block_hdr(bh);
|
|
|
|
neh->eh_entries = 0;
|
2009-08-28 18:40:33 +04:00
|
|
|
neh->eh_max = cpu_to_le16(ext4_ext_space_block(inode, 0));
|
2006-10-11 12:21:03 +04:00
|
|
|
neh->eh_magic = EXT4_EXT_MAGIC;
|
|
|
|
neh->eh_depth = 0;
|
|
|
|
|
2006-10-11 12:21:07 +04:00
|
|
|
/* move remainder of path[depth] to the new leaf */
|
2010-03-02 19:46:09 +03:00
|
|
|
if (unlikely(path[depth].p_hdr->eh_entries !=
|
|
|
|
path[depth].p_hdr->eh_max)) {
|
|
|
|
EXT4_ERROR_INODE(inode, "eh_entries %d != eh_max %d!",
|
|
|
|
path[depth].p_hdr->eh_entries,
|
|
|
|
path[depth].p_hdr->eh_max);
|
2015-10-17 23:16:04 +03:00
|
|
|
err = -EFSCORRUPTED;
|
2010-03-02 19:46:09 +03:00
|
|
|
goto cleanup;
|
|
|
|
}
|
2006-10-11 12:21:03 +04:00
|
|
|
/* start copy from next extent */
|
2011-05-26 01:41:48 +04:00
|
|
|
m = EXT_MAX_EXTENT(path[depth].p_hdr) - path[depth].p_ext++;
|
|
|
|
ext4_ext_show_move(inode, path, newblock, depth);
|
2006-10-11 12:21:03 +04:00
|
|
|
if (m) {
|
2011-05-26 01:41:48 +04:00
|
|
|
struct ext4_extent *ex;
|
|
|
|
ex = EXT_FIRST_EXTENT(neh);
|
|
|
|
memmove(ex, path[depth].p_ext, sizeof(struct ext4_extent) * m);
|
2008-04-17 18:38:59 +04:00
|
|
|
le16_add_cpu(&neh->eh_entries, m);
|
2006-10-11 12:21:03 +04:00
|
|
|
}
|
|
|
|
|
2012-04-30 02:37:10 +04:00
|
|
|
ext4_extent_block_csum_set(inode, neh);
|
2006-10-11 12:21:03 +04:00
|
|
|
set_buffer_uptodate(bh);
|
|
|
|
unlock_buffer(bh);
|
|
|
|
|
2009-01-07 08:06:22 +03:00
|
|
|
err = ext4_handle_dirty_metadata(handle, inode, bh);
|
2006-12-07 07:41:33 +03:00
|
|
|
if (err)
|
2006-10-11 12:21:03 +04:00
|
|
|
goto cleanup;
|
|
|
|
brelse(bh);
|
|
|
|
bh = NULL;
|
|
|
|
|
|
|
|
/* correct old leaf */
|
|
|
|
if (m) {
|
2006-12-07 07:41:33 +03:00
|
|
|
err = ext4_ext_get_access(handle, inode, path + depth);
|
|
|
|
if (err)
|
2006-10-11 12:21:03 +04:00
|
|
|
goto cleanup;
|
2008-04-17 18:38:59 +04:00
|
|
|
le16_add_cpu(&path[depth].p_hdr->eh_entries, -m);
|
2006-12-07 07:41:33 +03:00
|
|
|
err = ext4_ext_dirty(handle, inode, path + depth);
|
|
|
|
if (err)
|
2006-10-11 12:21:03 +04:00
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/* create intermediate indexes */
|
|
|
|
k = depth - at - 1;
|
2010-03-02 19:46:09 +03:00
|
|
|
if (unlikely(k < 0)) {
|
|
|
|
EXT4_ERROR_INODE(inode, "k %d < 0!", k);
|
2015-10-17 23:16:04 +03:00
|
|
|
err = -EFSCORRUPTED;
|
2010-03-02 19:46:09 +03:00
|
|
|
goto cleanup;
|
|
|
|
}
|
2006-10-11 12:21:03 +04:00
|
|
|
if (k)
|
|
|
|
ext_debug("create %d intermediate indices\n", k);
|
|
|
|
/* insert new index into current index block */
|
|
|
|
/* current depth stored in i var */
|
|
|
|
i = depth - 1;
|
|
|
|
while (k--) {
|
|
|
|
oldblock = newblock;
|
|
|
|
newblock = ablocks[--a];
|
2008-01-29 07:58:27 +03:00
|
|
|
bh = sb_getblk(inode->i_sb, newblock);
|
2013-01-13 01:28:47 +04:00
|
|
|
if (unlikely(!bh)) {
|
2013-01-13 01:19:36 +04:00
|
|
|
err = -ENOMEM;
|
2006-10-11 12:21:03 +04:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
lock_buffer(bh);
|
|
|
|
|
2006-12-07 07:41:33 +03:00
|
|
|
err = ext4_journal_get_create_access(handle, bh);
|
|
|
|
if (err)
|
2006-10-11 12:21:03 +04:00
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
neh = ext_block_hdr(bh);
|
|
|
|
neh->eh_entries = cpu_to_le16(1);
|
|
|
|
neh->eh_magic = EXT4_EXT_MAGIC;
|
2009-08-28 18:40:33 +04:00
|
|
|
neh->eh_max = cpu_to_le16(ext4_ext_space_block_idx(inode, 0));
|
2006-10-11 12:21:03 +04:00
|
|
|
neh->eh_depth = cpu_to_le16(depth - i);
|
|
|
|
fidx = EXT_FIRST_INDEX(neh);
|
|
|
|
fidx->ei_block = border;
|
2006-10-11 12:21:05 +04:00
|
|
|
ext4_idx_store_pblock(fidx, oldblock);
|
2006-10-11 12:21:03 +04:00
|
|
|
|
2008-01-29 07:58:27 +03:00
|
|
|
ext_debug("int.index at %d (block %llu): %u -> %llu\n",
|
|
|
|
i, newblock, le32_to_cpu(border), oldblock);
|
2006-10-11 12:21:03 +04:00
|
|
|
|
2011-05-26 01:41:48 +04:00
|
|
|
/* move remainder of path[i] to the new index block */
|
2010-03-02 19:46:09 +03:00
|
|
|
if (unlikely(EXT_MAX_INDEX(path[i].p_hdr) !=
|
|
|
|
EXT_LAST_INDEX(path[i].p_hdr))) {
|
|
|
|
EXT4_ERROR_INODE(inode,
|
|
|
|
"EXT_MAX_INDEX != EXT_LAST_INDEX ee_block %d!",
|
|
|
|
le32_to_cpu(path[i].p_ext->ee_block));
|
2015-10-17 23:16:04 +03:00
|
|
|
err = -EFSCORRUPTED;
|
2010-03-02 19:46:09 +03:00
|
|
|
goto cleanup;
|
|
|
|
}
|
2011-05-26 01:41:48 +04:00
|
|
|
/* start copy indexes */
|
|
|
|
m = EXT_MAX_INDEX(path[i].p_hdr) - path[i].p_idx++;
|
|
|
|
ext_debug("cur 0x%p, last 0x%p\n", path[i].p_idx,
|
|
|
|
EXT_MAX_INDEX(path[i].p_hdr));
|
|
|
|
ext4_ext_show_move(inode, path, newblock, i);
|
2006-10-11 12:21:03 +04:00
|
|
|
if (m) {
|
2011-05-26 01:41:48 +04:00
|
|
|
memmove(++fidx, path[i].p_idx,
|
2006-10-11 12:21:03 +04:00
|
|
|
sizeof(struct ext4_extent_idx) * m);
|
2008-04-17 18:38:59 +04:00
|
|
|
le16_add_cpu(&neh->eh_entries, m);
|
2006-10-11 12:21:03 +04:00
|
|
|
}
|
2012-04-30 02:37:10 +04:00
|
|
|
ext4_extent_block_csum_set(inode, neh);
|
2006-10-11 12:21:03 +04:00
|
|
|
set_buffer_uptodate(bh);
|
|
|
|
unlock_buffer(bh);
|
|
|
|
|
2009-01-07 08:06:22 +03:00
|
|
|
err = ext4_handle_dirty_metadata(handle, inode, bh);
|
2006-12-07 07:41:33 +03:00
|
|
|
if (err)
|
2006-10-11 12:21:03 +04:00
|
|
|
goto cleanup;
|
|
|
|
brelse(bh);
|
|
|
|
bh = NULL;
|
|
|
|
|
|
|
|
/* correct old index */
|
|
|
|
if (m) {
|
|
|
|
err = ext4_ext_get_access(handle, inode, path + i);
|
|
|
|
if (err)
|
|
|
|
goto cleanup;
|
2008-04-17 18:38:59 +04:00
|
|
|
le16_add_cpu(&path[i].p_hdr->eh_entries, -m);
|
2006-10-11 12:21:03 +04:00
|
|
|
err = ext4_ext_dirty(handle, inode, path + i);
|
|
|
|
if (err)
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
i--;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* insert new index */
|
|
|
|
err = ext4_ext_insert_index(handle, inode, path + at,
|
|
|
|
le32_to_cpu(border), newblock);
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
if (bh) {
|
|
|
|
if (buffer_locked(bh))
|
|
|
|
unlock_buffer(bh);
|
|
|
|
brelse(bh);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (err) {
|
|
|
|
/* free all allocated blocks in error case */
|
|
|
|
for (i = 0; i < depth; i++) {
|
|
|
|
if (!ablocks[i])
|
|
|
|
continue;
|
2011-02-22 05:01:42 +03:00
|
|
|
ext4_free_blocks(handle, inode, NULL, ablocks[i], 1,
|
2009-11-23 15:17:05 +03:00
|
|
|
EXT4_FREE_BLOCKS_METADATA);
|
2006-10-11 12:21:03 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
kfree(ablocks);
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2006-10-11 12:21:07 +04:00
|
|
|
* ext4_ext_grow_indepth:
|
|
|
|
* implements tree growing procedure:
|
|
|
|
* - allocates new block
|
|
|
|
* - moves top-level data (index block or leaf) into the new block
|
|
|
|
* - initializes new top-level, creating index that points to the
|
|
|
|
* just created block
|
2006-10-11 12:21:03 +04:00
|
|
|
*/
|
|
|
|
static int ext4_ext_grow_indepth(handle_t *handle, struct inode *inode,
|
2014-10-02 06:57:09 +04:00
|
|
|
unsigned int flags)
|
2006-10-11 12:21:03 +04:00
|
|
|
{
|
|
|
|
struct ext4_extent_header *neh;
|
|
|
|
struct buffer_head *bh;
|
2014-10-02 06:57:09 +04:00
|
|
|
ext4_fsblk_t newblock, goal = 0;
|
|
|
|
struct ext4_super_block *es = EXT4_SB(inode->i_sb)->s_es;
|
2006-10-11 12:21:03 +04:00
|
|
|
int err = 0;
|
|
|
|
|
2014-10-02 06:57:09 +04:00
|
|
|
/* Try to prepend new index to old one */
|
|
|
|
if (ext_depth(inode))
|
|
|
|
goal = ext4_idx_pblock(EXT_FIRST_INDEX(ext_inode_hdr(inode)));
|
|
|
|
if (goal > le32_to_cpu(es->s_first_data_block)) {
|
|
|
|
flags |= EXT4_MB_HINT_TRY_GOAL;
|
|
|
|
goal--;
|
|
|
|
} else
|
|
|
|
goal = ext4_inode_to_goal_block(inode);
|
|
|
|
newblock = ext4_new_meta_blocks(handle, inode, goal, flags,
|
|
|
|
NULL, &err);
|
2006-10-11 12:21:03 +04:00
|
|
|
if (newblock == 0)
|
|
|
|
return err;
|
|
|
|
|
2015-07-02 08:34:07 +03:00
|
|
|
bh = sb_getblk_gfp(inode->i_sb, newblock, __GFP_MOVABLE | GFP_NOFS);
|
2013-01-13 01:28:47 +04:00
|
|
|
if (unlikely(!bh))
|
2013-01-13 01:19:36 +04:00
|
|
|
return -ENOMEM;
|
2006-10-11 12:21:03 +04:00
|
|
|
lock_buffer(bh);
|
|
|
|
|
2006-12-07 07:41:33 +03:00
|
|
|
err = ext4_journal_get_create_access(handle, bh);
|
|
|
|
if (err) {
|
2006-10-11 12:21:03 +04:00
|
|
|
unlock_buffer(bh);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* move top-level index/leaf into new block */
|
2011-10-22 09:26:05 +04:00
|
|
|
memmove(bh->b_data, EXT4_I(inode)->i_data,
|
|
|
|
sizeof(EXT4_I(inode)->i_data));
|
2006-10-11 12:21:03 +04:00
|
|
|
|
|
|
|
/* set size of new block */
|
|
|
|
neh = ext_block_hdr(bh);
|
|
|
|
/* old root could have indexes or leaves
|
|
|
|
* so calculate e_max right way */
|
|
|
|
if (ext_depth(inode))
|
2009-08-28 18:40:33 +04:00
|
|
|
neh->eh_max = cpu_to_le16(ext4_ext_space_block_idx(inode, 0));
|
2006-10-11 12:21:03 +04:00
|
|
|
else
|
2009-08-28 18:40:33 +04:00
|
|
|
neh->eh_max = cpu_to_le16(ext4_ext_space_block(inode, 0));
|
2006-10-11 12:21:03 +04:00
|
|
|
neh->eh_magic = EXT4_EXT_MAGIC;
|
2012-04-30 02:37:10 +04:00
|
|
|
ext4_extent_block_csum_set(inode, neh);
|
2006-10-11 12:21:03 +04:00
|
|
|
set_buffer_uptodate(bh);
|
|
|
|
unlock_buffer(bh);
|
|
|
|
|
2009-01-07 08:06:22 +03:00
|
|
|
err = ext4_handle_dirty_metadata(handle, inode, bh);
|
2006-12-07 07:41:33 +03:00
|
|
|
if (err)
|
2006-10-11 12:21:03 +04:00
|
|
|
goto out;
|
|
|
|
|
2011-10-22 09:26:05 +04:00
|
|
|
/* Update top-level index: num,max,pointer */
|
2006-10-11 12:21:03 +04:00
|
|
|
neh = ext_inode_hdr(inode);
|
2011-10-22 09:26:05 +04:00
|
|
|
neh->eh_entries = cpu_to_le16(1);
|
|
|
|
ext4_idx_store_pblock(EXT_FIRST_INDEX(neh), newblock);
|
|
|
|
if (neh->eh_depth == 0) {
|
|
|
|
/* Root extent block becomes index block */
|
|
|
|
neh->eh_max = cpu_to_le16(ext4_ext_space_root_idx(inode, 0));
|
|
|
|
EXT_FIRST_INDEX(neh)->ei_block =
|
|
|
|
EXT_FIRST_EXTENT(neh)->ee_block;
|
|
|
|
}
|
2006-10-11 12:21:11 +04:00
|
|
|
ext_debug("new root: num %d(%d), lblock %d, ptr %llu\n",
|
2006-10-11 12:21:03 +04:00
|
|
|
le16_to_cpu(neh->eh_entries), le16_to_cpu(neh->eh_max),
|
2010-06-14 21:28:03 +04:00
|
|
|
le32_to_cpu(EXT_FIRST_INDEX(neh)->ei_block),
|
2010-10-28 05:30:14 +04:00
|
|
|
ext4_idx_pblock(EXT_FIRST_INDEX(neh)));
|
2006-10-11 12:21:03 +04:00
|
|
|
|
2012-09-27 17:37:53 +04:00
|
|
|
le16_add_cpu(&neh->eh_depth, 1);
|
2011-10-22 09:26:05 +04:00
|
|
|
ext4_mark_inode_dirty(handle, inode);
|
2006-10-11 12:21:03 +04:00
|
|
|
out:
|
|
|
|
brelse(bh);
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2006-10-11 12:21:07 +04:00
|
|
|
* ext4_ext_create_new_leaf:
|
|
|
|
* finds empty index and adds new leaf.
|
|
|
|
* if no free index is found, then it requests in-depth growing.
|
2006-10-11 12:21:03 +04:00
|
|
|
*/
|
|
|
|
static int ext4_ext_create_new_leaf(handle_t *handle, struct inode *inode,
|
2013-08-17 05:23:41 +04:00
|
|
|
unsigned int mb_flags,
|
|
|
|
unsigned int gb_flags,
|
2014-09-01 22:37:09 +04:00
|
|
|
struct ext4_ext_path **ppath,
|
2011-05-25 15:41:26 +04:00
|
|
|
struct ext4_extent *newext)
|
2006-10-11 12:21:03 +04:00
|
|
|
{
|
2014-09-01 22:37:09 +04:00
|
|
|
struct ext4_ext_path *path = *ppath;
|
2006-10-11 12:21:03 +04:00
|
|
|
struct ext4_ext_path *curp;
|
|
|
|
int depth, i, err = 0;
|
|
|
|
|
|
|
|
repeat:
|
|
|
|
i = depth = ext_depth(inode);
|
|
|
|
|
|
|
|
/* walk up to the tree and look for free index entry */
|
|
|
|
curp = path + depth;
|
|
|
|
while (i > 0 && !EXT_HAS_FREE_INDEX(curp)) {
|
|
|
|
i--;
|
|
|
|
curp--;
|
|
|
|
}
|
|
|
|
|
2006-10-11 12:21:07 +04:00
|
|
|
/* we use already allocated block for index block,
|
|
|
|
* so subsequent data blocks should be contiguous */
|
2006-10-11 12:21:03 +04:00
|
|
|
if (EXT_HAS_FREE_INDEX(curp)) {
|
|
|
|
/* if we found index with free entry, then use that
|
|
|
|
* entry: create all needed subtree and add new leaf */
|
2013-08-17 05:23:41 +04:00
|
|
|
err = ext4_ext_split(handle, inode, mb_flags, path, newext, i);
|
2008-07-12 03:27:31 +04:00
|
|
|
if (err)
|
|
|
|
goto out;
|
2006-10-11 12:21:03 +04:00
|
|
|
|
|
|
|
/* refill path */
|
2014-09-01 22:43:09 +04:00
|
|
|
path = ext4_find_extent(inode,
|
2008-01-29 07:58:27 +03:00
|
|
|
(ext4_lblk_t)le32_to_cpu(newext->ee_block),
|
2014-09-01 22:37:09 +04:00
|
|
|
ppath, gb_flags);
|
2006-10-11 12:21:03 +04:00
|
|
|
if (IS_ERR(path))
|
|
|
|
err = PTR_ERR(path);
|
|
|
|
} else {
|
|
|
|
/* tree is full, time to grow in depth */
|
2014-10-02 06:57:09 +04:00
|
|
|
err = ext4_ext_grow_indepth(handle, inode, mb_flags);
|
2006-10-11 12:21:03 +04:00
|
|
|
if (err)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
/* refill path */
|
2014-09-01 22:43:09 +04:00
|
|
|
path = ext4_find_extent(inode,
|
2008-01-29 07:58:27 +03:00
|
|
|
(ext4_lblk_t)le32_to_cpu(newext->ee_block),
|
2014-09-01 22:37:09 +04:00
|
|
|
ppath, gb_flags);
|
2006-10-11 12:21:03 +04:00
|
|
|
if (IS_ERR(path)) {
|
|
|
|
err = PTR_ERR(path);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2006-10-11 12:21:07 +04:00
|
|
|
* only first (depth 0 -> 1) produces free space;
|
|
|
|
* in all other cases we have to split the grown tree
|
2006-10-11 12:21:03 +04:00
|
|
|
*/
|
|
|
|
depth = ext_depth(inode);
|
|
|
|
if (path[depth].p_hdr->eh_entries == path[depth].p_hdr->eh_max) {
|
2006-10-11 12:21:07 +04:00
|
|
|
/* now we need to split */
|
2006-10-11 12:21:03 +04:00
|
|
|
goto repeat;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2008-01-29 07:58:27 +03:00
|
|
|
/*
|
|
|
|
* search the closest allocated block to the left for *logical
|
|
|
|
* and returns it at @logical + it's physical address at @phys
|
|
|
|
* if *logical is the smallest allocated block, the function
|
|
|
|
* returns 0 at @phys
|
|
|
|
* return value contains 0 (success) or error code
|
|
|
|
*/
|
2010-10-28 05:30:14 +04:00
|
|
|
static int ext4_ext_search_left(struct inode *inode,
|
|
|
|
struct ext4_ext_path *path,
|
|
|
|
ext4_lblk_t *logical, ext4_fsblk_t *phys)
|
2008-01-29 07:58:27 +03:00
|
|
|
{
|
|
|
|
struct ext4_extent_idx *ix;
|
|
|
|
struct ext4_extent *ex;
|
2008-01-29 07:58:27 +03:00
|
|
|
int depth, ee_len;
|
2008-01-29 07:58:27 +03:00
|
|
|
|
2010-03-02 19:46:09 +03:00
|
|
|
if (unlikely(path == NULL)) {
|
|
|
|
EXT4_ERROR_INODE(inode, "path == NULL *logical %d!", *logical);
|
2015-10-17 23:16:04 +03:00
|
|
|
return -EFSCORRUPTED;
|
2010-03-02 19:46:09 +03:00
|
|
|
}
|
2008-01-29 07:58:27 +03:00
|
|
|
depth = path->p_depth;
|
|
|
|
*phys = 0;
|
|
|
|
|
|
|
|
if (depth == 0 && path->p_ext == NULL)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* usually extent in the path covers blocks smaller
|
|
|
|
* then *logical, but it can be that extent is the
|
|
|
|
* first one in the file */
|
|
|
|
|
|
|
|
ex = path[depth].p_ext;
|
2008-01-29 07:58:27 +03:00
|
|
|
ee_len = ext4_ext_get_actual_len(ex);
|
2008-01-29 07:58:27 +03:00
|
|
|
if (*logical < le32_to_cpu(ex->ee_block)) {
|
2010-03-02 19:46:09 +03:00
|
|
|
if (unlikely(EXT_FIRST_EXTENT(path[depth].p_hdr) != ex)) {
|
|
|
|
EXT4_ERROR_INODE(inode,
|
|
|
|
"EXT_FIRST_EXTENT != ex *logical %d ee_block %d!",
|
|
|
|
*logical, le32_to_cpu(ex->ee_block));
|
2015-10-17 23:16:04 +03:00
|
|
|
return -EFSCORRUPTED;
|
2010-03-02 19:46:09 +03:00
|
|
|
}
|
2008-01-29 07:58:27 +03:00
|
|
|
while (--depth >= 0) {
|
|
|
|
ix = path[depth].p_idx;
|
2010-03-02 19:46:09 +03:00
|
|
|
if (unlikely(ix != EXT_FIRST_INDEX(path[depth].p_hdr))) {
|
|
|
|
EXT4_ERROR_INODE(inode,
|
|
|
|
"ix (%d) != EXT_FIRST_INDEX (%d) (depth %d)!",
|
2011-10-09 00:08:34 +04:00
|
|
|
ix != NULL ? le32_to_cpu(ix->ei_block) : 0,
|
2010-03-02 19:46:09 +03:00
|
|
|
EXT_FIRST_INDEX(path[depth].p_hdr) != NULL ?
|
2011-10-09 00:08:34 +04:00
|
|
|
le32_to_cpu(EXT_FIRST_INDEX(path[depth].p_hdr)->ei_block) : 0,
|
2010-03-02 19:46:09 +03:00
|
|
|
depth);
|
2015-10-17 23:16:04 +03:00
|
|
|
return -EFSCORRUPTED;
|
2010-03-02 19:46:09 +03:00
|
|
|
}
|
2008-01-29 07:58:27 +03:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-03-02 19:46:09 +03:00
|
|
|
if (unlikely(*logical < (le32_to_cpu(ex->ee_block) + ee_len))) {
|
|
|
|
EXT4_ERROR_INODE(inode,
|
|
|
|
"logical %d < ee_block %d + ee_len %d!",
|
|
|
|
*logical, le32_to_cpu(ex->ee_block), ee_len);
|
2015-10-17 23:16:04 +03:00
|
|
|
return -EFSCORRUPTED;
|
2010-03-02 19:46:09 +03:00
|
|
|
}
|
2008-01-29 07:58:27 +03:00
|
|
|
|
2008-01-29 07:58:27 +03:00
|
|
|
*logical = le32_to_cpu(ex->ee_block) + ee_len - 1;
|
2010-10-28 05:30:14 +04:00
|
|
|
*phys = ext4_ext_pblock(ex) + ee_len - 1;
|
2008-01-29 07:58:27 +03:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* search the closest allocated block to the right for *logical
|
|
|
|
* and returns it at @logical + it's physical address at @phys
|
2011-10-08 23:53:49 +04:00
|
|
|
* if *logical is the largest allocated block, the function
|
2008-01-29 07:58:27 +03:00
|
|
|
* returns 0 at @phys
|
|
|
|
* return value contains 0 (success) or error code
|
|
|
|
*/
|
2010-10-28 05:30:14 +04:00
|
|
|
static int ext4_ext_search_right(struct inode *inode,
|
|
|
|
struct ext4_ext_path *path,
|
2011-09-10 02:52:51 +04:00
|
|
|
ext4_lblk_t *logical, ext4_fsblk_t *phys,
|
|
|
|
struct ext4_extent **ret_ex)
|
2008-01-29 07:58:27 +03:00
|
|
|
{
|
|
|
|
struct buffer_head *bh = NULL;
|
|
|
|
struct ext4_extent_header *eh;
|
|
|
|
struct ext4_extent_idx *ix;
|
|
|
|
struct ext4_extent *ex;
|
|
|
|
ext4_fsblk_t block;
|
2009-03-11 01:18:47 +03:00
|
|
|
int depth; /* Note, NOT eh_depth; depth from top of tree */
|
|
|
|
int ee_len;
|
2008-01-29 07:58:27 +03:00
|
|
|
|
2010-03-02 19:46:09 +03:00
|
|
|
if (unlikely(path == NULL)) {
|
|
|
|
EXT4_ERROR_INODE(inode, "path == NULL *logical %d!", *logical);
|
2015-10-17 23:16:04 +03:00
|
|
|
return -EFSCORRUPTED;
|
2010-03-02 19:46:09 +03:00
|
|
|
}
|
2008-01-29 07:58:27 +03:00
|
|
|
depth = path->p_depth;
|
|
|
|
*phys = 0;
|
|
|
|
|
|
|
|
if (depth == 0 && path->p_ext == NULL)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* usually extent in the path covers blocks smaller
|
|
|
|
* then *logical, but it can be that extent is the
|
|
|
|
* first one in the file */
|
|
|
|
|
|
|
|
ex = path[depth].p_ext;
|
2008-01-29 07:58:27 +03:00
|
|
|
ee_len = ext4_ext_get_actual_len(ex);
|
2008-01-29 07:58:27 +03:00
|
|
|
if (*logical < le32_to_cpu(ex->ee_block)) {
|
2010-03-02 19:46:09 +03:00
|
|
|
if (unlikely(EXT_FIRST_EXTENT(path[depth].p_hdr) != ex)) {
|
|
|
|
EXT4_ERROR_INODE(inode,
|
|
|
|
"first_extent(path[%d].p_hdr) != ex",
|
|
|
|
depth);
|
2015-10-17 23:16:04 +03:00
|
|
|
return -EFSCORRUPTED;
|
2010-03-02 19:46:09 +03:00
|
|
|
}
|
2008-01-29 07:58:27 +03:00
|
|
|
while (--depth >= 0) {
|
|
|
|
ix = path[depth].p_idx;
|
2010-03-02 19:46:09 +03:00
|
|
|
if (unlikely(ix != EXT_FIRST_INDEX(path[depth].p_hdr))) {
|
|
|
|
EXT4_ERROR_INODE(inode,
|
|
|
|
"ix != EXT_FIRST_INDEX *logical %d!",
|
|
|
|
*logical);
|
2015-10-17 23:16:04 +03:00
|
|
|
return -EFSCORRUPTED;
|
2010-03-02 19:46:09 +03:00
|
|
|
}
|
2008-01-29 07:58:27 +03:00
|
|
|
}
|
2011-09-10 02:52:51 +04:00
|
|
|
goto found_extent;
|
2008-01-29 07:58:27 +03:00
|
|
|
}
|
|
|
|
|
2010-03-02 19:46:09 +03:00
|
|
|
if (unlikely(*logical < (le32_to_cpu(ex->ee_block) + ee_len))) {
|
|
|
|
EXT4_ERROR_INODE(inode,
|
|
|
|
"logical %d < ee_block %d + ee_len %d!",
|
|
|
|
*logical, le32_to_cpu(ex->ee_block), ee_len);
|
2015-10-17 23:16:04 +03:00
|
|
|
return -EFSCORRUPTED;
|
2010-03-02 19:46:09 +03:00
|
|
|
}
|
2008-01-29 07:58:27 +03:00
|
|
|
|
|
|
|
if (ex != EXT_LAST_EXTENT(path[depth].p_hdr)) {
|
|
|
|
/* next allocated block in this leaf */
|
|
|
|
ex++;
|
2011-09-10 02:52:51 +04:00
|
|
|
goto found_extent;
|
2008-01-29 07:58:27 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* go up and search for index to the right */
|
|
|
|
while (--depth >= 0) {
|
|
|
|
ix = path[depth].p_idx;
|
|
|
|
if (ix != EXT_LAST_INDEX(path[depth].p_hdr))
|
2008-11-26 01:24:23 +03:00
|
|
|
goto got_index;
|
2008-01-29 07:58:27 +03:00
|
|
|
}
|
|
|
|
|
2008-11-26 01:24:23 +03:00
|
|
|
/* we've gone up to the root and found no index to the right */
|
|
|
|
return 0;
|
2008-01-29 07:58:27 +03:00
|
|
|
|
2008-11-26 01:24:23 +03:00
|
|
|
got_index:
|
2008-01-29 07:58:27 +03:00
|
|
|
/* we've found index to the right, let's
|
|
|
|
* follow it and find the closest allocated
|
|
|
|
* block to the right */
|
|
|
|
ix++;
|
2010-10-28 05:30:14 +04:00
|
|
|
block = ext4_idx_pblock(ix);
|
2008-01-29 07:58:27 +03:00
|
|
|
while (++depth < path->p_depth) {
|
2009-03-11 01:18:47 +03:00
|
|
|
/* subtract from p_depth to get proper eh_depth */
|
2013-08-17 05:20:41 +04:00
|
|
|
bh = read_extent_tree_block(inode, block,
|
2013-08-17 05:23:41 +04:00
|
|
|
path->p_depth - depth, 0);
|
2013-08-17 05:20:41 +04:00
|
|
|
if (IS_ERR(bh))
|
|
|
|
return PTR_ERR(bh);
|
|
|
|
eh = ext_block_hdr(bh);
|
2008-01-29 07:58:27 +03:00
|
|
|
ix = EXT_FIRST_INDEX(eh);
|
2010-10-28 05:30:14 +04:00
|
|
|
block = ext4_idx_pblock(ix);
|
2008-01-29 07:58:27 +03:00
|
|
|
put_bh(bh);
|
|
|
|
}
|
|
|
|
|
2013-08-17 05:23:41 +04:00
|
|
|
bh = read_extent_tree_block(inode, block, path->p_depth - depth, 0);
|
2013-08-17 05:20:41 +04:00
|
|
|
if (IS_ERR(bh))
|
|
|
|
return PTR_ERR(bh);
|
2008-01-29 07:58:27 +03:00
|
|
|
eh = ext_block_hdr(bh);
|
|
|
|
ex = EXT_FIRST_EXTENT(eh);
|
2011-09-10 02:52:51 +04:00
|
|
|
found_extent:
|
2008-01-29 07:58:27 +03:00
|
|
|
*logical = le32_to_cpu(ex->ee_block);
|
2010-10-28 05:30:14 +04:00
|
|
|
*phys = ext4_ext_pblock(ex);
|
2011-09-10 02:52:51 +04:00
|
|
|
*ret_ex = ex;
|
|
|
|
if (bh)
|
|
|
|
put_bh(bh);
|
2008-01-29 07:58:27 +03:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-10-11 12:21:03 +04:00
|
|
|
/*
|
2006-10-11 12:21:07 +04:00
|
|
|
* ext4_ext_next_allocated_block:
|
2011-06-06 08:05:17 +04:00
|
|
|
* returns allocated block in subsequent extent or EXT_MAX_BLOCKS.
|
2006-10-11 12:21:07 +04:00
|
|
|
* NOTE: it considers block number from index entry as
|
|
|
|
* allocated block. Thus, index entries have to be consistent
|
|
|
|
* with leaves.
|
2006-10-11 12:21:03 +04:00
|
|
|
*/
|
2014-08-31 07:52:19 +04:00
|
|
|
ext4_lblk_t
|
2006-10-11 12:21:03 +04:00
|
|
|
ext4_ext_next_allocated_block(struct ext4_ext_path *path)
|
|
|
|
{
|
|
|
|
int depth;
|
|
|
|
|
|
|
|
BUG_ON(path == NULL);
|
|
|
|
depth = path->p_depth;
|
|
|
|
|
|
|
|
if (depth == 0 && path->p_ext == NULL)
|
2011-06-06 08:05:17 +04:00
|
|
|
return EXT_MAX_BLOCKS;
|
2006-10-11 12:21:03 +04:00
|
|
|
|
|
|
|
while (depth >= 0) {
|
|
|
|
if (depth == path->p_depth) {
|
|
|
|
/* leaf */
|
2011-10-26 12:38:59 +04:00
|
|
|
if (path[depth].p_ext &&
|
|
|
|
path[depth].p_ext !=
|
2006-10-11 12:21:03 +04:00
|
|
|
EXT_LAST_EXTENT(path[depth].p_hdr))
|
|
|
|
return le32_to_cpu(path[depth].p_ext[1].ee_block);
|
|
|
|
} else {
|
|
|
|
/* index */
|
|
|
|
if (path[depth].p_idx !=
|
|
|
|
EXT_LAST_INDEX(path[depth].p_hdr))
|
|
|
|
return le32_to_cpu(path[depth].p_idx[1].ei_block);
|
|
|
|
}
|
|
|
|
depth--;
|
|
|
|
}
|
|
|
|
|
2011-06-06 08:05:17 +04:00
|
|
|
return EXT_MAX_BLOCKS;
|
2006-10-11 12:21:03 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2006-10-11 12:21:07 +04:00
|
|
|
* ext4_ext_next_leaf_block:
|
2011-06-06 08:05:17 +04:00
|
|
|
* returns first allocated block from next leaf or EXT_MAX_BLOCKS
|
2006-10-11 12:21:03 +04:00
|
|
|
*/
|
2011-07-24 05:49:07 +04:00
|
|
|
static ext4_lblk_t ext4_ext_next_leaf_block(struct ext4_ext_path *path)
|
2006-10-11 12:21:03 +04:00
|
|
|
{
|
|
|
|
int depth;
|
|
|
|
|
|
|
|
BUG_ON(path == NULL);
|
|
|
|
depth = path->p_depth;
|
|
|
|
|
|
|
|
/* zero-tree has no leaf blocks at all */
|
|
|
|
if (depth == 0)
|
2011-06-06 08:05:17 +04:00
|
|
|
return EXT_MAX_BLOCKS;
|
2006-10-11 12:21:03 +04:00
|
|
|
|
|
|
|
/* go to index block */
|
|
|
|
depth--;
|
|
|
|
|
|
|
|
while (depth >= 0) {
|
|
|
|
if (path[depth].p_idx !=
|
|
|
|
EXT_LAST_INDEX(path[depth].p_hdr))
|
2008-01-29 07:58:27 +03:00
|
|
|
return (ext4_lblk_t)
|
|
|
|
le32_to_cpu(path[depth].p_idx[1].ei_block);
|
2006-10-11 12:21:03 +04:00
|
|
|
depth--;
|
|
|
|
}
|
|
|
|
|
2011-06-06 08:05:17 +04:00
|
|
|
return EXT_MAX_BLOCKS;
|
2006-10-11 12:21:03 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2006-10-11 12:21:07 +04:00
|
|
|
* ext4_ext_correct_indexes:
|
|
|
|
* if leaf gets modified and modified extent is first in the leaf,
|
|
|
|
* then we have to correct all indexes above.
|
2006-10-11 12:21:03 +04:00
|
|
|
* TODO: do we need to correct tree in all cases?
|
|
|
|
*/
|
2008-01-29 07:58:27 +03:00
|
|
|
static int ext4_ext_correct_indexes(handle_t *handle, struct inode *inode,
|
2006-10-11 12:21:03 +04:00
|
|
|
struct ext4_ext_path *path)
|
|
|
|
{
|
|
|
|
struct ext4_extent_header *eh;
|
|
|
|
int depth = ext_depth(inode);
|
|
|
|
struct ext4_extent *ex;
|
|
|
|
__le32 border;
|
|
|
|
int k, err = 0;
|
|
|
|
|
|
|
|
eh = path[depth].p_hdr;
|
|
|
|
ex = path[depth].p_ext;
|
2010-03-02 19:46:09 +03:00
|
|
|
|
|
|
|
if (unlikely(ex == NULL || eh == NULL)) {
|
|
|
|
EXT4_ERROR_INODE(inode,
|
|
|
|
"ex %p == NULL or eh %p == NULL", ex, eh);
|
2015-10-17 23:16:04 +03:00
|
|
|
return -EFSCORRUPTED;
|
2010-03-02 19:46:09 +03:00
|
|
|
}
|
2006-10-11 12:21:03 +04:00
|
|
|
|
|
|
|
if (depth == 0) {
|
|
|
|
/* there is no tree at all */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ex != EXT_FIRST_EXTENT(eh)) {
|
|
|
|
/* we correct tree if first leaf got modified only */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2006-10-11 12:21:07 +04:00
|
|
|
* TODO: we need correction if border is smaller than current one
|
2006-10-11 12:21:03 +04:00
|
|
|
*/
|
|
|
|
k = depth - 1;
|
|
|
|
border = path[depth].p_ext->ee_block;
|
2006-12-07 07:41:33 +03:00
|
|
|
err = ext4_ext_get_access(handle, inode, path + k);
|
|
|
|
if (err)
|
2006-10-11 12:21:03 +04:00
|
|
|
return err;
|
|
|
|
path[k].p_idx->ei_block = border;
|
2006-12-07 07:41:33 +03:00
|
|
|
err = ext4_ext_dirty(handle, inode, path + k);
|
|
|
|
if (err)
|
2006-10-11 12:21:03 +04:00
|
|
|
return err;
|
|
|
|
|
|
|
|
while (k--) {
|
|
|
|
/* change all left-side indexes */
|
|
|
|
if (path[k+1].p_idx != EXT_FIRST_INDEX(path[k+1].p_hdr))
|
|
|
|
break;
|
2006-12-07 07:41:33 +03:00
|
|
|
err = ext4_ext_get_access(handle, inode, path + k);
|
|
|
|
if (err)
|
2006-10-11 12:21:03 +04:00
|
|
|
break;
|
|
|
|
path[k].p_idx->ei_block = border;
|
2006-12-07 07:41:33 +03:00
|
|
|
err = ext4_ext_dirty(handle, inode, path + k);
|
|
|
|
if (err)
|
2006-10-11 12:21:03 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2009-06-18 03:24:03 +04:00
|
|
|
int
|
2006-10-11 12:21:03 +04:00
|
|
|
ext4_can_extents_be_merged(struct inode *inode, struct ext4_extent *ex1,
|
|
|
|
struct ext4_extent *ex2)
|
|
|
|
{
|
2013-11-04 18:58:26 +04:00
|
|
|
unsigned short ext1_ee_len, ext2_ee_len;
|
2007-07-18 05:42:41 +04:00
|
|
|
|
2014-04-21 07:45:47 +04:00
|
|
|
if (ext4_ext_is_unwritten(ex1) != ext4_ext_is_unwritten(ex2))
|
2007-07-18 05:42:41 +04:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
ext1_ee_len = ext4_ext_get_actual_len(ex1);
|
|
|
|
ext2_ee_len = ext4_ext_get_actual_len(ex2);
|
|
|
|
|
|
|
|
if (le32_to_cpu(ex1->ee_block) + ext1_ee_len !=
|
2006-10-11 12:21:24 +04:00
|
|
|
le32_to_cpu(ex2->ee_block))
|
2006-10-11 12:21:03 +04:00
|
|
|
return 0;
|
|
|
|
|
2006-10-11 12:21:06 +04:00
|
|
|
/*
|
|
|
|
* To allow future support for preallocated extents to be added
|
|
|
|
* as an RO_COMPAT feature, refuse to merge to extents if
|
2006-10-11 12:21:07 +04:00
|
|
|
* this can result in the top bit of ee_len being set.
|
2006-10-11 12:21:06 +04:00
|
|
|
*/
|
2013-11-04 18:58:26 +04:00
|
|
|
if (ext1_ee_len + ext2_ee_len > EXT_INIT_MAX_LEN)
|
2006-10-11 12:21:06 +04:00
|
|
|
return 0;
|
2016-03-09 07:36:46 +03:00
|
|
|
/*
|
|
|
|
* The check for IO to unwritten extent is somewhat racy as we
|
|
|
|
* increment i_unwritten / set EXT4_STATE_DIO_UNWRITTEN only after
|
|
|
|
* dropping i_data_sem. But reserved blocks should save us in that
|
|
|
|
* case.
|
|
|
|
*/
|
2014-04-21 07:45:47 +04:00
|
|
|
if (ext4_ext_is_unwritten(ex1) &&
|
2014-02-21 06:17:35 +04:00
|
|
|
(ext4_test_inode_state(inode, EXT4_STATE_DIO_UNWRITTEN) ||
|
|
|
|
atomic_read(&EXT4_I(inode)->i_unwritten) ||
|
2014-04-21 07:45:47 +04:00
|
|
|
(ext1_ee_len + ext2_ee_len > EXT_UNWRITTEN_MAX_LEN)))
|
2014-02-21 06:17:35 +04:00
|
|
|
return 0;
|
2007-02-17 21:20:16 +03:00
|
|
|
#ifdef AGGRESSIVE_TEST
|
2008-01-29 07:58:27 +03:00
|
|
|
if (ext1_ee_len >= 4)
|
2006-10-11 12:21:03 +04:00
|
|
|
return 0;
|
|
|
|
#endif
|
|
|
|
|
2010-10-28 05:30:14 +04:00
|
|
|
if (ext4_ext_pblock(ex1) + ext1_ee_len == ext4_ext_pblock(ex2))
|
2006-10-11 12:21:03 +04:00
|
|
|
return 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-07-18 05:42:38 +04:00
|
|
|
/*
|
|
|
|
* This function tries to merge the "ex" extent to the next extent in the tree.
|
|
|
|
* It always tries to merge towards right. If you want to merge towards
|
|
|
|
* left, pass "ex - 1" as argument instead of "ex".
|
|
|
|
* Returns 0 if the extents (ex and ex+1) were _not_ merged and returns
|
|
|
|
* 1 if they got merged.
|
|
|
|
*/
|
2011-05-03 19:45:29 +04:00
|
|
|
static int ext4_ext_try_to_merge_right(struct inode *inode,
|
2010-10-28 05:30:14 +04:00
|
|
|
struct ext4_ext_path *path,
|
|
|
|
struct ext4_extent *ex)
|
2007-07-18 05:42:38 +04:00
|
|
|
{
|
|
|
|
struct ext4_extent_header *eh;
|
|
|
|
unsigned int depth, len;
|
2014-04-21 07:45:47 +04:00
|
|
|
int merge_done = 0, unwritten;
|
2007-07-18 05:42:38 +04:00
|
|
|
|
|
|
|
depth = ext_depth(inode);
|
|
|
|
BUG_ON(path[depth].p_hdr == NULL);
|
|
|
|
eh = path[depth].p_hdr;
|
|
|
|
|
|
|
|
while (ex < EXT_LAST_EXTENT(eh)) {
|
|
|
|
if (!ext4_can_extents_be_merged(inode, ex, ex + 1))
|
|
|
|
break;
|
|
|
|
/* merge with next extent! */
|
2014-04-21 07:45:47 +04:00
|
|
|
unwritten = ext4_ext_is_unwritten(ex);
|
2007-07-18 05:42:38 +04:00
|
|
|
ex->ee_len = cpu_to_le16(ext4_ext_get_actual_len(ex)
|
|
|
|
+ ext4_ext_get_actual_len(ex + 1));
|
2014-04-21 07:45:47 +04:00
|
|
|
if (unwritten)
|
|
|
|
ext4_ext_mark_unwritten(ex);
|
2007-07-18 05:42:38 +04:00
|
|
|
|
|
|
|
if (ex + 1 < EXT_LAST_EXTENT(eh)) {
|
|
|
|
len = (EXT_LAST_EXTENT(eh) - ex - 1)
|
|
|
|
* sizeof(struct ext4_extent);
|
|
|
|
memmove(ex + 1, ex + 2, len);
|
|
|
|
}
|
2008-04-17 18:38:59 +04:00
|
|
|
le16_add_cpu(&eh->eh_entries, -1);
|
2007-07-18 05:42:38 +04:00
|
|
|
merge_done = 1;
|
|
|
|
WARN_ON(eh->eh_entries == 0);
|
|
|
|
if (!eh->eh_entries)
|
2010-05-17 05:00:00 +04:00
|
|
|
EXT4_ERROR_INODE(inode, "eh->eh_entries = 0!");
|
2007-07-18 05:42:38 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
return merge_done;
|
|
|
|
}
|
|
|
|
|
2012-08-17 17:44:17 +04:00
|
|
|
/*
|
|
|
|
* This function does a very simple check to see if we can collapse
|
|
|
|
* an extent tree with a single extent tree leaf block into the inode.
|
|
|
|
*/
|
|
|
|
static void ext4_ext_try_to_merge_up(handle_t *handle,
|
|
|
|
struct inode *inode,
|
|
|
|
struct ext4_ext_path *path)
|
|
|
|
{
|
|
|
|
size_t s;
|
|
|
|
unsigned max_root = ext4_ext_space_root(inode, 0);
|
|
|
|
ext4_fsblk_t blk;
|
|
|
|
|
|
|
|
if ((path[0].p_depth != 1) ||
|
|
|
|
(le16_to_cpu(path[0].p_hdr->eh_entries) != 1) ||
|
|
|
|
(le16_to_cpu(path[1].p_hdr->eh_entries) > max_root))
|
|
|
|
return;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We need to modify the block allocation bitmap and the block
|
|
|
|
* group descriptor to release the extent tree block. If we
|
|
|
|
* can't get the journal credits, give up.
|
|
|
|
*/
|
|
|
|
if (ext4_journal_extend(handle, 2))
|
|
|
|
return;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Copy the extent data up to the inode
|
|
|
|
*/
|
|
|
|
blk = ext4_idx_pblock(path[0].p_idx);
|
|
|
|
s = le16_to_cpu(path[1].p_hdr->eh_entries) *
|
|
|
|
sizeof(struct ext4_extent_idx);
|
|
|
|
s += sizeof(struct ext4_extent_header);
|
|
|
|
|
2014-09-01 22:40:09 +04:00
|
|
|
path[1].p_maxdepth = path[0].p_maxdepth;
|
2012-08-17 17:44:17 +04:00
|
|
|
memcpy(path[0].p_hdr, path[1].p_hdr, s);
|
|
|
|
path[0].p_depth = 0;
|
|
|
|
path[0].p_ext = EXT_FIRST_EXTENT(path[0].p_hdr) +
|
|
|
|
(path[1].p_ext - EXT_FIRST_EXTENT(path[1].p_hdr));
|
|
|
|
path[0].p_hdr->eh_max = cpu_to_le16(max_root);
|
|
|
|
|
|
|
|
brelse(path[1].p_bh);
|
|
|
|
ext4_free_blocks(handle, inode, NULL, blk, 1,
|
2014-07-15 14:02:38 +04:00
|
|
|
EXT4_FREE_BLOCKS_METADATA | EXT4_FREE_BLOCKS_FORGET);
|
2012-08-17 17:44:17 +04:00
|
|
|
}
|
|
|
|
|
2011-05-03 19:45:29 +04:00
|
|
|
/*
|
|
|
|
* This function tries to merge the @ex extent to neighbours in the tree.
|
|
|
|
* return 1 if merge left else 0.
|
|
|
|
*/
|
2012-08-17 17:44:17 +04:00
|
|
|
static void ext4_ext_try_to_merge(handle_t *handle,
|
|
|
|
struct inode *inode,
|
2011-05-03 19:45:29 +04:00
|
|
|
struct ext4_ext_path *path,
|
|
|
|
struct ext4_extent *ex) {
|
|
|
|
struct ext4_extent_header *eh;
|
|
|
|
unsigned int depth;
|
|
|
|
int merge_done = 0;
|
|
|
|
|
|
|
|
depth = ext_depth(inode);
|
|
|
|
BUG_ON(path[depth].p_hdr == NULL);
|
|
|
|
eh = path[depth].p_hdr;
|
|
|
|
|
|
|
|
if (ex > EXT_FIRST_EXTENT(eh))
|
|
|
|
merge_done = ext4_ext_try_to_merge_right(inode, path, ex - 1);
|
|
|
|
|
|
|
|
if (!merge_done)
|
2012-08-17 17:44:17 +04:00
|
|
|
(void) ext4_ext_try_to_merge_right(inode, path, ex);
|
2011-05-03 19:45:29 +04:00
|
|
|
|
2012-08-17 17:44:17 +04:00
|
|
|
ext4_ext_try_to_merge_up(handle, inode, path);
|
2011-05-03 19:45:29 +04:00
|
|
|
}
|
|
|
|
|
2007-05-24 21:04:13 +04:00
|
|
|
/*
|
|
|
|
* check if a portion of the "newext" extent overlaps with an
|
|
|
|
* existing extent.
|
|
|
|
*
|
|
|
|
* If there is an overlap discovered, it updates the length of the newext
|
|
|
|
* such that there will be no overlap, and then returns 1.
|
|
|
|
* If there is no overlap found, it returns 0.
|
|
|
|
*/
|
2011-09-10 02:52:51 +04:00
|
|
|
static unsigned int ext4_ext_check_overlap(struct ext4_sb_info *sbi,
|
|
|
|
struct inode *inode,
|
2010-10-28 05:30:14 +04:00
|
|
|
struct ext4_extent *newext,
|
|
|
|
struct ext4_ext_path *path)
|
2007-05-24 21:04:13 +04:00
|
|
|
{
|
2008-01-29 07:58:27 +03:00
|
|
|
ext4_lblk_t b1, b2;
|
2007-05-24 21:04:13 +04:00
|
|
|
unsigned int depth, len1;
|
|
|
|
unsigned int ret = 0;
|
|
|
|
|
|
|
|
b1 = le32_to_cpu(newext->ee_block);
|
2007-07-18 05:42:41 +04:00
|
|
|
len1 = ext4_ext_get_actual_len(newext);
|
2007-05-24 21:04:13 +04:00
|
|
|
depth = ext_depth(inode);
|
|
|
|
if (!path[depth].p_ext)
|
|
|
|
goto out;
|
2013-12-20 18:29:35 +04:00
|
|
|
b2 = EXT4_LBLK_CMASK(sbi, le32_to_cpu(path[depth].p_ext->ee_block));
|
2007-05-24 21:04:13 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* get the next allocated block if the extent in the path
|
2008-07-27 00:15:44 +04:00
|
|
|
* is before the requested block(s)
|
2007-05-24 21:04:13 +04:00
|
|
|
*/
|
|
|
|
if (b2 < b1) {
|
|
|
|
b2 = ext4_ext_next_allocated_block(path);
|
2011-06-06 08:05:17 +04:00
|
|
|
if (b2 == EXT_MAX_BLOCKS)
|
2007-05-24 21:04:13 +04:00
|
|
|
goto out;
|
2013-12-20 18:29:35 +04:00
|
|
|
b2 = EXT4_LBLK_CMASK(sbi, b2);
|
2007-05-24 21:04:13 +04:00
|
|
|
}
|
|
|
|
|
2008-01-29 07:58:27 +03:00
|
|
|
/* check for wrap through zero on extent logical start block*/
|
2007-05-24 21:04:13 +04:00
|
|
|
if (b1 + len1 < b1) {
|
2011-06-06 08:05:17 +04:00
|
|
|
len1 = EXT_MAX_BLOCKS - b1;
|
2007-05-24 21:04:13 +04:00
|
|
|
newext->ee_len = cpu_to_le16(len1);
|
|
|
|
ret = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* check for overlap */
|
|
|
|
if (b1 + len1 > b2) {
|
|
|
|
newext->ee_len = cpu_to_le16(b2 - b1);
|
|
|
|
ret = 1;
|
|
|
|
}
|
|
|
|
out:
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2006-10-11 12:21:03 +04:00
|
|
|
/*
|
2006-10-11 12:21:07 +04:00
|
|
|
* ext4_ext_insert_extent:
|
|
|
|
* tries to merge requsted extent into the existing extent or
|
|
|
|
* inserts requested extent as new one into the tree,
|
|
|
|
* creating new leaf in the no-space case.
|
2006-10-11 12:21:03 +04:00
|
|
|
*/
|
|
|
|
int ext4_ext_insert_extent(handle_t *handle, struct inode *inode,
|
2014-09-01 22:37:09 +04:00
|
|
|
struct ext4_ext_path **ppath,
|
2013-08-17 05:23:41 +04:00
|
|
|
struct ext4_extent *newext, int gb_flags)
|
2006-10-11 12:21:03 +04:00
|
|
|
{
|
2014-09-01 22:37:09 +04:00
|
|
|
struct ext4_ext_path *path = *ppath;
|
2008-09-09 06:25:24 +04:00
|
|
|
struct ext4_extent_header *eh;
|
2006-10-11 12:21:03 +04:00
|
|
|
struct ext4_extent *ex, *fex;
|
|
|
|
struct ext4_extent *nearex; /* nearest extent */
|
|
|
|
struct ext4_ext_path *npath = NULL;
|
2008-01-29 07:58:27 +03:00
|
|
|
int depth, len, err;
|
|
|
|
ext4_lblk_t next;
|
2014-04-21 07:45:47 +04:00
|
|
|
int mb_flags = 0, unwritten;
|
2006-10-11 12:21:03 +04:00
|
|
|
|
2014-09-05 02:07:25 +04:00
|
|
|
if (gb_flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE)
|
|
|
|
mb_flags |= EXT4_MB_DELALLOC_RESERVED;
|
2010-03-02 19:46:09 +03:00
|
|
|
if (unlikely(ext4_ext_get_actual_len(newext) == 0)) {
|
|
|
|
EXT4_ERROR_INODE(inode, "ext4_ext_get_actual_len(newext) == 0");
|
2015-10-17 23:16:04 +03:00
|
|
|
return -EFSCORRUPTED;
|
2010-03-02 19:46:09 +03:00
|
|
|
}
|
2006-10-11 12:21:03 +04:00
|
|
|
depth = ext_depth(inode);
|
|
|
|
ex = path[depth].p_ext;
|
2013-04-04 07:33:28 +04:00
|
|
|
eh = path[depth].p_hdr;
|
2010-03-02 19:46:09 +03:00
|
|
|
if (unlikely(path[depth].p_hdr == NULL)) {
|
|
|
|
EXT4_ERROR_INODE(inode, "path[%d].p_hdr == NULL", depth);
|
2015-10-17 23:16:04 +03:00
|
|
|
return -EFSCORRUPTED;
|
2010-03-02 19:46:09 +03:00
|
|
|
}
|
2006-10-11 12:21:03 +04:00
|
|
|
|
|
|
|
/* try to insert block into found extent and return */
|
2013-08-17 05:23:41 +04:00
|
|
|
if (ex && !(gb_flags & EXT4_GET_BLOCKS_PRE_IO)) {
|
2007-07-18 05:42:41 +04:00
|
|
|
|
|
|
|
/*
|
2013-04-04 07:33:28 +04:00
|
|
|
* Try to see whether we should rather test the extent on
|
|
|
|
* right from ex, or from the left of ex. This is because
|
2014-09-01 22:43:09 +04:00
|
|
|
* ext4_find_extent() can return either extent on the
|
2013-04-04 07:33:28 +04:00
|
|
|
* left, or on the right from the searched position. This
|
|
|
|
* will make merging more effective.
|
2007-07-18 05:42:41 +04:00
|
|
|
*/
|
2013-04-04 07:33:28 +04:00
|
|
|
if (ex < EXT_LAST_EXTENT(eh) &&
|
|
|
|
(le32_to_cpu(ex->ee_block) +
|
|
|
|
ext4_ext_get_actual_len(ex) <
|
|
|
|
le32_to_cpu(newext->ee_block))) {
|
|
|
|
ex += 1;
|
|
|
|
goto prepend;
|
|
|
|
} else if ((ex > EXT_FIRST_EXTENT(eh)) &&
|
|
|
|
(le32_to_cpu(newext->ee_block) +
|
|
|
|
ext4_ext_get_actual_len(newext) <
|
|
|
|
le32_to_cpu(ex->ee_block)))
|
|
|
|
ex -= 1;
|
|
|
|
|
|
|
|
/* Try to append newex to the ex */
|
|
|
|
if (ext4_can_extents_be_merged(inode, ex, newext)) {
|
|
|
|
ext_debug("append [%d]%d block to %u:[%d]%d"
|
|
|
|
"(from %llu)\n",
|
2014-04-21 07:45:47 +04:00
|
|
|
ext4_ext_is_unwritten(newext),
|
2013-04-04 07:33:28 +04:00
|
|
|
ext4_ext_get_actual_len(newext),
|
|
|
|
le32_to_cpu(ex->ee_block),
|
2014-04-21 07:45:47 +04:00
|
|
|
ext4_ext_is_unwritten(ex),
|
2013-04-04 07:33:28 +04:00
|
|
|
ext4_ext_get_actual_len(ex),
|
|
|
|
ext4_ext_pblock(ex));
|
|
|
|
err = ext4_ext_get_access(handle, inode,
|
|
|
|
path + depth);
|
|
|
|
if (err)
|
|
|
|
return err;
|
2014-04-21 07:45:47 +04:00
|
|
|
unwritten = ext4_ext_is_unwritten(ex);
|
2013-04-04 07:33:28 +04:00
|
|
|
ex->ee_len = cpu_to_le16(ext4_ext_get_actual_len(ex)
|
2007-07-18 05:42:41 +04:00
|
|
|
+ ext4_ext_get_actual_len(newext));
|
2014-04-21 07:45:47 +04:00
|
|
|
if (unwritten)
|
|
|
|
ext4_ext_mark_unwritten(ex);
|
2013-04-04 07:33:28 +04:00
|
|
|
eh = path[depth].p_hdr;
|
|
|
|
nearex = ex;
|
|
|
|
goto merge;
|
|
|
|
}
|
|
|
|
|
|
|
|
prepend:
|
|
|
|
/* Try to prepend newex to the ex */
|
|
|
|
if (ext4_can_extents_be_merged(inode, newext, ex)) {
|
|
|
|
ext_debug("prepend %u[%d]%d block to %u:[%d]%d"
|
|
|
|
"(from %llu)\n",
|
|
|
|
le32_to_cpu(newext->ee_block),
|
2014-04-21 07:45:47 +04:00
|
|
|
ext4_ext_is_unwritten(newext),
|
2013-04-04 07:33:28 +04:00
|
|
|
ext4_ext_get_actual_len(newext),
|
|
|
|
le32_to_cpu(ex->ee_block),
|
2014-04-21 07:45:47 +04:00
|
|
|
ext4_ext_is_unwritten(ex),
|
2013-04-04 07:33:28 +04:00
|
|
|
ext4_ext_get_actual_len(ex),
|
|
|
|
ext4_ext_pblock(ex));
|
|
|
|
err = ext4_ext_get_access(handle, inode,
|
|
|
|
path + depth);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
2014-04-21 07:45:47 +04:00
|
|
|
unwritten = ext4_ext_is_unwritten(ex);
|
2013-04-04 07:33:28 +04:00
|
|
|
ex->ee_block = newext->ee_block;
|
|
|
|
ext4_ext_store_pblock(ex, ext4_ext_pblock(newext));
|
|
|
|
ex->ee_len = cpu_to_le16(ext4_ext_get_actual_len(ex)
|
|
|
|
+ ext4_ext_get_actual_len(newext));
|
2014-04-21 07:45:47 +04:00
|
|
|
if (unwritten)
|
|
|
|
ext4_ext_mark_unwritten(ex);
|
2013-04-04 07:33:28 +04:00
|
|
|
eh = path[depth].p_hdr;
|
|
|
|
nearex = ex;
|
|
|
|
goto merge;
|
|
|
|
}
|
2006-10-11 12:21:03 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
depth = ext_depth(inode);
|
|
|
|
eh = path[depth].p_hdr;
|
|
|
|
if (le16_to_cpu(eh->eh_entries) < le16_to_cpu(eh->eh_max))
|
|
|
|
goto has_space;
|
|
|
|
|
|
|
|
/* probably next leaf has space for us? */
|
|
|
|
fex = EXT_LAST_EXTENT(eh);
|
2011-07-12 02:24:01 +04:00
|
|
|
next = EXT_MAX_BLOCKS;
|
|
|
|
if (le32_to_cpu(newext->ee_block) > le32_to_cpu(fex->ee_block))
|
2011-07-24 05:49:07 +04:00
|
|
|
next = ext4_ext_next_leaf_block(path);
|
2011-07-12 02:24:01 +04:00
|
|
|
if (next != EXT_MAX_BLOCKS) {
|
2011-11-02 02:56:41 +04:00
|
|
|
ext_debug("next leaf block - %u\n", next);
|
2006-10-11 12:21:03 +04:00
|
|
|
BUG_ON(npath != NULL);
|
2014-09-01 22:43:09 +04:00
|
|
|
npath = ext4_find_extent(inode, next, NULL, 0);
|
2006-10-11 12:21:03 +04:00
|
|
|
if (IS_ERR(npath))
|
|
|
|
return PTR_ERR(npath);
|
|
|
|
BUG_ON(npath->p_depth != path->p_depth);
|
|
|
|
eh = npath[depth].p_hdr;
|
|
|
|
if (le16_to_cpu(eh->eh_entries) < le16_to_cpu(eh->eh_max)) {
|
2011-03-31 05:57:33 +04:00
|
|
|
ext_debug("next leaf isn't full(%d)\n",
|
2006-10-11 12:21:03 +04:00
|
|
|
le16_to_cpu(eh->eh_entries));
|
|
|
|
path = npath;
|
2011-07-11 19:43:59 +04:00
|
|
|
goto has_space;
|
2006-10-11 12:21:03 +04:00
|
|
|
}
|
|
|
|
ext_debug("next leaf has no free space(%d,%d)\n",
|
|
|
|
le16_to_cpu(eh->eh_entries), le16_to_cpu(eh->eh_max));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2006-10-11 12:21:07 +04:00
|
|
|
* There is no free space in the found leaf.
|
|
|
|
* We're gonna add a new leaf in the tree.
|
2006-10-11 12:21:03 +04:00
|
|
|
*/
|
2013-08-17 05:23:41 +04:00
|
|
|
if (gb_flags & EXT4_GET_BLOCKS_METADATA_NOFAIL)
|
2014-09-05 02:07:25 +04:00
|
|
|
mb_flags |= EXT4_MB_USE_RESERVED;
|
2013-08-17 05:23:41 +04:00
|
|
|
err = ext4_ext_create_new_leaf(handle, inode, mb_flags, gb_flags,
|
2014-09-01 22:37:09 +04:00
|
|
|
ppath, newext);
|
2006-10-11 12:21:03 +04:00
|
|
|
if (err)
|
|
|
|
goto cleanup;
|
|
|
|
depth = ext_depth(inode);
|
|
|
|
eh = path[depth].p_hdr;
|
|
|
|
|
|
|
|
has_space:
|
|
|
|
nearex = path[depth].p_ext;
|
|
|
|
|
2006-12-07 07:41:33 +03:00
|
|
|
err = ext4_ext_get_access(handle, inode, path + depth);
|
|
|
|
if (err)
|
2006-10-11 12:21:03 +04:00
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (!nearex) {
|
|
|
|
/* there is no extent in this leaf, create first one */
|
2011-11-02 02:56:41 +04:00
|
|
|
ext_debug("first extent in the leaf: %u:%llu:[%d]%d\n",
|
2007-05-24 21:04:54 +04:00
|
|
|
le32_to_cpu(newext->ee_block),
|
2010-10-28 05:30:14 +04:00
|
|
|
ext4_ext_pblock(newext),
|
2014-04-21 07:45:47 +04:00
|
|
|
ext4_ext_is_unwritten(newext),
|
2007-07-18 05:42:41 +04:00
|
|
|
ext4_ext_get_actual_len(newext));
|
2011-10-27 19:52:18 +04:00
|
|
|
nearex = EXT_FIRST_EXTENT(eh);
|
|
|
|
} else {
|
|
|
|
if (le32_to_cpu(newext->ee_block)
|
2007-05-24 21:04:54 +04:00
|
|
|
> le32_to_cpu(nearex->ee_block)) {
|
2011-10-27 19:52:18 +04:00
|
|
|
/* Insert after */
|
2011-11-02 02:56:41 +04:00
|
|
|
ext_debug("insert %u:%llu:[%d]%d before: "
|
|
|
|
"nearest %p\n",
|
2011-10-27 19:52:18 +04:00
|
|
|
le32_to_cpu(newext->ee_block),
|
|
|
|
ext4_ext_pblock(newext),
|
2014-04-21 07:45:47 +04:00
|
|
|
ext4_ext_is_unwritten(newext),
|
2011-10-27 19:52:18 +04:00
|
|
|
ext4_ext_get_actual_len(newext),
|
|
|
|
nearex);
|
|
|
|
nearex++;
|
|
|
|
} else {
|
|
|
|
/* Insert before */
|
|
|
|
BUG_ON(newext->ee_block == nearex->ee_block);
|
2011-11-02 02:56:41 +04:00
|
|
|
ext_debug("insert %u:%llu:[%d]%d after: "
|
|
|
|
"nearest %p\n",
|
2007-05-24 21:04:54 +04:00
|
|
|
le32_to_cpu(newext->ee_block),
|
2010-10-28 05:30:14 +04:00
|
|
|
ext4_ext_pblock(newext),
|
2014-04-21 07:45:47 +04:00
|
|
|
ext4_ext_is_unwritten(newext),
|
2007-07-18 05:42:41 +04:00
|
|
|
ext4_ext_get_actual_len(newext),
|
2011-10-27 19:52:18 +04:00
|
|
|
nearex);
|
|
|
|
}
|
|
|
|
len = EXT_LAST_EXTENT(eh) - nearex + 1;
|
|
|
|
if (len > 0) {
|
2011-11-02 02:56:41 +04:00
|
|
|
ext_debug("insert %u:%llu:[%d]%d: "
|
2011-10-27 19:52:18 +04:00
|
|
|
"move %d extents from 0x%p to 0x%p\n",
|
|
|
|
le32_to_cpu(newext->ee_block),
|
|
|
|
ext4_ext_pblock(newext),
|
2014-04-21 07:45:47 +04:00
|
|
|
ext4_ext_is_unwritten(newext),
|
2011-10-27 19:52:18 +04:00
|
|
|
ext4_ext_get_actual_len(newext),
|
|
|
|
len, nearex, nearex + 1);
|
|
|
|
memmove(nearex + 1, nearex,
|
|
|
|
len * sizeof(struct ext4_extent));
|
2006-10-11 12:21:03 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-04-17 18:38:59 +04:00
|
|
|
le16_add_cpu(&eh->eh_entries, 1);
|
2011-10-27 19:52:18 +04:00
|
|
|
path[depth].p_ext = nearex;
|
2006-10-11 12:21:03 +04:00
|
|
|
nearex->ee_block = newext->ee_block;
|
2010-10-28 05:30:14 +04:00
|
|
|
ext4_ext_store_pblock(nearex, ext4_ext_pblock(newext));
|
2006-10-11 12:21:03 +04:00
|
|
|
nearex->ee_len = newext->ee_len;
|
|
|
|
|
|
|
|
merge:
|
2012-07-10 00:29:28 +04:00
|
|
|
/* try to merge extents */
|
2013-08-17 05:23:41 +04:00
|
|
|
if (!(gb_flags & EXT4_GET_BLOCKS_PRE_IO))
|
2012-08-17 17:44:17 +04:00
|
|
|
ext4_ext_try_to_merge(handle, inode, path, nearex);
|
2006-10-11 12:21:03 +04:00
|
|
|
|
|
|
|
|
|
|
|
/* time to correct all indexes above */
|
|
|
|
err = ext4_ext_correct_indexes(handle, inode, path);
|
|
|
|
if (err)
|
|
|
|
goto cleanup;
|
|
|
|
|
2012-08-17 17:44:17 +04:00
|
|
|
err = ext4_ext_dirty(handle, inode, path + path->p_depth);
|
2006-10-11 12:21:03 +04:00
|
|
|
|
|
|
|
cleanup:
|
2014-09-01 22:39:09 +04:00
|
|
|
ext4_ext_drop_refs(npath);
|
|
|
|
kfree(npath);
|
2006-10-11 12:21:03 +04:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2012-11-28 21:32:26 +04:00
|
|
|
static int ext4_fill_fiemap_extents(struct inode *inode,
|
|
|
|
ext4_lblk_t block, ext4_lblk_t num,
|
|
|
|
struct fiemap_extent_info *fieinfo)
|
2008-10-07 08:46:36 +04:00
|
|
|
{
|
|
|
|
struct ext4_ext_path *path = NULL;
|
|
|
|
struct ext4_extent *ex;
|
2013-02-18 09:31:07 +04:00
|
|
|
struct extent_status es;
|
2012-11-28 21:32:26 +04:00
|
|
|
ext4_lblk_t next, next_del, start = 0, end = 0;
|
2008-10-07 08:46:36 +04:00
|
|
|
ext4_lblk_t last = block + num;
|
2012-11-28 21:32:26 +04:00
|
|
|
int exists, depth = 0, err = 0;
|
|
|
|
unsigned int flags = 0;
|
|
|
|
unsigned char blksize_bits = inode->i_sb->s_blocksize_bits;
|
2008-10-07 08:46:36 +04:00
|
|
|
|
2011-06-06 08:05:17 +04:00
|
|
|
while (block < last && block != EXT_MAX_BLOCKS) {
|
2008-10-07 08:46:36 +04:00
|
|
|
num = last - block;
|
|
|
|
/* find extent for this block */
|
2009-12-10 05:30:02 +03:00
|
|
|
down_read(&EXT4_I(inode)->i_data_sem);
|
2012-11-28 21:32:26 +04:00
|
|
|
|
2014-09-01 22:43:09 +04:00
|
|
|
path = ext4_find_extent(inode, block, &path, 0);
|
2008-10-07 08:46:36 +04:00
|
|
|
if (IS_ERR(path)) {
|
2012-11-28 21:32:26 +04:00
|
|
|
up_read(&EXT4_I(inode)->i_data_sem);
|
2008-10-07 08:46:36 +04:00
|
|
|
err = PTR_ERR(path);
|
|
|
|
path = NULL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
depth = ext_depth(inode);
|
2010-03-02 19:46:09 +03:00
|
|
|
if (unlikely(path[depth].p_hdr == NULL)) {
|
2012-11-28 21:32:26 +04:00
|
|
|
up_read(&EXT4_I(inode)->i_data_sem);
|
2010-03-02 19:46:09 +03:00
|
|
|
EXT4_ERROR_INODE(inode, "path[%d].p_hdr == NULL", depth);
|
2015-10-17 23:16:04 +03:00
|
|
|
err = -EFSCORRUPTED;
|
2010-03-02 19:46:09 +03:00
|
|
|
break;
|
|
|
|
}
|
2008-10-07 08:46:36 +04:00
|
|
|
ex = path[depth].p_ext;
|
|
|
|
next = ext4_ext_next_allocated_block(path);
|
|
|
|
|
2012-11-28 21:32:26 +04:00
|
|
|
flags = 0;
|
2008-10-07 08:46:36 +04:00
|
|
|
exists = 0;
|
|
|
|
if (!ex) {
|
|
|
|
/* there is no extent yet, so try to allocate
|
|
|
|
* all requested space */
|
|
|
|
start = block;
|
|
|
|
end = block + num;
|
|
|
|
} else if (le32_to_cpu(ex->ee_block) > block) {
|
|
|
|
/* need to allocate space before found extent */
|
|
|
|
start = block;
|
|
|
|
end = le32_to_cpu(ex->ee_block);
|
|
|
|
if (block + num < end)
|
|
|
|
end = block + num;
|
|
|
|
} else if (block >= le32_to_cpu(ex->ee_block)
|
|
|
|
+ ext4_ext_get_actual_len(ex)) {
|
|
|
|
/* need to allocate space after found extent */
|
|
|
|
start = block;
|
|
|
|
end = block + num;
|
|
|
|
if (end >= next)
|
|
|
|
end = next;
|
|
|
|
} else if (block >= le32_to_cpu(ex->ee_block)) {
|
|
|
|
/*
|
|
|
|
* some part of requested space is covered
|
|
|
|
* by found extent
|
|
|
|
*/
|
|
|
|
start = block;
|
|
|
|
end = le32_to_cpu(ex->ee_block)
|
|
|
|
+ ext4_ext_get_actual_len(ex);
|
|
|
|
if (block + num < end)
|
|
|
|
end = block + num;
|
|
|
|
exists = 1;
|
|
|
|
} else {
|
|
|
|
BUG();
|
|
|
|
}
|
|
|
|
BUG_ON(end <= start);
|
|
|
|
|
|
|
|
if (!exists) {
|
2013-02-18 09:31:07 +04:00
|
|
|
es.es_lblk = start;
|
|
|
|
es.es_len = end - start;
|
|
|
|
es.es_pblk = 0;
|
2008-10-07 08:46:36 +04:00
|
|
|
} else {
|
2013-02-18 09:31:07 +04:00
|
|
|
es.es_lblk = le32_to_cpu(ex->ee_block);
|
|
|
|
es.es_len = ext4_ext_get_actual_len(ex);
|
|
|
|
es.es_pblk = ext4_ext_pblock(ex);
|
2014-04-21 07:45:47 +04:00
|
|
|
if (ext4_ext_is_unwritten(ex))
|
2012-11-28 21:32:26 +04:00
|
|
|
flags |= FIEMAP_EXTENT_UNWRITTEN;
|
2008-10-07 08:46:36 +04:00
|
|
|
}
|
|
|
|
|
2012-11-28 21:32:26 +04:00
|
|
|
/*
|
2013-02-18 09:31:07 +04:00
|
|
|
* Find delayed extent and update es accordingly. We call
|
|
|
|
* it even in !exists case to find out whether es is the
|
2012-11-28 21:32:26 +04:00
|
|
|
* last existing extent or not.
|
|
|
|
*/
|
2013-02-18 09:31:07 +04:00
|
|
|
next_del = ext4_find_delayed_extent(inode, &es);
|
2012-11-28 21:32:26 +04:00
|
|
|
if (!exists && next_del) {
|
|
|
|
exists = 1;
|
2013-06-13 07:13:59 +04:00
|
|
|
flags |= (FIEMAP_EXTENT_DELALLOC |
|
|
|
|
FIEMAP_EXTENT_UNKNOWN);
|
2012-11-28 21:32:26 +04:00
|
|
|
}
|
|
|
|
up_read(&EXT4_I(inode)->i_data_sem);
|
|
|
|
|
2013-02-18 09:31:07 +04:00
|
|
|
if (unlikely(es.es_len == 0)) {
|
|
|
|
EXT4_ERROR_INODE(inode, "es.es_len == 0");
|
2015-10-17 23:16:04 +03:00
|
|
|
err = -EFSCORRUPTED;
|
2010-03-02 19:46:09 +03:00
|
|
|
break;
|
|
|
|
}
|
2008-10-07 08:46:36 +04:00
|
|
|
|
2013-02-18 09:28:47 +04:00
|
|
|
/*
|
|
|
|
* This is possible iff next == next_del == EXT_MAX_BLOCKS.
|
|
|
|
* we need to check next == EXT_MAX_BLOCKS because it is
|
|
|
|
* possible that an extent is with unwritten and delayed
|
|
|
|
* status due to when an extent is delayed allocated and
|
|
|
|
* is allocated by fallocate status tree will track both of
|
|
|
|
* them in a extent.
|
|
|
|
*
|
|
|
|
* So we could return a unwritten and delayed extent, and
|
|
|
|
* its block is equal to 'next'.
|
|
|
|
*/
|
|
|
|
if (next == next_del && next == EXT_MAX_BLOCKS) {
|
2012-11-28 21:32:26 +04:00
|
|
|
flags |= FIEMAP_EXTENT_LAST;
|
|
|
|
if (unlikely(next_del != EXT_MAX_BLOCKS ||
|
|
|
|
next != EXT_MAX_BLOCKS)) {
|
|
|
|
EXT4_ERROR_INODE(inode,
|
|
|
|
"next extent == %u, next "
|
|
|
|
"delalloc extent = %u",
|
|
|
|
next, next_del);
|
2015-10-17 23:16:04 +03:00
|
|
|
err = -EFSCORRUPTED;
|
2012-11-28 21:32:26 +04:00
|
|
|
break;
|
|
|
|
}
|
2008-10-07 08:46:36 +04:00
|
|
|
}
|
|
|
|
|
2012-11-28 21:32:26 +04:00
|
|
|
if (exists) {
|
|
|
|
err = fiemap_fill_next_extent(fieinfo,
|
2013-02-18 09:31:07 +04:00
|
|
|
(__u64)es.es_lblk << blksize_bits,
|
|
|
|
(__u64)es.es_pblk << blksize_bits,
|
|
|
|
(__u64)es.es_len << blksize_bits,
|
2012-11-28 21:32:26 +04:00
|
|
|
flags);
|
|
|
|
if (err < 0)
|
|
|
|
break;
|
|
|
|
if (err == 1) {
|
|
|
|
err = 0;
|
|
|
|
break;
|
|
|
|
}
|
2008-10-07 08:46:36 +04:00
|
|
|
}
|
|
|
|
|
2013-02-18 09:31:07 +04:00
|
|
|
block = es.es_lblk + es.es_len;
|
2008-10-07 08:46:36 +04:00
|
|
|
}
|
|
|
|
|
2014-09-01 22:39:09 +04:00
|
|
|
ext4_ext_drop_refs(path);
|
|
|
|
kfree(path);
|
2008-10-07 08:46:36 +04:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2006-10-11 12:21:03 +04:00
|
|
|
/*
|
2016-03-10 06:46:57 +03:00
|
|
|
* ext4_ext_determine_hole - determine hole around given block
|
|
|
|
* @inode: inode we lookup in
|
|
|
|
* @path: path in extent tree to @lblk
|
|
|
|
* @lblk: pointer to logical block around which we want to determine hole
|
|
|
|
*
|
|
|
|
* Determine hole length (and start if easily possible) around given logical
|
|
|
|
* block. We don't try too hard to find the beginning of the hole but @path
|
|
|
|
* actually points to extent before @lblk, we provide it.
|
|
|
|
*
|
|
|
|
* The function returns the length of a hole starting at @lblk. We update @lblk
|
|
|
|
* to the beginning of the hole if we managed to find it.
|
2006-10-11 12:21:03 +04:00
|
|
|
*/
|
2016-03-10 06:46:57 +03:00
|
|
|
static ext4_lblk_t ext4_ext_determine_hole(struct inode *inode,
|
|
|
|
struct ext4_ext_path *path,
|
|
|
|
ext4_lblk_t *lblk)
|
2006-10-11 12:21:03 +04:00
|
|
|
{
|
|
|
|
int depth = ext_depth(inode);
|
|
|
|
struct ext4_extent *ex;
|
2016-03-10 06:46:57 +03:00
|
|
|
ext4_lblk_t len;
|
2006-10-11 12:21:03 +04:00
|
|
|
|
|
|
|
ex = path[depth].p_ext;
|
|
|
|
if (ex == NULL) {
|
2014-11-25 19:44:37 +03:00
|
|
|
/* there is no extent yet, so gap is [0;-] */
|
2016-03-10 06:46:57 +03:00
|
|
|
*lblk = 0;
|
2014-11-25 19:44:37 +03:00
|
|
|
len = EXT_MAX_BLOCKS;
|
2016-03-10 06:46:57 +03:00
|
|
|
} else if (*lblk < le32_to_cpu(ex->ee_block)) {
|
|
|
|
len = le32_to_cpu(ex->ee_block) - *lblk;
|
|
|
|
} else if (*lblk >= le32_to_cpu(ex->ee_block)
|
2007-07-18 05:42:41 +04:00
|
|
|
+ ext4_ext_get_actual_len(ex)) {
|
2008-01-29 07:58:27 +03:00
|
|
|
ext4_lblk_t next;
|
|
|
|
|
2016-03-10 06:46:57 +03:00
|
|
|
*lblk = le32_to_cpu(ex->ee_block) + ext4_ext_get_actual_len(ex);
|
2008-01-29 07:58:27 +03:00
|
|
|
next = ext4_ext_next_allocated_block(path);
|
2016-03-10 06:46:57 +03:00
|
|
|
BUG_ON(next == *lblk);
|
|
|
|
len = next - *lblk;
|
2006-10-11 12:21:03 +04:00
|
|
|
} else {
|
|
|
|
BUG();
|
|
|
|
}
|
2016-03-10 06:46:57 +03:00
|
|
|
return len;
|
|
|
|
}
|
2006-10-11 12:21:03 +04:00
|
|
|
|
2016-03-10 06:46:57 +03:00
|
|
|
/*
|
|
|
|
* ext4_ext_put_gap_in_cache:
|
|
|
|
* calculate boundaries of the gap that the requested block fits into
|
|
|
|
* and cache this gap
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
ext4_ext_put_gap_in_cache(struct inode *inode, ext4_lblk_t hole_start,
|
|
|
|
ext4_lblk_t hole_len)
|
|
|
|
{
|
|
|
|
struct extent_status es;
|
|
|
|
|
|
|
|
ext4_es_find_delayed_extent_range(inode, hole_start,
|
|
|
|
hole_start + hole_len - 1, &es);
|
2014-11-25 19:44:37 +03:00
|
|
|
if (es.es_len) {
|
|
|
|
/* There's delayed extent containing lblock? */
|
2016-03-10 06:46:57 +03:00
|
|
|
if (es.es_lblk <= hole_start)
|
2014-11-25 19:44:37 +03:00
|
|
|
return;
|
2016-03-10 06:46:57 +03:00
|
|
|
hole_len = min(es.es_lblk - hole_start, hole_len);
|
2014-11-25 19:44:37 +03:00
|
|
|
}
|
2016-03-10 06:46:57 +03:00
|
|
|
ext_debug(" -> %u:%u\n", hole_start, hole_len);
|
|
|
|
ext4_es_insert_extent(inode, hole_start, hole_len, ~0,
|
|
|
|
EXTENT_STATUS_HOLE);
|
2006-10-11 12:21:03 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2006-10-11 12:21:07 +04:00
|
|
|
* ext4_ext_rm_idx:
|
|
|
|
* removes index from the index block.
|
2006-10-11 12:21:03 +04:00
|
|
|
*/
|
2008-01-29 07:58:27 +03:00
|
|
|
static int ext4_ext_rm_idx(handle_t *handle, struct inode *inode,
|
2012-12-17 18:55:39 +04:00
|
|
|
struct ext4_ext_path *path, int depth)
|
2006-10-11 12:21:03 +04:00
|
|
|
{
|
|
|
|
int err;
|
2006-10-11 12:21:05 +04:00
|
|
|
ext4_fsblk_t leaf;
|
2006-10-11 12:21:03 +04:00
|
|
|
|
|
|
|
/* free index block */
|
2012-12-17 18:55:39 +04:00
|
|
|
depth--;
|
|
|
|
path = path + depth;
|
2010-10-28 05:30:14 +04:00
|
|
|
leaf = ext4_idx_pblock(path->p_idx);
|
2010-03-02 19:46:09 +03:00
|
|
|
if (unlikely(path->p_hdr->eh_entries == 0)) {
|
|
|
|
EXT4_ERROR_INODE(inode, "path->p_hdr->eh_entries == 0");
|
2015-10-17 23:16:04 +03:00
|
|
|
return -EFSCORRUPTED;
|
2010-03-02 19:46:09 +03:00
|
|
|
}
|
2006-12-07 07:41:33 +03:00
|
|
|
err = ext4_ext_get_access(handle, inode, path);
|
|
|
|
if (err)
|
2006-10-11 12:21:03 +04:00
|
|
|
return err;
|
2011-07-28 05:29:33 +04:00
|
|
|
|
|
|
|
if (path->p_idx != EXT_LAST_INDEX(path->p_hdr)) {
|
|
|
|
int len = EXT_LAST_INDEX(path->p_hdr) - path->p_idx;
|
|
|
|
len *= sizeof(struct ext4_extent_idx);
|
|
|
|
memmove(path->p_idx, path->p_idx + 1, len);
|
|
|
|
}
|
|
|
|
|
2008-04-17 18:38:59 +04:00
|
|
|
le16_add_cpu(&path->p_hdr->eh_entries, -1);
|
2006-12-07 07:41:33 +03:00
|
|
|
err = ext4_ext_dirty(handle, inode, path);
|
|
|
|
if (err)
|
2006-10-11 12:21:03 +04:00
|
|
|
return err;
|
2006-10-11 12:21:11 +04:00
|
|
|
ext_debug("index is empty, remove it, free block %llu\n", leaf);
|
2011-09-10 03:18:51 +04:00
|
|
|
trace_ext4_ext_rm_idx(inode, leaf);
|
|
|
|
|
2011-02-22 05:01:42 +03:00
|
|
|
ext4_free_blocks(handle, inode, NULL, leaf, 1,
|
2009-11-23 15:17:05 +03:00
|
|
|
EXT4_FREE_BLOCKS_METADATA | EXT4_FREE_BLOCKS_FORGET);
|
2012-12-17 18:55:39 +04:00
|
|
|
|
|
|
|
while (--depth >= 0) {
|
|
|
|
if (path->p_idx != EXT_FIRST_INDEX(path->p_hdr))
|
|
|
|
break;
|
|
|
|
path--;
|
|
|
|
err = ext4_ext_get_access(handle, inode, path);
|
|
|
|
if (err)
|
|
|
|
break;
|
|
|
|
path->p_idx->ei_block = (path+1)->p_idx->ei_block;
|
|
|
|
err = ext4_ext_dirty(handle, inode, path);
|
|
|
|
if (err)
|
|
|
|
break;
|
|
|
|
}
|
2006-10-11 12:21:03 +04:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2008-08-20 06:16:05 +04:00
|
|
|
* ext4_ext_calc_credits_for_single_extent:
|
|
|
|
* This routine returns max. credits that needed to insert an extent
|
|
|
|
* to the extent tree.
|
|
|
|
* When pass the actual path, the caller should calculate credits
|
|
|
|
* under i_data_sem.
|
2006-10-11 12:21:03 +04:00
|
|
|
*/
|
2008-08-20 06:15:58 +04:00
|
|
|
int ext4_ext_calc_credits_for_single_extent(struct inode *inode, int nrblocks,
|
2006-10-11 12:21:03 +04:00
|
|
|
struct ext4_ext_path *path)
|
|
|
|
{
|
|
|
|
if (path) {
|
2008-08-20 06:16:05 +04:00
|
|
|
int depth = ext_depth(inode);
|
2008-08-20 06:16:03 +04:00
|
|
|
int ret = 0;
|
2008-08-20 06:16:05 +04:00
|
|
|
|
2006-10-11 12:21:03 +04:00
|
|
|
/* probably there is space in leaf? */
|
|
|
|
if (le16_to_cpu(path[depth].p_hdr->eh_entries)
|
2008-08-20 06:16:05 +04:00
|
|
|
< le16_to_cpu(path[depth].p_hdr->eh_max)) {
|
2006-10-11 12:21:03 +04:00
|
|
|
|
2008-08-20 06:16:05 +04:00
|
|
|
/*
|
|
|
|
* There are some space in the leaf tree, no
|
|
|
|
* need to account for leaf block credit
|
|
|
|
*
|
|
|
|
* bitmaps and block group descriptor blocks
|
2011-10-08 23:53:49 +04:00
|
|
|
* and other metadata blocks still need to be
|
2008-08-20 06:16:05 +04:00
|
|
|
* accounted.
|
|
|
|
*/
|
2008-08-20 06:15:58 +04:00
|
|
|
/* 1 bitmap, 1 block group descriptor */
|
2008-08-20 06:16:05 +04:00
|
|
|
ret = 2 + EXT4_META_TRANS_BLOCKS(inode->i_sb);
|
2009-07-06 07:12:04 +04:00
|
|
|
return ret;
|
2008-08-20 06:16:05 +04:00
|
|
|
}
|
|
|
|
}
|
2006-10-11 12:21:03 +04:00
|
|
|
|
2008-08-20 06:15:58 +04:00
|
|
|
return ext4_chunk_trans_blocks(inode, nrblocks);
|
2008-08-20 06:16:05 +04:00
|
|
|
}
|
2006-10-11 12:21:03 +04:00
|
|
|
|
2008-08-20 06:16:05 +04:00
|
|
|
/*
|
2013-06-04 21:01:11 +04:00
|
|
|
* How many index/leaf blocks need to change/allocate to add @extents extents?
|
2008-08-20 06:16:05 +04:00
|
|
|
*
|
2013-06-04 21:01:11 +04:00
|
|
|
* If we add a single extent, then in the worse case, each tree level
|
|
|
|
* index/leaf need to be changed in case of the tree split.
|
2008-08-20 06:16:05 +04:00
|
|
|
*
|
2013-06-04 21:01:11 +04:00
|
|
|
* If more extents are inserted, they could cause the whole tree split more
|
|
|
|
* than once, but this is really rare.
|
2008-08-20 06:16:05 +04:00
|
|
|
*/
|
2013-06-04 21:01:11 +04:00
|
|
|
int ext4_ext_index_trans_blocks(struct inode *inode, int extents)
|
2008-08-20 06:16:05 +04:00
|
|
|
{
|
|
|
|
int index;
|
2012-12-10 23:05:51 +04:00
|
|
|
int depth;
|
|
|
|
|
|
|
|
/* If we are converting the inline data, only one is needed here. */
|
|
|
|
if (ext4_has_inline_data(inode))
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
depth = ext_depth(inode);
|
2006-10-11 12:21:03 +04:00
|
|
|
|
2013-06-04 21:01:11 +04:00
|
|
|
if (extents <= 1)
|
2008-08-20 06:16:05 +04:00
|
|
|
index = depth * 2;
|
|
|
|
else
|
|
|
|
index = depth * 3;
|
2006-10-11 12:21:03 +04:00
|
|
|
|
2008-08-20 06:16:05 +04:00
|
|
|
return index;
|
2006-10-11 12:21:03 +04:00
|
|
|
}
|
|
|
|
|
2013-06-12 19:48:29 +04:00
|
|
|
static inline int get_default_free_blocks_flags(struct inode *inode)
|
|
|
|
{
|
|
|
|
if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))
|
|
|
|
return EXT4_FREE_BLOCKS_METADATA | EXT4_FREE_BLOCKS_FORGET;
|
|
|
|
else if (ext4_should_journal_data(inode))
|
|
|
|
return EXT4_FREE_BLOCKS_FORGET;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-10-11 12:21:03 +04:00
|
|
|
static int ext4_remove_blocks(handle_t *handle, struct inode *inode,
|
2011-09-10 02:54:51 +04:00
|
|
|
struct ext4_extent *ex,
|
2013-05-28 07:33:35 +04:00
|
|
|
long long *partial_cluster,
|
2011-09-10 02:54:51 +04:00
|
|
|
ext4_lblk_t from, ext4_lblk_t to)
|
2006-10-11 12:21:03 +04:00
|
|
|
{
|
2011-09-10 02:54:51 +04:00
|
|
|
struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
|
2014-11-23 08:59:39 +03:00
|
|
|
unsigned short ee_len = ext4_ext_get_actual_len(ex);
|
2011-09-10 02:54:51 +04:00
|
|
|
ext4_fsblk_t pblk;
|
2013-06-12 19:48:29 +04:00
|
|
|
int flags = get_default_free_blocks_flags(inode);
|
2012-09-19 22:14:53 +04:00
|
|
|
|
2011-09-10 02:54:51 +04:00
|
|
|
/*
|
|
|
|
* For bigalloc file systems, we never free a partial cluster
|
|
|
|
* at the beginning of the extent. Instead, we make a note
|
|
|
|
* that we tried freeing the cluster, and check to see if we
|
|
|
|
* need to free it on a subsequent call to ext4_remove_blocks,
|
2014-11-23 08:59:39 +03:00
|
|
|
* or at the end of ext4_ext_rm_leaf or ext4_ext_remove_space.
|
2011-09-10 02:54:51 +04:00
|
|
|
*/
|
|
|
|
flags |= EXT4_FREE_BLOCKS_NOFREE_FIRST_CLUSTER;
|
|
|
|
|
2011-09-10 03:18:51 +04:00
|
|
|
trace_ext4_remove_blocks(inode, ex, from, to, *partial_cluster);
|
2011-09-10 02:54:51 +04:00
|
|
|
/*
|
|
|
|
* If we have a partial cluster, and it's different from the
|
|
|
|
* cluster of the last block, we need to explicitly free the
|
|
|
|
* partial cluster here.
|
|
|
|
*/
|
|
|
|
pblk = ext4_ext_pblock(ex) + ee_len - 1;
|
2014-11-23 08:59:39 +03:00
|
|
|
if (*partial_cluster > 0 &&
|
|
|
|
*partial_cluster != (long long) EXT4_B2C(sbi, pblk)) {
|
2011-09-10 02:54:51 +04:00
|
|
|
ext4_free_blocks(handle, inode, NULL,
|
|
|
|
EXT4_C2B(sbi, *partial_cluster),
|
|
|
|
sbi->s_cluster_ratio, flags);
|
|
|
|
*partial_cluster = 0;
|
|
|
|
}
|
|
|
|
|
2006-10-11 12:21:03 +04:00
|
|
|
#ifdef EXTENTS_STATS
|
|
|
|
{
|
|
|
|
struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
|
|
|
|
spin_lock(&sbi->s_ext_stats_lock);
|
|
|
|
sbi->s_ext_blocks += ee_len;
|
|
|
|
sbi->s_ext_extents++;
|
|
|
|
if (ee_len < sbi->s_ext_min)
|
|
|
|
sbi->s_ext_min = ee_len;
|
|
|
|
if (ee_len > sbi->s_ext_max)
|
|
|
|
sbi->s_ext_max = ee_len;
|
|
|
|
if (ext_depth(inode) > sbi->s_depth_max)
|
|
|
|
sbi->s_depth_max = ext_depth(inode);
|
|
|
|
spin_unlock(&sbi->s_ext_stats_lock);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
if (from >= le32_to_cpu(ex->ee_block)
|
2007-07-18 05:42:41 +04:00
|
|
|
&& to == le32_to_cpu(ex->ee_block) + ee_len - 1) {
|
2006-10-11 12:21:03 +04:00
|
|
|
/* tail removal */
|
2008-01-29 07:58:27 +03:00
|
|
|
ext4_lblk_t num;
|
2014-11-23 08:59:39 +03:00
|
|
|
long long first_cluster;
|
2008-01-29 07:58:27 +03:00
|
|
|
|
2007-07-18 05:42:41 +04:00
|
|
|
num = le32_to_cpu(ex->ee_block) + ee_len - from;
|
2011-09-10 02:54:51 +04:00
|
|
|
pblk = ext4_ext_pblock(ex) + ee_len - num;
|
2013-05-28 07:33:35 +04:00
|
|
|
/*
|
|
|
|
* Usually we want to free partial cluster at the end of the
|
|
|
|
* extent, except for the situation when the cluster is still
|
|
|
|
* used by any other extent (partial_cluster is negative).
|
|
|
|
*/
|
|
|
|
if (*partial_cluster < 0 &&
|
2014-11-23 08:59:39 +03:00
|
|
|
*partial_cluster == -(long long) EXT4_B2C(sbi, pblk+num-1))
|
2013-05-28 07:33:35 +04:00
|
|
|
flags |= EXT4_FREE_BLOCKS_NOFREE_LAST_CLUSTER;
|
|
|
|
|
|
|
|
ext_debug("free last %u blocks starting %llu partial %lld\n",
|
|
|
|
num, pblk, *partial_cluster);
|
2011-09-10 02:54:51 +04:00
|
|
|
ext4_free_blocks(handle, inode, NULL, pblk, num, flags);
|
|
|
|
/*
|
|
|
|
* If the block range to be freed didn't start at the
|
|
|
|
* beginning of a cluster, and we removed the entire
|
2013-05-28 07:33:35 +04:00
|
|
|
* extent and the cluster is not used by any other extent,
|
|
|
|
* save the partial cluster here, since we might need to
|
2014-11-23 08:59:39 +03:00
|
|
|
* delete if we determine that the truncate or punch hole
|
|
|
|
* operation has removed all of the blocks in the cluster.
|
|
|
|
* If that cluster is used by another extent, preserve its
|
|
|
|
* negative value so it isn't freed later on.
|
2013-05-28 07:33:35 +04:00
|
|
|
*
|
2014-11-23 08:59:39 +03:00
|
|
|
* If the whole extent wasn't freed, we've reached the
|
|
|
|
* start of the truncated/punched region and have finished
|
|
|
|
* removing blocks. If there's a partial cluster here it's
|
|
|
|
* shared with the remainder of the extent and is no longer
|
|
|
|
* a candidate for removal.
|
2011-09-10 02:54:51 +04:00
|
|
|
*/
|
2014-11-23 08:59:39 +03:00
|
|
|
if (EXT4_PBLK_COFF(sbi, pblk) && ee_len == num) {
|
|
|
|
first_cluster = (long long) EXT4_B2C(sbi, pblk);
|
|
|
|
if (first_cluster != -*partial_cluster)
|
|
|
|
*partial_cluster = first_cluster;
|
|
|
|
} else {
|
2011-09-10 02:54:51 +04:00
|
|
|
*partial_cluster = 0;
|
2014-11-23 08:59:39 +03:00
|
|
|
}
|
2013-05-28 07:32:35 +04:00
|
|
|
} else
|
|
|
|
ext4_error(sbi->s_sb, "strange request: removal(2) "
|
|
|
|
"%u-%u from %u:%u\n",
|
|
|
|
from, to, le32_to_cpu(ex->ee_block), ee_len);
|
2006-10-11 12:21:03 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-05-25 15:41:43 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* ext4_ext_rm_leaf() Removes the extents associated with the
|
2014-11-23 08:58:11 +03:00
|
|
|
* blocks appearing between "start" and "end". Both "start"
|
|
|
|
* and "end" must appear in the same extent or EIO is returned.
|
2011-05-25 15:41:43 +04:00
|
|
|
*
|
|
|
|
* @handle: The journal handle
|
|
|
|
* @inode: The files inode
|
|
|
|
* @path: The path to the leaf
|
2013-05-28 07:33:35 +04:00
|
|
|
* @partial_cluster: The cluster which we'll have to free if all extents
|
2014-11-23 08:58:11 +03:00
|
|
|
* has been released from it. However, if this value is
|
|
|
|
* negative, it's a cluster just to the right of the
|
|
|
|
* punched region and it must not be freed.
|
2011-05-25 15:41:43 +04:00
|
|
|
* @start: The first block to remove
|
|
|
|
* @end: The last block to remove
|
|
|
|
*/
|
2006-10-11 12:21:03 +04:00
|
|
|
static int
|
|
|
|
ext4_ext_rm_leaf(handle_t *handle, struct inode *inode,
|
2013-05-28 07:33:35 +04:00
|
|
|
struct ext4_ext_path *path,
|
|
|
|
long long *partial_cluster,
|
2011-09-10 02:54:51 +04:00
|
|
|
ext4_lblk_t start, ext4_lblk_t end)
|
2006-10-11 12:21:03 +04:00
|
|
|
{
|
2011-09-10 02:54:51 +04:00
|
|
|
struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
|
2006-10-11 12:21:03 +04:00
|
|
|
int err = 0, correct_index = 0;
|
|
|
|
int depth = ext_depth(inode), credits;
|
|
|
|
struct ext4_extent_header *eh;
|
2011-10-25 13:35:05 +04:00
|
|
|
ext4_lblk_t a, b;
|
2008-01-29 07:58:27 +03:00
|
|
|
unsigned num;
|
|
|
|
ext4_lblk_t ex_ee_block;
|
2006-10-11 12:21:03 +04:00
|
|
|
unsigned short ex_ee_len;
|
2014-04-21 07:45:47 +04:00
|
|
|
unsigned unwritten = 0;
|
2006-10-11 12:21:03 +04:00
|
|
|
struct ext4_extent *ex;
|
2013-05-28 07:33:35 +04:00
|
|
|
ext4_fsblk_t pblk;
|
2006-10-11 12:21:03 +04:00
|
|
|
|
2007-07-18 17:19:09 +04:00
|
|
|
/* the header must be checked already in ext4_ext_remove_space() */
|
ext4: rewrite punch hole to use ext4_ext_remove_space()
This commit rewrites ext4 punch hole implementation to use
ext4_ext_remove_space() instead of its home gown way of doing this via
ext4_ext_map_blocks(). There are several reasons for changing this.
Firstly it is quite non obvious that punching hole needs to
ext4_ext_map_blocks() to punch a hole, especially given that this
function should map blocks, not unmap it. It also required a lot of new
code in ext4_ext_map_blocks().
Secondly the design of it is not very effective. The reason is that we
are trying to punch out blocks in ext4_ext_punch_hole() in opposite
direction than in ext4_ext_rm_leaf() which causes the ext4_ext_rm_leaf()
to iterate through the whole tree from the end to the start to find the
requested extent for every extent we are going to punch out.
And finally the current implementation does not use the existing code,
but bring a lot of new code, which is IMO unnecessary since there
already is some infrastructure we can use. Specifically
ext4_ext_remove_space().
This commit changes ext4_ext_remove_space() to accept 'end' parameter so
we can not only truncate to the end of file, but also remove the space
in the middle of the file (punch a hole). Moreover, because the last
block to punch out, might be in the middle of the extent, we have to
split the extent at 'end + 1' so ext4_ext_rm_leaf() can easily either
remove the whole fist part of split extent, or change its size.
ext4_ext_remove_space() is then used to actually remove the space
(extents) from within the hole, instead of ext4_ext_map_blocks().
Note that this also fix the issue with punch hole, where we would forget
to remove empty index blocks from the extent tree, resulting in double
free block error and file system corruption. This is simply because we
now use different code path, where this problem does not exist.
This has been tested with fsx running for several days and xfstests,
plus xfstest #251 with '-o discard' run on the loop image (which
converts discard requestes into punch hole to the backing file). All of
it on 1K and 4K file system block size.
Signed-off-by: Lukas Czerner <lczerner@redhat.com>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
2012-03-20 07:03:19 +04:00
|
|
|
ext_debug("truncate since %u in leaf to %u\n", start, end);
|
2006-10-11 12:21:03 +04:00
|
|
|
if (!path[depth].p_hdr)
|
|
|
|
path[depth].p_hdr = ext_block_hdr(path[depth].p_bh);
|
|
|
|
eh = path[depth].p_hdr;
|
2010-03-02 19:46:09 +03:00
|
|
|
if (unlikely(path[depth].p_hdr == NULL)) {
|
|
|
|
EXT4_ERROR_INODE(inode, "path[%d].p_hdr == NULL", depth);
|
2015-10-17 23:16:04 +03:00
|
|
|
return -EFSCORRUPTED;
|
2010-03-02 19:46:09 +03:00
|
|
|
}
|
2006-10-11 12:21:03 +04:00
|
|
|
/* find where to start removing */
|
2013-07-01 16:12:41 +04:00
|
|
|
ex = path[depth].p_ext;
|
|
|
|
if (!ex)
|
|
|
|
ex = EXT_LAST_EXTENT(eh);
|
2006-10-11 12:21:03 +04:00
|
|
|
|
|
|
|
ex_ee_block = le32_to_cpu(ex->ee_block);
|
2007-07-18 05:42:41 +04:00
|
|
|
ex_ee_len = ext4_ext_get_actual_len(ex);
|
2006-10-11 12:21:03 +04:00
|
|
|
|
2011-09-10 03:18:51 +04:00
|
|
|
trace_ext4_ext_rm_leaf(inode, start, ex, *partial_cluster);
|
|
|
|
|
2006-10-11 12:21:03 +04:00
|
|
|
while (ex >= EXT_FIRST_EXTENT(eh) &&
|
|
|
|
ex_ee_block + ex_ee_len > start) {
|
2009-06-10 22:22:55 +04:00
|
|
|
|
2014-04-21 07:45:47 +04:00
|
|
|
if (ext4_ext_is_unwritten(ex))
|
|
|
|
unwritten = 1;
|
2009-06-10 22:22:55 +04:00
|
|
|
else
|
2014-04-21 07:45:47 +04:00
|
|
|
unwritten = 0;
|
2009-06-10 22:22:55 +04:00
|
|
|
|
2009-09-18 21:34:55 +04:00
|
|
|
ext_debug("remove ext %u:[%d]%d\n", ex_ee_block,
|
2014-04-21 07:45:47 +04:00
|
|
|
unwritten, ex_ee_len);
|
2006-10-11 12:21:03 +04:00
|
|
|
path[depth].p_ext = ex;
|
|
|
|
|
|
|
|
a = ex_ee_block > start ? ex_ee_block : start;
|
2011-05-25 15:41:43 +04:00
|
|
|
b = ex_ee_block+ex_ee_len - 1 < end ?
|
|
|
|
ex_ee_block+ex_ee_len - 1 : end;
|
2006-10-11 12:21:03 +04:00
|
|
|
|
|
|
|
ext_debug(" border %u:%u\n", a, b);
|
|
|
|
|
2011-05-25 15:41:43 +04:00
|
|
|
/* If this extent is beyond the end of the hole, skip it */
|
ext4: rewrite punch hole to use ext4_ext_remove_space()
This commit rewrites ext4 punch hole implementation to use
ext4_ext_remove_space() instead of its home gown way of doing this via
ext4_ext_map_blocks(). There are several reasons for changing this.
Firstly it is quite non obvious that punching hole needs to
ext4_ext_map_blocks() to punch a hole, especially given that this
function should map blocks, not unmap it. It also required a lot of new
code in ext4_ext_map_blocks().
Secondly the design of it is not very effective. The reason is that we
are trying to punch out blocks in ext4_ext_punch_hole() in opposite
direction than in ext4_ext_rm_leaf() which causes the ext4_ext_rm_leaf()
to iterate through the whole tree from the end to the start to find the
requested extent for every extent we are going to punch out.
And finally the current implementation does not use the existing code,
but bring a lot of new code, which is IMO unnecessary since there
already is some infrastructure we can use. Specifically
ext4_ext_remove_space().
This commit changes ext4_ext_remove_space() to accept 'end' parameter so
we can not only truncate to the end of file, but also remove the space
in the middle of the file (punch a hole). Moreover, because the last
block to punch out, might be in the middle of the extent, we have to
split the extent at 'end + 1' so ext4_ext_rm_leaf() can easily either
remove the whole fist part of split extent, or change its size.
ext4_ext_remove_space() is then used to actually remove the space
(extents) from within the hole, instead of ext4_ext_map_blocks().
Note that this also fix the issue with punch hole, where we would forget
to remove empty index blocks from the extent tree, resulting in double
free block error and file system corruption. This is simply because we
now use different code path, where this problem does not exist.
This has been tested with fsx running for several days and xfstests,
plus xfstest #251 with '-o discard' run on the loop image (which
converts discard requestes into punch hole to the backing file). All of
it on 1K and 4K file system block size.
Signed-off-by: Lukas Czerner <lczerner@redhat.com>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
2012-03-20 07:03:19 +04:00
|
|
|
if (end < ex_ee_block) {
|
2013-05-28 07:33:35 +04:00
|
|
|
/*
|
|
|
|
* We're going to skip this extent and move to another,
|
2014-11-23 08:55:42 +03:00
|
|
|
* so note that its first cluster is in use to avoid
|
|
|
|
* freeing it when removing blocks. Eventually, the
|
|
|
|
* right edge of the truncated/punched region will
|
|
|
|
* be just to the left.
|
2013-05-28 07:33:35 +04:00
|
|
|
*/
|
2014-11-23 08:55:42 +03:00
|
|
|
if (sbi->s_cluster_ratio > 1) {
|
|
|
|
pblk = ext4_ext_pblock(ex);
|
2013-05-28 07:33:35 +04:00
|
|
|
*partial_cluster =
|
2014-11-23 08:55:42 +03:00
|
|
|
-(long long) EXT4_B2C(sbi, pblk);
|
|
|
|
}
|
2011-05-25 15:41:43 +04:00
|
|
|
ex--;
|
|
|
|
ex_ee_block = le32_to_cpu(ex->ee_block);
|
|
|
|
ex_ee_len = ext4_ext_get_actual_len(ex);
|
|
|
|
continue;
|
2011-10-25 13:35:05 +04:00
|
|
|
} else if (b != ex_ee_block + ex_ee_len - 1) {
|
2012-03-20 07:07:43 +04:00
|
|
|
EXT4_ERROR_INODE(inode,
|
|
|
|
"can not handle truncate %u:%u "
|
|
|
|
"on extent %u:%u",
|
|
|
|
start, end, ex_ee_block,
|
|
|
|
ex_ee_block + ex_ee_len - 1);
|
2015-10-17 23:16:04 +03:00
|
|
|
err = -EFSCORRUPTED;
|
2011-10-25 13:35:05 +04:00
|
|
|
goto out;
|
2006-10-11 12:21:03 +04:00
|
|
|
} else if (a != ex_ee_block) {
|
|
|
|
/* remove tail of the extent */
|
2011-10-25 13:35:05 +04:00
|
|
|
num = a - ex_ee_block;
|
2006-10-11 12:21:03 +04:00
|
|
|
} else {
|
|
|
|
/* remove whole extent: excellent! */
|
|
|
|
num = 0;
|
|
|
|
}
|
2008-08-02 05:59:19 +04:00
|
|
|
/*
|
|
|
|
* 3 for leaf, sb, and inode plus 2 (bmap and group
|
|
|
|
* descriptor) for each block group; assume two block
|
|
|
|
* groups plus ex_ee_len/blocks_per_block_group for
|
|
|
|
* the worst case
|
|
|
|
*/
|
|
|
|
credits = 7 + 2*(ex_ee_len/EXT4_BLOCKS_PER_GROUP(inode->i_sb));
|
2006-10-11 12:21:03 +04:00
|
|
|
if (ex == EXT_FIRST_EXTENT(eh)) {
|
|
|
|
correct_index = 1;
|
|
|
|
credits += (ext_depth(inode)) + 1;
|
|
|
|
}
|
2009-12-09 06:42:15 +03:00
|
|
|
credits += EXT4_MAXQUOTAS_TRANS_BLOCKS(inode->i_sb);
|
2006-10-11 12:21:03 +04:00
|
|
|
|
2009-08-18 06:17:20 +04:00
|
|
|
err = ext4_ext_truncate_extend_restart(handle, inode, credits);
|
2008-07-12 03:27:31 +04:00
|
|
|
if (err)
|
2006-10-11 12:21:03 +04:00
|
|
|
goto out;
|
|
|
|
|
|
|
|
err = ext4_ext_get_access(handle, inode, path + depth);
|
|
|
|
if (err)
|
|
|
|
goto out;
|
|
|
|
|
2011-09-10 02:54:51 +04:00
|
|
|
err = ext4_remove_blocks(handle, inode, ex, partial_cluster,
|
|
|
|
a, b);
|
2006-10-11 12:21:03 +04:00
|
|
|
if (err)
|
|
|
|
goto out;
|
|
|
|
|
2011-10-25 13:35:05 +04:00
|
|
|
if (num == 0)
|
2006-10-11 12:21:07 +04:00
|
|
|
/* this extent is removed; mark slot entirely unused */
|
2006-10-11 12:21:05 +04:00
|
|
|
ext4_ext_store_pblock(ex, 0);
|
2006-10-11 12:21:03 +04:00
|
|
|
|
|
|
|
ex->ee_len = cpu_to_le16(num);
|
2007-07-18 17:02:56 +04:00
|
|
|
/*
|
2014-04-21 07:45:47 +04:00
|
|
|
* Do not mark unwritten if all the blocks in the
|
2007-07-18 17:02:56 +04:00
|
|
|
* extent have been removed.
|
|
|
|
*/
|
2014-04-21 07:45:47 +04:00
|
|
|
if (unwritten && num)
|
|
|
|
ext4_ext_mark_unwritten(ex);
|
2011-05-25 15:41:43 +04:00
|
|
|
/*
|
|
|
|
* If the extent was completely released,
|
|
|
|
* we need to remove it from the leaf
|
|
|
|
*/
|
|
|
|
if (num == 0) {
|
2011-06-06 08:05:17 +04:00
|
|
|
if (end != EXT_MAX_BLOCKS - 1) {
|
2011-05-25 15:41:43 +04:00
|
|
|
/*
|
|
|
|
* For hole punching, we need to scoot all the
|
|
|
|
* extents up when an extent is removed so that
|
|
|
|
* we dont have blank extents in the middle
|
|
|
|
*/
|
|
|
|
memmove(ex, ex+1, (EXT_LAST_EXTENT(eh) - ex) *
|
|
|
|
sizeof(struct ext4_extent));
|
|
|
|
|
|
|
|
/* Now get rid of the one at the end */
|
|
|
|
memset(EXT_LAST_EXTENT(eh), 0,
|
|
|
|
sizeof(struct ext4_extent));
|
|
|
|
}
|
|
|
|
le16_add_cpu(&eh->eh_entries, -1);
|
2014-11-23 08:58:11 +03:00
|
|
|
}
|
2011-05-25 15:41:43 +04:00
|
|
|
|
2011-10-25 13:35:05 +04:00
|
|
|
err = ext4_ext_dirty(handle, inode, path + depth);
|
|
|
|
if (err)
|
|
|
|
goto out;
|
|
|
|
|
2011-11-02 02:59:26 +04:00
|
|
|
ext_debug("new extent: %u:%u:%llu\n", ex_ee_block, num,
|
2010-10-28 05:30:14 +04:00
|
|
|
ext4_ext_pblock(ex));
|
2006-10-11 12:21:03 +04:00
|
|
|
ex--;
|
|
|
|
ex_ee_block = le32_to_cpu(ex->ee_block);
|
2007-07-18 05:42:41 +04:00
|
|
|
ex_ee_len = ext4_ext_get_actual_len(ex);
|
2006-10-11 12:21:03 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (correct_index && eh->eh_entries)
|
|
|
|
err = ext4_ext_correct_indexes(handle, inode, path);
|
|
|
|
|
2011-09-10 02:54:51 +04:00
|
|
|
/*
|
2014-04-02 03:49:30 +04:00
|
|
|
* If there's a partial cluster and at least one extent remains in
|
|
|
|
* the leaf, free the partial cluster if it isn't shared with the
|
2014-11-23 08:58:11 +03:00
|
|
|
* current extent. If it is shared with the current extent
|
|
|
|
* we zero partial_cluster because we've reached the start of the
|
|
|
|
* truncated/punched region and we're done removing blocks.
|
2011-09-10 02:54:51 +04:00
|
|
|
*/
|
2014-11-23 08:58:11 +03:00
|
|
|
if (*partial_cluster > 0 && ex >= EXT_FIRST_EXTENT(eh)) {
|
|
|
|
pblk = ext4_ext_pblock(ex) + ex_ee_len - 1;
|
|
|
|
if (*partial_cluster != (long long) EXT4_B2C(sbi, pblk)) {
|
|
|
|
ext4_free_blocks(handle, inode, NULL,
|
|
|
|
EXT4_C2B(sbi, *partial_cluster),
|
|
|
|
sbi->s_cluster_ratio,
|
|
|
|
get_default_free_blocks_flags(inode));
|
|
|
|
}
|
2011-09-10 02:54:51 +04:00
|
|
|
*partial_cluster = 0;
|
|
|
|
}
|
|
|
|
|
2006-10-11 12:21:03 +04:00
|
|
|
/* if this leaf is free, then we should
|
|
|
|
* remove it from index block above */
|
|
|
|
if (err == 0 && eh->eh_entries == 0 && path[depth].p_bh != NULL)
|
2012-12-17 18:55:39 +04:00
|
|
|
err = ext4_ext_rm_idx(handle, inode, path, depth);
|
2006-10-11 12:21:03 +04:00
|
|
|
|
|
|
|
out:
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2006-10-11 12:21:07 +04:00
|
|
|
* ext4_ext_more_to_rm:
|
|
|
|
* returns 1 if current index has to be freed (even partial)
|
2006-10-11 12:21:03 +04:00
|
|
|
*/
|
2006-12-07 07:41:36 +03:00
|
|
|
static int
|
2006-10-11 12:21:03 +04:00
|
|
|
ext4_ext_more_to_rm(struct ext4_ext_path *path)
|
|
|
|
{
|
|
|
|
BUG_ON(path->p_idx == NULL);
|
|
|
|
|
|
|
|
if (path->p_idx < EXT_FIRST_INDEX(path->p_hdr))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/*
|
2006-10-11 12:21:07 +04:00
|
|
|
* if truncate on deeper level happened, it wasn't partial,
|
2006-10-11 12:21:03 +04:00
|
|
|
* so we have to consider current index for truncation
|
|
|
|
*/
|
|
|
|
if (le16_to_cpu(path->p_hdr->eh_entries) == path->p_block)
|
|
|
|
return 0;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2013-04-03 20:45:17 +04:00
|
|
|
int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start,
|
|
|
|
ext4_lblk_t end)
|
2006-10-11 12:21:03 +04:00
|
|
|
{
|
2014-11-23 08:55:42 +03:00
|
|
|
struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
|
2006-10-11 12:21:03 +04:00
|
|
|
int depth = ext_depth(inode);
|
2012-07-23 06:49:08 +04:00
|
|
|
struct ext4_ext_path *path = NULL;
|
2013-05-28 07:33:35 +04:00
|
|
|
long long partial_cluster = 0;
|
2006-10-11 12:21:03 +04:00
|
|
|
handle_t *handle;
|
2012-10-01 07:03:50 +04:00
|
|
|
int i = 0, err = 0;
|
2006-10-11 12:21:03 +04:00
|
|
|
|
ext4: rewrite punch hole to use ext4_ext_remove_space()
This commit rewrites ext4 punch hole implementation to use
ext4_ext_remove_space() instead of its home gown way of doing this via
ext4_ext_map_blocks(). There are several reasons for changing this.
Firstly it is quite non obvious that punching hole needs to
ext4_ext_map_blocks() to punch a hole, especially given that this
function should map blocks, not unmap it. It also required a lot of new
code in ext4_ext_map_blocks().
Secondly the design of it is not very effective. The reason is that we
are trying to punch out blocks in ext4_ext_punch_hole() in opposite
direction than in ext4_ext_rm_leaf() which causes the ext4_ext_rm_leaf()
to iterate through the whole tree from the end to the start to find the
requested extent for every extent we are going to punch out.
And finally the current implementation does not use the existing code,
but bring a lot of new code, which is IMO unnecessary since there
already is some infrastructure we can use. Specifically
ext4_ext_remove_space().
This commit changes ext4_ext_remove_space() to accept 'end' parameter so
we can not only truncate to the end of file, but also remove the space
in the middle of the file (punch a hole). Moreover, because the last
block to punch out, might be in the middle of the extent, we have to
split the extent at 'end + 1' so ext4_ext_rm_leaf() can easily either
remove the whole fist part of split extent, or change its size.
ext4_ext_remove_space() is then used to actually remove the space
(extents) from within the hole, instead of ext4_ext_map_blocks().
Note that this also fix the issue with punch hole, where we would forget
to remove empty index blocks from the extent tree, resulting in double
free block error and file system corruption. This is simply because we
now use different code path, where this problem does not exist.
This has been tested with fsx running for several days and xfstests,
plus xfstest #251 with '-o discard' run on the loop image (which
converts discard requestes into punch hole to the backing file). All of
it on 1K and 4K file system block size.
Signed-off-by: Lukas Czerner <lczerner@redhat.com>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
2012-03-20 07:03:19 +04:00
|
|
|
ext_debug("truncate since %u to %u\n", start, end);
|
2006-10-11 12:21:03 +04:00
|
|
|
|
|
|
|
/* probably first extent we're gonna free will be last in block */
|
2013-02-09 06:59:22 +04:00
|
|
|
handle = ext4_journal_start(inode, EXT4_HT_TRUNCATE, depth + 1);
|
2006-10-11 12:21:03 +04:00
|
|
|
if (IS_ERR(handle))
|
|
|
|
return PTR_ERR(handle);
|
|
|
|
|
2010-05-17 09:00:00 +04:00
|
|
|
again:
|
2013-05-28 07:32:35 +04:00
|
|
|
trace_ext4_ext_remove_space(inode, start, end, depth);
|
2011-09-10 03:18:51 +04:00
|
|
|
|
ext4: rewrite punch hole to use ext4_ext_remove_space()
This commit rewrites ext4 punch hole implementation to use
ext4_ext_remove_space() instead of its home gown way of doing this via
ext4_ext_map_blocks(). There are several reasons for changing this.
Firstly it is quite non obvious that punching hole needs to
ext4_ext_map_blocks() to punch a hole, especially given that this
function should map blocks, not unmap it. It also required a lot of new
code in ext4_ext_map_blocks().
Secondly the design of it is not very effective. The reason is that we
are trying to punch out blocks in ext4_ext_punch_hole() in opposite
direction than in ext4_ext_rm_leaf() which causes the ext4_ext_rm_leaf()
to iterate through the whole tree from the end to the start to find the
requested extent for every extent we are going to punch out.
And finally the current implementation does not use the existing code,
but bring a lot of new code, which is IMO unnecessary since there
already is some infrastructure we can use. Specifically
ext4_ext_remove_space().
This commit changes ext4_ext_remove_space() to accept 'end' parameter so
we can not only truncate to the end of file, but also remove the space
in the middle of the file (punch a hole). Moreover, because the last
block to punch out, might be in the middle of the extent, we have to
split the extent at 'end + 1' so ext4_ext_rm_leaf() can easily either
remove the whole fist part of split extent, or change its size.
ext4_ext_remove_space() is then used to actually remove the space
(extents) from within the hole, instead of ext4_ext_map_blocks().
Note that this also fix the issue with punch hole, where we would forget
to remove empty index blocks from the extent tree, resulting in double
free block error and file system corruption. This is simply because we
now use different code path, where this problem does not exist.
This has been tested with fsx running for several days and xfstests,
plus xfstest #251 with '-o discard' run on the loop image (which
converts discard requestes into punch hole to the backing file). All of
it on 1K and 4K file system block size.
Signed-off-by: Lukas Czerner <lczerner@redhat.com>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
2012-03-20 07:03:19 +04:00
|
|
|
/*
|
|
|
|
* Check if we are removing extents inside the extent tree. If that
|
|
|
|
* is the case, we are going to punch a hole inside the extent tree
|
|
|
|
* so we have to check whether we need to split the extent covering
|
|
|
|
* the last block to remove so we can easily remove the part of it
|
|
|
|
* in ext4_ext_rm_leaf().
|
|
|
|
*/
|
|
|
|
if (end < EXT_MAX_BLOCKS - 1) {
|
|
|
|
struct ext4_extent *ex;
|
2014-11-23 08:55:42 +03:00
|
|
|
ext4_lblk_t ee_block, ex_end, lblk;
|
|
|
|
ext4_fsblk_t pblk;
|
ext4: rewrite punch hole to use ext4_ext_remove_space()
This commit rewrites ext4 punch hole implementation to use
ext4_ext_remove_space() instead of its home gown way of doing this via
ext4_ext_map_blocks(). There are several reasons for changing this.
Firstly it is quite non obvious that punching hole needs to
ext4_ext_map_blocks() to punch a hole, especially given that this
function should map blocks, not unmap it. It also required a lot of new
code in ext4_ext_map_blocks().
Secondly the design of it is not very effective. The reason is that we
are trying to punch out blocks in ext4_ext_punch_hole() in opposite
direction than in ext4_ext_rm_leaf() which causes the ext4_ext_rm_leaf()
to iterate through the whole tree from the end to the start to find the
requested extent for every extent we are going to punch out.
And finally the current implementation does not use the existing code,
but bring a lot of new code, which is IMO unnecessary since there
already is some infrastructure we can use. Specifically
ext4_ext_remove_space().
This commit changes ext4_ext_remove_space() to accept 'end' parameter so
we can not only truncate to the end of file, but also remove the space
in the middle of the file (punch a hole). Moreover, because the last
block to punch out, might be in the middle of the extent, we have to
split the extent at 'end + 1' so ext4_ext_rm_leaf() can easily either
remove the whole fist part of split extent, or change its size.
ext4_ext_remove_space() is then used to actually remove the space
(extents) from within the hole, instead of ext4_ext_map_blocks().
Note that this also fix the issue with punch hole, where we would forget
to remove empty index blocks from the extent tree, resulting in double
free block error and file system corruption. This is simply because we
now use different code path, where this problem does not exist.
This has been tested with fsx running for several days and xfstests,
plus xfstest #251 with '-o discard' run on the loop image (which
converts discard requestes into punch hole to the backing file). All of
it on 1K and 4K file system block size.
Signed-off-by: Lukas Czerner <lczerner@redhat.com>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
2012-03-20 07:03:19 +04:00
|
|
|
|
2014-11-23 08:55:42 +03:00
|
|
|
/* find extent for or closest extent to this block */
|
2014-09-01 22:43:09 +04:00
|
|
|
path = ext4_find_extent(inode, end, NULL, EXT4_EX_NOCACHE);
|
ext4: rewrite punch hole to use ext4_ext_remove_space()
This commit rewrites ext4 punch hole implementation to use
ext4_ext_remove_space() instead of its home gown way of doing this via
ext4_ext_map_blocks(). There are several reasons for changing this.
Firstly it is quite non obvious that punching hole needs to
ext4_ext_map_blocks() to punch a hole, especially given that this
function should map blocks, not unmap it. It also required a lot of new
code in ext4_ext_map_blocks().
Secondly the design of it is not very effective. The reason is that we
are trying to punch out blocks in ext4_ext_punch_hole() in opposite
direction than in ext4_ext_rm_leaf() which causes the ext4_ext_rm_leaf()
to iterate through the whole tree from the end to the start to find the
requested extent for every extent we are going to punch out.
And finally the current implementation does not use the existing code,
but bring a lot of new code, which is IMO unnecessary since there
already is some infrastructure we can use. Specifically
ext4_ext_remove_space().
This commit changes ext4_ext_remove_space() to accept 'end' parameter so
we can not only truncate to the end of file, but also remove the space
in the middle of the file (punch a hole). Moreover, because the last
block to punch out, might be in the middle of the extent, we have to
split the extent at 'end + 1' so ext4_ext_rm_leaf() can easily either
remove the whole fist part of split extent, or change its size.
ext4_ext_remove_space() is then used to actually remove the space
(extents) from within the hole, instead of ext4_ext_map_blocks().
Note that this also fix the issue with punch hole, where we would forget
to remove empty index blocks from the extent tree, resulting in double
free block error and file system corruption. This is simply because we
now use different code path, where this problem does not exist.
This has been tested with fsx running for several days and xfstests,
plus xfstest #251 with '-o discard' run on the loop image (which
converts discard requestes into punch hole to the backing file). All of
it on 1K and 4K file system block size.
Signed-off-by: Lukas Czerner <lczerner@redhat.com>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
2012-03-20 07:03:19 +04:00
|
|
|
if (IS_ERR(path)) {
|
|
|
|
ext4_journal_stop(handle);
|
|
|
|
return PTR_ERR(path);
|
|
|
|
}
|
|
|
|
depth = ext_depth(inode);
|
2012-10-01 07:03:50 +04:00
|
|
|
/* Leaf not may not exist only if inode has no blocks at all */
|
ext4: rewrite punch hole to use ext4_ext_remove_space()
This commit rewrites ext4 punch hole implementation to use
ext4_ext_remove_space() instead of its home gown way of doing this via
ext4_ext_map_blocks(). There are several reasons for changing this.
Firstly it is quite non obvious that punching hole needs to
ext4_ext_map_blocks() to punch a hole, especially given that this
function should map blocks, not unmap it. It also required a lot of new
code in ext4_ext_map_blocks().
Secondly the design of it is not very effective. The reason is that we
are trying to punch out blocks in ext4_ext_punch_hole() in opposite
direction than in ext4_ext_rm_leaf() which causes the ext4_ext_rm_leaf()
to iterate through the whole tree from the end to the start to find the
requested extent for every extent we are going to punch out.
And finally the current implementation does not use the existing code,
but bring a lot of new code, which is IMO unnecessary since there
already is some infrastructure we can use. Specifically
ext4_ext_remove_space().
This commit changes ext4_ext_remove_space() to accept 'end' parameter so
we can not only truncate to the end of file, but also remove the space
in the middle of the file (punch a hole). Moreover, because the last
block to punch out, might be in the middle of the extent, we have to
split the extent at 'end + 1' so ext4_ext_rm_leaf() can easily either
remove the whole fist part of split extent, or change its size.
ext4_ext_remove_space() is then used to actually remove the space
(extents) from within the hole, instead of ext4_ext_map_blocks().
Note that this also fix the issue with punch hole, where we would forget
to remove empty index blocks from the extent tree, resulting in double
free block error and file system corruption. This is simply because we
now use different code path, where this problem does not exist.
This has been tested with fsx running for several days and xfstests,
plus xfstest #251 with '-o discard' run on the loop image (which
converts discard requestes into punch hole to the backing file). All of
it on 1K and 4K file system block size.
Signed-off-by: Lukas Czerner <lczerner@redhat.com>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
2012-03-20 07:03:19 +04:00
|
|
|
ex = path[depth].p_ext;
|
2012-07-23 06:49:08 +04:00
|
|
|
if (!ex) {
|
2012-10-01 07:03:50 +04:00
|
|
|
if (depth) {
|
|
|
|
EXT4_ERROR_INODE(inode,
|
|
|
|
"path[%d].p_hdr == NULL",
|
|
|
|
depth);
|
2015-10-17 23:16:04 +03:00
|
|
|
err = -EFSCORRUPTED;
|
2012-10-01 07:03:50 +04:00
|
|
|
}
|
|
|
|
goto out;
|
2012-07-23 06:49:08 +04:00
|
|
|
}
|
ext4: rewrite punch hole to use ext4_ext_remove_space()
This commit rewrites ext4 punch hole implementation to use
ext4_ext_remove_space() instead of its home gown way of doing this via
ext4_ext_map_blocks(). There are several reasons for changing this.
Firstly it is quite non obvious that punching hole needs to
ext4_ext_map_blocks() to punch a hole, especially given that this
function should map blocks, not unmap it. It also required a lot of new
code in ext4_ext_map_blocks().
Secondly the design of it is not very effective. The reason is that we
are trying to punch out blocks in ext4_ext_punch_hole() in opposite
direction than in ext4_ext_rm_leaf() which causes the ext4_ext_rm_leaf()
to iterate through the whole tree from the end to the start to find the
requested extent for every extent we are going to punch out.
And finally the current implementation does not use the existing code,
but bring a lot of new code, which is IMO unnecessary since there
already is some infrastructure we can use. Specifically
ext4_ext_remove_space().
This commit changes ext4_ext_remove_space() to accept 'end' parameter so
we can not only truncate to the end of file, but also remove the space
in the middle of the file (punch a hole). Moreover, because the last
block to punch out, might be in the middle of the extent, we have to
split the extent at 'end + 1' so ext4_ext_rm_leaf() can easily either
remove the whole fist part of split extent, or change its size.
ext4_ext_remove_space() is then used to actually remove the space
(extents) from within the hole, instead of ext4_ext_map_blocks().
Note that this also fix the issue with punch hole, where we would forget
to remove empty index blocks from the extent tree, resulting in double
free block error and file system corruption. This is simply because we
now use different code path, where this problem does not exist.
This has been tested with fsx running for several days and xfstests,
plus xfstest #251 with '-o discard' run on the loop image (which
converts discard requestes into punch hole to the backing file). All of
it on 1K and 4K file system block size.
Signed-off-by: Lukas Czerner <lczerner@redhat.com>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
2012-03-20 07:03:19 +04:00
|
|
|
|
|
|
|
ee_block = le32_to_cpu(ex->ee_block);
|
2014-11-23 08:55:42 +03:00
|
|
|
ex_end = ee_block + ext4_ext_get_actual_len(ex) - 1;
|
ext4: rewrite punch hole to use ext4_ext_remove_space()
This commit rewrites ext4 punch hole implementation to use
ext4_ext_remove_space() instead of its home gown way of doing this via
ext4_ext_map_blocks(). There are several reasons for changing this.
Firstly it is quite non obvious that punching hole needs to
ext4_ext_map_blocks() to punch a hole, especially given that this
function should map blocks, not unmap it. It also required a lot of new
code in ext4_ext_map_blocks().
Secondly the design of it is not very effective. The reason is that we
are trying to punch out blocks in ext4_ext_punch_hole() in opposite
direction than in ext4_ext_rm_leaf() which causes the ext4_ext_rm_leaf()
to iterate through the whole tree from the end to the start to find the
requested extent for every extent we are going to punch out.
And finally the current implementation does not use the existing code,
but bring a lot of new code, which is IMO unnecessary since there
already is some infrastructure we can use. Specifically
ext4_ext_remove_space().
This commit changes ext4_ext_remove_space() to accept 'end' parameter so
we can not only truncate to the end of file, but also remove the space
in the middle of the file (punch a hole). Moreover, because the last
block to punch out, might be in the middle of the extent, we have to
split the extent at 'end + 1' so ext4_ext_rm_leaf() can easily either
remove the whole fist part of split extent, or change its size.
ext4_ext_remove_space() is then used to actually remove the space
(extents) from within the hole, instead of ext4_ext_map_blocks().
Note that this also fix the issue with punch hole, where we would forget
to remove empty index blocks from the extent tree, resulting in double
free block error and file system corruption. This is simply because we
now use different code path, where this problem does not exist.
This has been tested with fsx running for several days and xfstests,
plus xfstest #251 with '-o discard' run on the loop image (which
converts discard requestes into punch hole to the backing file). All of
it on 1K and 4K file system block size.
Signed-off-by: Lukas Czerner <lczerner@redhat.com>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
2012-03-20 07:03:19 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* See if the last block is inside the extent, if so split
|
|
|
|
* the extent at 'end' block so we can easily remove the
|
|
|
|
* tail of the first part of the split extent in
|
|
|
|
* ext4_ext_rm_leaf().
|
|
|
|
*/
|
2014-11-23 08:55:42 +03:00
|
|
|
if (end >= ee_block && end < ex_end) {
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If we're going to split the extent, note that
|
|
|
|
* the cluster containing the block after 'end' is
|
|
|
|
* in use to avoid freeing it when removing blocks.
|
|
|
|
*/
|
|
|
|
if (sbi->s_cluster_ratio > 1) {
|
|
|
|
pblk = ext4_ext_pblock(ex) + end - ee_block + 2;
|
|
|
|
partial_cluster =
|
|
|
|
-(long long) EXT4_B2C(sbi, pblk);
|
|
|
|
}
|
|
|
|
|
ext4: rewrite punch hole to use ext4_ext_remove_space()
This commit rewrites ext4 punch hole implementation to use
ext4_ext_remove_space() instead of its home gown way of doing this via
ext4_ext_map_blocks(). There are several reasons for changing this.
Firstly it is quite non obvious that punching hole needs to
ext4_ext_map_blocks() to punch a hole, especially given that this
function should map blocks, not unmap it. It also required a lot of new
code in ext4_ext_map_blocks().
Secondly the design of it is not very effective. The reason is that we
are trying to punch out blocks in ext4_ext_punch_hole() in opposite
direction than in ext4_ext_rm_leaf() which causes the ext4_ext_rm_leaf()
to iterate through the whole tree from the end to the start to find the
requested extent for every extent we are going to punch out.
And finally the current implementation does not use the existing code,
but bring a lot of new code, which is IMO unnecessary since there
already is some infrastructure we can use. Specifically
ext4_ext_remove_space().
This commit changes ext4_ext_remove_space() to accept 'end' parameter so
we can not only truncate to the end of file, but also remove the space
in the middle of the file (punch a hole). Moreover, because the last
block to punch out, might be in the middle of the extent, we have to
split the extent at 'end + 1' so ext4_ext_rm_leaf() can easily either
remove the whole fist part of split extent, or change its size.
ext4_ext_remove_space() is then used to actually remove the space
(extents) from within the hole, instead of ext4_ext_map_blocks().
Note that this also fix the issue with punch hole, where we would forget
to remove empty index blocks from the extent tree, resulting in double
free block error and file system corruption. This is simply because we
now use different code path, where this problem does not exist.
This has been tested with fsx running for several days and xfstests,
plus xfstest #251 with '-o discard' run on the loop image (which
converts discard requestes into punch hole to the backing file). All of
it on 1K and 4K file system block size.
Signed-off-by: Lukas Czerner <lczerner@redhat.com>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
2012-03-20 07:03:19 +04:00
|
|
|
/*
|
|
|
|
* Split the extent in two so that 'end' is the last
|
2013-04-10 06:11:22 +04:00
|
|
|
* block in the first new extent. Also we should not
|
|
|
|
* fail removing space due to ENOSPC so try to use
|
|
|
|
* reserved block if that happens.
|
ext4: rewrite punch hole to use ext4_ext_remove_space()
This commit rewrites ext4 punch hole implementation to use
ext4_ext_remove_space() instead of its home gown way of doing this via
ext4_ext_map_blocks(). There are several reasons for changing this.
Firstly it is quite non obvious that punching hole needs to
ext4_ext_map_blocks() to punch a hole, especially given that this
function should map blocks, not unmap it. It also required a lot of new
code in ext4_ext_map_blocks().
Secondly the design of it is not very effective. The reason is that we
are trying to punch out blocks in ext4_ext_punch_hole() in opposite
direction than in ext4_ext_rm_leaf() which causes the ext4_ext_rm_leaf()
to iterate through the whole tree from the end to the start to find the
requested extent for every extent we are going to punch out.
And finally the current implementation does not use the existing code,
but bring a lot of new code, which is IMO unnecessary since there
already is some infrastructure we can use. Specifically
ext4_ext_remove_space().
This commit changes ext4_ext_remove_space() to accept 'end' parameter so
we can not only truncate to the end of file, but also remove the space
in the middle of the file (punch a hole). Moreover, because the last
block to punch out, might be in the middle of the extent, we have to
split the extent at 'end + 1' so ext4_ext_rm_leaf() can easily either
remove the whole fist part of split extent, or change its size.
ext4_ext_remove_space() is then used to actually remove the space
(extents) from within the hole, instead of ext4_ext_map_blocks().
Note that this also fix the issue with punch hole, where we would forget
to remove empty index blocks from the extent tree, resulting in double
free block error and file system corruption. This is simply because we
now use different code path, where this problem does not exist.
This has been tested with fsx running for several days and xfstests,
plus xfstest #251 with '-o discard' run on the loop image (which
converts discard requestes into punch hole to the backing file). All of
it on 1K and 4K file system block size.
Signed-off-by: Lukas Czerner <lczerner@redhat.com>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
2012-03-20 07:03:19 +04:00
|
|
|
*/
|
2014-09-01 22:37:09 +04:00
|
|
|
err = ext4_force_split_extent_at(handle, inode, &path,
|
2014-08-31 07:52:19 +04:00
|
|
|
end + 1, 1);
|
ext4: rewrite punch hole to use ext4_ext_remove_space()
This commit rewrites ext4 punch hole implementation to use
ext4_ext_remove_space() instead of its home gown way of doing this via
ext4_ext_map_blocks(). There are several reasons for changing this.
Firstly it is quite non obvious that punching hole needs to
ext4_ext_map_blocks() to punch a hole, especially given that this
function should map blocks, not unmap it. It also required a lot of new
code in ext4_ext_map_blocks().
Secondly the design of it is not very effective. The reason is that we
are trying to punch out blocks in ext4_ext_punch_hole() in opposite
direction than in ext4_ext_rm_leaf() which causes the ext4_ext_rm_leaf()
to iterate through the whole tree from the end to the start to find the
requested extent for every extent we are going to punch out.
And finally the current implementation does not use the existing code,
but bring a lot of new code, which is IMO unnecessary since there
already is some infrastructure we can use. Specifically
ext4_ext_remove_space().
This commit changes ext4_ext_remove_space() to accept 'end' parameter so
we can not only truncate to the end of file, but also remove the space
in the middle of the file (punch a hole). Moreover, because the last
block to punch out, might be in the middle of the extent, we have to
split the extent at 'end + 1' so ext4_ext_rm_leaf() can easily either
remove the whole fist part of split extent, or change its size.
ext4_ext_remove_space() is then used to actually remove the space
(extents) from within the hole, instead of ext4_ext_map_blocks().
Note that this also fix the issue with punch hole, where we would forget
to remove empty index blocks from the extent tree, resulting in double
free block error and file system corruption. This is simply because we
now use different code path, where this problem does not exist.
This has been tested with fsx running for several days and xfstests,
plus xfstest #251 with '-o discard' run on the loop image (which
converts discard requestes into punch hole to the backing file). All of
it on 1K and 4K file system block size.
Signed-off-by: Lukas Czerner <lczerner@redhat.com>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
2012-03-20 07:03:19 +04:00
|
|
|
if (err < 0)
|
|
|
|
goto out;
|
2014-11-23 08:55:42 +03:00
|
|
|
|
|
|
|
} else if (sbi->s_cluster_ratio > 1 && end >= ex_end) {
|
|
|
|
/*
|
|
|
|
* If there's an extent to the right its first cluster
|
|
|
|
* contains the immediate right boundary of the
|
|
|
|
* truncated/punched region. Set partial_cluster to
|
|
|
|
* its negative value so it won't be freed if shared
|
|
|
|
* with the current extent. The end < ee_block case
|
|
|
|
* is handled in ext4_ext_rm_leaf().
|
|
|
|
*/
|
|
|
|
lblk = ex_end + 1;
|
|
|
|
err = ext4_ext_search_right(inode, path, &lblk, &pblk,
|
|
|
|
&ex);
|
|
|
|
if (err)
|
|
|
|
goto out;
|
|
|
|
if (pblk)
|
|
|
|
partial_cluster =
|
|
|
|
-(long long) EXT4_B2C(sbi, pblk);
|
ext4: rewrite punch hole to use ext4_ext_remove_space()
This commit rewrites ext4 punch hole implementation to use
ext4_ext_remove_space() instead of its home gown way of doing this via
ext4_ext_map_blocks(). There are several reasons for changing this.
Firstly it is quite non obvious that punching hole needs to
ext4_ext_map_blocks() to punch a hole, especially given that this
function should map blocks, not unmap it. It also required a lot of new
code in ext4_ext_map_blocks().
Secondly the design of it is not very effective. The reason is that we
are trying to punch out blocks in ext4_ext_punch_hole() in opposite
direction than in ext4_ext_rm_leaf() which causes the ext4_ext_rm_leaf()
to iterate through the whole tree from the end to the start to find the
requested extent for every extent we are going to punch out.
And finally the current implementation does not use the existing code,
but bring a lot of new code, which is IMO unnecessary since there
already is some infrastructure we can use. Specifically
ext4_ext_remove_space().
This commit changes ext4_ext_remove_space() to accept 'end' parameter so
we can not only truncate to the end of file, but also remove the space
in the middle of the file (punch a hole). Moreover, because the last
block to punch out, might be in the middle of the extent, we have to
split the extent at 'end + 1' so ext4_ext_rm_leaf() can easily either
remove the whole fist part of split extent, or change its size.
ext4_ext_remove_space() is then used to actually remove the space
(extents) from within the hole, instead of ext4_ext_map_blocks().
Note that this also fix the issue with punch hole, where we would forget
to remove empty index blocks from the extent tree, resulting in double
free block error and file system corruption. This is simply because we
now use different code path, where this problem does not exist.
This has been tested with fsx running for several days and xfstests,
plus xfstest #251 with '-o discard' run on the loop image (which
converts discard requestes into punch hole to the backing file). All of
it on 1K and 4K file system block size.
Signed-off-by: Lukas Czerner <lczerner@redhat.com>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
2012-03-20 07:03:19 +04:00
|
|
|
}
|
|
|
|
}
|
2006-10-11 12:21:03 +04:00
|
|
|
/*
|
2006-10-11 12:21:07 +04:00
|
|
|
* We start scanning from right side, freeing all the blocks
|
|
|
|
* after i_size and walking into the tree depth-wise.
|
2006-10-11 12:21:03 +04:00
|
|
|
*/
|
2010-05-17 09:00:00 +04:00
|
|
|
depth = ext_depth(inode);
|
2012-07-23 06:49:08 +04:00
|
|
|
if (path) {
|
|
|
|
int k = i = depth;
|
|
|
|
while (--k > 0)
|
|
|
|
path[k].p_block =
|
|
|
|
le16_to_cpu(path[k].p_hdr->eh_entries)+1;
|
|
|
|
} else {
|
|
|
|
path = kzalloc(sizeof(struct ext4_ext_path) * (depth + 1),
|
|
|
|
GFP_NOFS);
|
|
|
|
if (path == NULL) {
|
|
|
|
ext4_journal_stop(handle);
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
2014-09-01 22:40:09 +04:00
|
|
|
path[0].p_maxdepth = path[0].p_depth = depth;
|
2012-07-23 06:49:08 +04:00
|
|
|
path[0].p_hdr = ext_inode_hdr(inode);
|
2012-08-17 16:54:52 +04:00
|
|
|
i = 0;
|
ext4: rewrite punch hole to use ext4_ext_remove_space()
This commit rewrites ext4 punch hole implementation to use
ext4_ext_remove_space() instead of its home gown way of doing this via
ext4_ext_map_blocks(). There are several reasons for changing this.
Firstly it is quite non obvious that punching hole needs to
ext4_ext_map_blocks() to punch a hole, especially given that this
function should map blocks, not unmap it. It also required a lot of new
code in ext4_ext_map_blocks().
Secondly the design of it is not very effective. The reason is that we
are trying to punch out blocks in ext4_ext_punch_hole() in opposite
direction than in ext4_ext_rm_leaf() which causes the ext4_ext_rm_leaf()
to iterate through the whole tree from the end to the start to find the
requested extent for every extent we are going to punch out.
And finally the current implementation does not use the existing code,
but bring a lot of new code, which is IMO unnecessary since there
already is some infrastructure we can use. Specifically
ext4_ext_remove_space().
This commit changes ext4_ext_remove_space() to accept 'end' parameter so
we can not only truncate to the end of file, but also remove the space
in the middle of the file (punch a hole). Moreover, because the last
block to punch out, might be in the middle of the extent, we have to
split the extent at 'end + 1' so ext4_ext_rm_leaf() can easily either
remove the whole fist part of split extent, or change its size.
ext4_ext_remove_space() is then used to actually remove the space
(extents) from within the hole, instead of ext4_ext_map_blocks().
Note that this also fix the issue with punch hole, where we would forget
to remove empty index blocks from the extent tree, resulting in double
free block error and file system corruption. This is simply because we
now use different code path, where this problem does not exist.
This has been tested with fsx running for several days and xfstests,
plus xfstest #251 with '-o discard' run on the loop image (which
converts discard requestes into punch hole to the backing file). All of
it on 1K and 4K file system block size.
Signed-off-by: Lukas Czerner <lczerner@redhat.com>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
2012-03-20 07:03:19 +04:00
|
|
|
|
2013-08-17 05:21:41 +04:00
|
|
|
if (ext4_ext_check(inode, path[0].p_hdr, depth, 0)) {
|
2015-10-17 23:16:04 +03:00
|
|
|
err = -EFSCORRUPTED;
|
2012-07-23 06:49:08 +04:00
|
|
|
goto out;
|
|
|
|
}
|
2006-10-11 12:21:03 +04:00
|
|
|
}
|
2012-07-23 06:49:08 +04:00
|
|
|
err = 0;
|
2006-10-11 12:21:03 +04:00
|
|
|
|
|
|
|
while (i >= 0 && err == 0) {
|
|
|
|
if (i == depth) {
|
|
|
|
/* this is leaf block */
|
2011-05-25 15:41:43 +04:00
|
|
|
err = ext4_ext_rm_leaf(handle, inode, path,
|
2011-09-10 02:54:51 +04:00
|
|
|
&partial_cluster, start,
|
ext4: rewrite punch hole to use ext4_ext_remove_space()
This commit rewrites ext4 punch hole implementation to use
ext4_ext_remove_space() instead of its home gown way of doing this via
ext4_ext_map_blocks(). There are several reasons for changing this.
Firstly it is quite non obvious that punching hole needs to
ext4_ext_map_blocks() to punch a hole, especially given that this
function should map blocks, not unmap it. It also required a lot of new
code in ext4_ext_map_blocks().
Secondly the design of it is not very effective. The reason is that we
are trying to punch out blocks in ext4_ext_punch_hole() in opposite
direction than in ext4_ext_rm_leaf() which causes the ext4_ext_rm_leaf()
to iterate through the whole tree from the end to the start to find the
requested extent for every extent we are going to punch out.
And finally the current implementation does not use the existing code,
but bring a lot of new code, which is IMO unnecessary since there
already is some infrastructure we can use. Specifically
ext4_ext_remove_space().
This commit changes ext4_ext_remove_space() to accept 'end' parameter so
we can not only truncate to the end of file, but also remove the space
in the middle of the file (punch a hole). Moreover, because the last
block to punch out, might be in the middle of the extent, we have to
split the extent at 'end + 1' so ext4_ext_rm_leaf() can easily either
remove the whole fist part of split extent, or change its size.
ext4_ext_remove_space() is then used to actually remove the space
(extents) from within the hole, instead of ext4_ext_map_blocks().
Note that this also fix the issue with punch hole, where we would forget
to remove empty index blocks from the extent tree, resulting in double
free block error and file system corruption. This is simply because we
now use different code path, where this problem does not exist.
This has been tested with fsx running for several days and xfstests,
plus xfstest #251 with '-o discard' run on the loop image (which
converts discard requestes into punch hole to the backing file). All of
it on 1K and 4K file system block size.
Signed-off-by: Lukas Czerner <lczerner@redhat.com>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
2012-03-20 07:03:19 +04:00
|
|
|
end);
|
2006-10-11 12:21:07 +04:00
|
|
|
/* root level has p_bh == NULL, brelse() eats this */
|
2006-10-11 12:21:03 +04:00
|
|
|
brelse(path[i].p_bh);
|
|
|
|
path[i].p_bh = NULL;
|
|
|
|
i--;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* this is index block */
|
|
|
|
if (!path[i].p_hdr) {
|
|
|
|
ext_debug("initialize header\n");
|
|
|
|
path[i].p_hdr = ext_block_hdr(path[i].p_bh);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!path[i].p_idx) {
|
2006-10-11 12:21:07 +04:00
|
|
|
/* this level hasn't been touched yet */
|
2006-10-11 12:21:03 +04:00
|
|
|
path[i].p_idx = EXT_LAST_INDEX(path[i].p_hdr);
|
|
|
|
path[i].p_block = le16_to_cpu(path[i].p_hdr->eh_entries)+1;
|
|
|
|
ext_debug("init index ptr: hdr 0x%p, num %d\n",
|
|
|
|
path[i].p_hdr,
|
|
|
|
le16_to_cpu(path[i].p_hdr->eh_entries));
|
|
|
|
} else {
|
2006-10-11 12:21:07 +04:00
|
|
|
/* we were already here, see at next index */
|
2006-10-11 12:21:03 +04:00
|
|
|
path[i].p_idx--;
|
|
|
|
}
|
|
|
|
|
|
|
|
ext_debug("level %d - index, first 0x%p, cur 0x%p\n",
|
|
|
|
i, EXT_FIRST_INDEX(path[i].p_hdr),
|
|
|
|
path[i].p_idx);
|
|
|
|
if (ext4_ext_more_to_rm(path + i)) {
|
2007-07-18 17:19:09 +04:00
|
|
|
struct buffer_head *bh;
|
2006-10-11 12:21:03 +04:00
|
|
|
/* go to the next level */
|
2006-10-11 12:21:11 +04:00
|
|
|
ext_debug("move to level %d (block %llu)\n",
|
2010-10-28 05:30:14 +04:00
|
|
|
i + 1, ext4_idx_pblock(path[i].p_idx));
|
2006-10-11 12:21:03 +04:00
|
|
|
memset(path + i + 1, 0, sizeof(*path));
|
2013-08-17 05:20:41 +04:00
|
|
|
bh = read_extent_tree_block(inode,
|
2013-08-17 05:23:41 +04:00
|
|
|
ext4_idx_pblock(path[i].p_idx), depth - i - 1,
|
|
|
|
EXT4_EX_NOCACHE);
|
2013-08-17 05:20:41 +04:00
|
|
|
if (IS_ERR(bh)) {
|
2006-10-11 12:21:03 +04:00
|
|
|
/* should we reset i_size? */
|
2013-08-17 05:20:41 +04:00
|
|
|
err = PTR_ERR(bh);
|
2006-10-11 12:21:03 +04:00
|
|
|
break;
|
|
|
|
}
|
2013-07-15 20:27:47 +04:00
|
|
|
/* Yield here to deal with large extent trees.
|
|
|
|
* Should be a no-op if we did IO above. */
|
|
|
|
cond_resched();
|
2007-07-18 17:19:09 +04:00
|
|
|
if (WARN_ON(i + 1 > depth)) {
|
2015-10-17 23:16:04 +03:00
|
|
|
err = -EFSCORRUPTED;
|
2007-07-18 17:19:09 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
path[i + 1].p_bh = bh;
|
2006-10-11 12:21:03 +04:00
|
|
|
|
2006-10-11 12:21:07 +04:00
|
|
|
/* save actual number of indexes since this
|
|
|
|
* number is changed at the next iteration */
|
2006-10-11 12:21:03 +04:00
|
|
|
path[i].p_block = le16_to_cpu(path[i].p_hdr->eh_entries);
|
|
|
|
i++;
|
|
|
|
} else {
|
2006-10-11 12:21:07 +04:00
|
|
|
/* we finished processing this index, go up */
|
2006-10-11 12:21:03 +04:00
|
|
|
if (path[i].p_hdr->eh_entries == 0 && i > 0) {
|
2006-10-11 12:21:07 +04:00
|
|
|
/* index is empty, remove it;
|
2006-10-11 12:21:03 +04:00
|
|
|
* handle must be already prepared by the
|
|
|
|
* truncatei_leaf() */
|
2012-12-17 18:55:39 +04:00
|
|
|
err = ext4_ext_rm_idx(handle, inode, path, i);
|
2006-10-11 12:21:03 +04:00
|
|
|
}
|
2006-10-11 12:21:07 +04:00
|
|
|
/* root level has p_bh == NULL, brelse() eats this */
|
2006-10-11 12:21:03 +04:00
|
|
|
brelse(path[i].p_bh);
|
|
|
|
path[i].p_bh = NULL;
|
|
|
|
i--;
|
|
|
|
ext_debug("return to level %d\n", i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-28 07:32:35 +04:00
|
|
|
trace_ext4_ext_remove_space_done(inode, start, end, depth,
|
|
|
|
partial_cluster, path->p_hdr->eh_entries);
|
2011-09-10 03:18:51 +04:00
|
|
|
|
2014-11-23 08:59:39 +03:00
|
|
|
/*
|
|
|
|
* If we still have something in the partial cluster and we have removed
|
2011-09-10 03:04:51 +04:00
|
|
|
* even the first extent, then we should free the blocks in the partial
|
2014-11-23 08:59:39 +03:00
|
|
|
* cluster as well. (This code will only run when there are no leaves
|
|
|
|
* to the immediate left of the truncated/punched region.)
|
|
|
|
*/
|
|
|
|
if (partial_cluster > 0 && err == 0) {
|
|
|
|
/* don't zero partial_cluster since it's not used afterwards */
|
2011-09-10 03:04:51 +04:00
|
|
|
ext4_free_blocks(handle, inode, NULL,
|
2014-11-23 08:55:42 +03:00
|
|
|
EXT4_C2B(sbi, partial_cluster),
|
2014-11-23 08:59:39 +03:00
|
|
|
sbi->s_cluster_ratio,
|
|
|
|
get_default_free_blocks_flags(inode));
|
2011-09-10 03:04:51 +04:00
|
|
|
}
|
|
|
|
|
2006-10-11 12:21:03 +04:00
|
|
|
/* TODO: flexible tree reduction should be here */
|
|
|
|
if (path->p_hdr->eh_entries == 0) {
|
|
|
|
/*
|
2006-10-11 12:21:07 +04:00
|
|
|
* truncate to zero freed all the tree,
|
|
|
|
* so we need to correct eh_depth
|
2006-10-11 12:21:03 +04:00
|
|
|
*/
|
|
|
|
err = ext4_ext_get_access(handle, inode, path);
|
|
|
|
if (err == 0) {
|
|
|
|
ext_inode_hdr(inode)->eh_depth = 0;
|
|
|
|
ext_inode_hdr(inode)->eh_max =
|
2009-08-28 18:40:33 +04:00
|
|
|
cpu_to_le16(ext4_ext_space_root(inode, 0));
|
2006-10-11 12:21:03 +04:00
|
|
|
err = ext4_ext_dirty(handle, inode, path);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
out:
|
2014-09-01 22:39:09 +04:00
|
|
|
ext4_ext_drop_refs(path);
|
|
|
|
kfree(path);
|
|
|
|
path = NULL;
|
2014-09-01 22:37:09 +04:00
|
|
|
if (err == -EAGAIN)
|
|
|
|
goto again;
|
2006-10-11 12:21:03 +04:00
|
|
|
ext4_journal_stop(handle);
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* called at mount time
|
|
|
|
*/
|
|
|
|
void ext4_ext_init(struct super_block *sb)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* possible initialization would be here
|
|
|
|
*/
|
|
|
|
|
2015-10-17 23:18:43 +03:00
|
|
|
if (ext4_has_feature_extents(sb)) {
|
2009-09-29 23:51:30 +04:00
|
|
|
#if defined(AGGRESSIVE_TEST) || defined(CHECK_BINSEARCH) || defined(EXTENTS_STATS)
|
2012-03-20 07:41:49 +04:00
|
|
|
printk(KERN_INFO "EXT4-fs: file extents enabled"
|
2007-02-17 21:20:16 +03:00
|
|
|
#ifdef AGGRESSIVE_TEST
|
2012-03-20 07:41:49 +04:00
|
|
|
", aggressive tests"
|
2006-10-11 12:21:03 +04:00
|
|
|
#endif
|
|
|
|
#ifdef CHECK_BINSEARCH
|
2012-03-20 07:41:49 +04:00
|
|
|
", check binsearch"
|
2006-10-11 12:21:03 +04:00
|
|
|
#endif
|
|
|
|
#ifdef EXTENTS_STATS
|
2012-03-20 07:41:49 +04:00
|
|
|
", stats"
|
2006-10-11 12:21:03 +04:00
|
|
|
#endif
|
2012-03-20 07:41:49 +04:00
|
|
|
"\n");
|
2009-09-29 23:51:30 +04:00
|
|
|
#endif
|
2006-10-11 12:21:03 +04:00
|
|
|
#ifdef EXTENTS_STATS
|
|
|
|
spin_lock_init(&EXT4_SB(sb)->s_ext_stats_lock);
|
|
|
|
EXT4_SB(sb)->s_ext_min = 1 << 30;
|
|
|
|
EXT4_SB(sb)->s_ext_max = 0;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* called at umount time
|
|
|
|
*/
|
|
|
|
void ext4_ext_release(struct super_block *sb)
|
|
|
|
{
|
2015-10-17 23:18:43 +03:00
|
|
|
if (!ext4_has_feature_extents(sb))
|
2006-10-11 12:21:03 +04:00
|
|
|
return;
|
|
|
|
|
|
|
|
#ifdef EXTENTS_STATS
|
|
|
|
if (EXT4_SB(sb)->s_ext_blocks && EXT4_SB(sb)->s_ext_extents) {
|
|
|
|
struct ext4_sb_info *sbi = EXT4_SB(sb);
|
|
|
|
printk(KERN_ERR "EXT4-fs: %lu blocks in %lu extents (%lu ave)\n",
|
|
|
|
sbi->s_ext_blocks, sbi->s_ext_extents,
|
|
|
|
sbi->s_ext_blocks / sbi->s_ext_extents);
|
|
|
|
printk(KERN_ERR "EXT4-fs: extents: %lu min, %lu max, max depth %lu\n",
|
|
|
|
sbi->s_ext_min, sbi->s_ext_max, sbi->s_depth_max);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2013-08-28 22:47:06 +04:00
|
|
|
static int ext4_zeroout_es(struct inode *inode, struct ext4_extent *ex)
|
|
|
|
{
|
|
|
|
ext4_lblk_t ee_block;
|
|
|
|
ext4_fsblk_t ee_pblock;
|
|
|
|
unsigned int ee_len;
|
|
|
|
|
|
|
|
ee_block = le32_to_cpu(ex->ee_block);
|
|
|
|
ee_len = ext4_ext_get_actual_len(ex);
|
|
|
|
ee_pblock = ext4_ext_pblock(ex);
|
|
|
|
|
|
|
|
if (ee_len == 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return ext4_es_insert_extent(inode, ee_block, ee_len, ee_pblock,
|
|
|
|
EXTENT_STATUS_WRITTEN);
|
|
|
|
}
|
|
|
|
|
2008-04-29 16:11:12 +04:00
|
|
|
/* FIXME!! we need to try to merge to left or right after zero-out */
|
|
|
|
static int ext4_ext_zeroout(struct inode *inode, struct ext4_extent *ex)
|
|
|
|
{
|
2010-10-28 05:30:06 +04:00
|
|
|
ext4_fsblk_t ee_pblock;
|
|
|
|
unsigned int ee_len;
|
2008-04-29 16:11:12 +04:00
|
|
|
|
|
|
|
ee_len = ext4_ext_get_actual_len(ex);
|
2010-10-28 05:30:14 +04:00
|
|
|
ee_pblock = ext4_ext_pblock(ex);
|
2015-12-07 23:09:35 +03:00
|
|
|
return ext4_issue_zeroout(inode, le32_to_cpu(ex->ee_block), ee_pblock,
|
|
|
|
ee_len);
|
2008-04-29 16:11:12 +04:00
|
|
|
}
|
|
|
|
|
2011-05-03 20:23:07 +04:00
|
|
|
/*
|
|
|
|
* ext4_split_extent_at() splits an extent at given block.
|
|
|
|
*
|
|
|
|
* @handle: the journal handle
|
|
|
|
* @inode: the file inode
|
|
|
|
* @path: the path to the extent
|
|
|
|
* @split: the logical block where the extent is splitted.
|
|
|
|
* @split_flags: indicates if the extent could be zeroout if split fails, and
|
2014-04-21 07:45:47 +04:00
|
|
|
* the states(init or unwritten) of new extents.
|
2011-05-03 20:23:07 +04:00
|
|
|
* @flags: flags used to insert new extent to extent tree.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* Splits extent [a, b] into two extents [a, @split) and [@split, b], states
|
|
|
|
* of which are deterimined by split_flag.
|
|
|
|
*
|
|
|
|
* There are two cases:
|
|
|
|
* a> the extent are splitted into two extent.
|
|
|
|
* b> split is not needed, and just mark the extent.
|
|
|
|
*
|
|
|
|
* return 0 on success.
|
|
|
|
*/
|
|
|
|
static int ext4_split_extent_at(handle_t *handle,
|
|
|
|
struct inode *inode,
|
2014-09-01 22:37:09 +04:00
|
|
|
struct ext4_ext_path **ppath,
|
2011-05-03 20:23:07 +04:00
|
|
|
ext4_lblk_t split,
|
|
|
|
int split_flag,
|
|
|
|
int flags)
|
|
|
|
{
|
2014-09-01 22:37:09 +04:00
|
|
|
struct ext4_ext_path *path = *ppath;
|
2011-05-03 20:23:07 +04:00
|
|
|
ext4_fsblk_t newblock;
|
|
|
|
ext4_lblk_t ee_block;
|
2013-03-11 05:13:05 +04:00
|
|
|
struct ext4_extent *ex, newex, orig_ex, zero_ex;
|
2011-05-03 20:23:07 +04:00
|
|
|
struct ext4_extent *ex2 = NULL;
|
|
|
|
unsigned int ee_len, depth;
|
|
|
|
int err = 0;
|
|
|
|
|
2012-10-10 09:04:58 +04:00
|
|
|
BUG_ON((split_flag & (EXT4_EXT_DATA_VALID1 | EXT4_EXT_DATA_VALID2)) ==
|
|
|
|
(EXT4_EXT_DATA_VALID1 | EXT4_EXT_DATA_VALID2));
|
|
|
|
|
2011-05-03 20:23:07 +04:00
|
|
|
ext_debug("ext4_split_extents_at: inode %lu, logical"
|
|
|
|
"block %llu\n", inode->i_ino, (unsigned long long)split);
|
|
|
|
|
|
|
|
ext4_ext_show_leaf(inode, path);
|
|
|
|
|
|
|
|
depth = ext_depth(inode);
|
|
|
|
ex = path[depth].p_ext;
|
|
|
|
ee_block = le32_to_cpu(ex->ee_block);
|
|
|
|
ee_len = ext4_ext_get_actual_len(ex);
|
|
|
|
newblock = split - ee_block + ext4_ext_pblock(ex);
|
|
|
|
|
|
|
|
BUG_ON(split < ee_block || split >= (ee_block + ee_len));
|
2014-04-21 07:45:47 +04:00
|
|
|
BUG_ON(!ext4_ext_is_unwritten(ex) &&
|
ext4: ext4_split_extent should take care of extent zeroout
When ext4_split_extent_at() ends up doing zeroout & conversion to
initialized instead of split & conversion, ext4_split_extent() gets
confused and can wrongly mark the extent back as uninitialized
resulting in end IO code getting confused from large unwritten extents
and may result in data loss.
The example of problematic behavior is:
lblk len lblk len
ext4_split_extent() (ex=[1000,30,uninit], map=[1010,10])
ext4_split_extent_at() (split [1000,30,uninit] at 1020)
ext4_ext_insert_extent() -> ENOSPC
ext4_ext_zeroout()
-> extent [1000,30] is now initialized
ext4_split_extent_at() (split [1000,30,init] at 1010,
MARK_UNINIT1 | MARK_UNINIT2)
-> extent is split and parts marked as uninitialized
Fix the problem by rechecking extent type after the first
ext4_split_extent_at() returns. None of split_flags can not be applied
to initialized extent so this patch also add BUG_ON to prevent similar
issues in future.
TESTCASE: https://github.com/dmonakhov/xfstests/commit/b8a55eb5ce28c6ff29e620ab090902fcd5833597
Signed-off-by: Dmitry Monakhov <dmonakhov@openvz.org>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Reviewed-by: Jan Kara <jack@suse.cz>
2013-03-04 09:34:34 +04:00
|
|
|
split_flag & (EXT4_EXT_MAY_ZEROOUT |
|
2014-04-21 07:45:47 +04:00
|
|
|
EXT4_EXT_MARK_UNWRIT1 |
|
|
|
|
EXT4_EXT_MARK_UNWRIT2));
|
2011-05-03 20:23:07 +04:00
|
|
|
|
|
|
|
err = ext4_ext_get_access(handle, inode, path + depth);
|
|
|
|
if (err)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
if (split == ee_block) {
|
|
|
|
/*
|
|
|
|
* case b: block @split is the block that the extent begins with
|
|
|
|
* then we just change the state of the extent, and splitting
|
|
|
|
* is not needed.
|
|
|
|
*/
|
2014-04-21 07:45:47 +04:00
|
|
|
if (split_flag & EXT4_EXT_MARK_UNWRIT2)
|
|
|
|
ext4_ext_mark_unwritten(ex);
|
2011-05-03 20:23:07 +04:00
|
|
|
else
|
|
|
|
ext4_ext_mark_initialized(ex);
|
|
|
|
|
|
|
|
if (!(flags & EXT4_GET_BLOCKS_PRE_IO))
|
2012-08-17 17:44:17 +04:00
|
|
|
ext4_ext_try_to_merge(handle, inode, path, ex);
|
2011-05-03 20:23:07 +04:00
|
|
|
|
2012-08-17 17:44:17 +04:00
|
|
|
err = ext4_ext_dirty(handle, inode, path + path->p_depth);
|
2011-05-03 20:23:07 +04:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* case a */
|
|
|
|
memcpy(&orig_ex, ex, sizeof(orig_ex));
|
|
|
|
ex->ee_len = cpu_to_le16(split - ee_block);
|
2014-04-21 07:45:47 +04:00
|
|
|
if (split_flag & EXT4_EXT_MARK_UNWRIT1)
|
|
|
|
ext4_ext_mark_unwritten(ex);
|
2011-05-03 20:23:07 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* path may lead to new leaf, not to original leaf any more
|
|
|
|
* after ext4_ext_insert_extent() returns,
|
|
|
|
*/
|
|
|
|
err = ext4_ext_dirty(handle, inode, path + depth);
|
|
|
|
if (err)
|
|
|
|
goto fix_extent_len;
|
|
|
|
|
|
|
|
ex2 = &newex;
|
|
|
|
ex2->ee_block = cpu_to_le32(split);
|
|
|
|
ex2->ee_len = cpu_to_le16(ee_len - (split - ee_block));
|
|
|
|
ext4_ext_store_pblock(ex2, newblock);
|
2014-04-21 07:45:47 +04:00
|
|
|
if (split_flag & EXT4_EXT_MARK_UNWRIT2)
|
|
|
|
ext4_ext_mark_unwritten(ex2);
|
2011-05-03 20:23:07 +04:00
|
|
|
|
2014-09-01 22:37:09 +04:00
|
|
|
err = ext4_ext_insert_extent(handle, inode, ppath, &newex, flags);
|
2011-05-03 20:23:07 +04:00
|
|
|
if (err == -ENOSPC && (EXT4_EXT_MAY_ZEROOUT & split_flag)) {
|
2012-10-10 09:04:58 +04:00
|
|
|
if (split_flag & (EXT4_EXT_DATA_VALID1|EXT4_EXT_DATA_VALID2)) {
|
2013-03-11 05:13:05 +04:00
|
|
|
if (split_flag & EXT4_EXT_DATA_VALID1) {
|
2012-10-10 09:04:58 +04:00
|
|
|
err = ext4_ext_zeroout(inode, ex2);
|
2013-03-11 05:13:05 +04:00
|
|
|
zero_ex.ee_block = ex2->ee_block;
|
2013-04-03 20:27:18 +04:00
|
|
|
zero_ex.ee_len = cpu_to_le16(
|
|
|
|
ext4_ext_get_actual_len(ex2));
|
2013-03-11 05:13:05 +04:00
|
|
|
ext4_ext_store_pblock(&zero_ex,
|
|
|
|
ext4_ext_pblock(ex2));
|
|
|
|
} else {
|
2012-10-10 09:04:58 +04:00
|
|
|
err = ext4_ext_zeroout(inode, ex);
|
2013-03-11 05:13:05 +04:00
|
|
|
zero_ex.ee_block = ex->ee_block;
|
2013-04-03 20:27:18 +04:00
|
|
|
zero_ex.ee_len = cpu_to_le16(
|
|
|
|
ext4_ext_get_actual_len(ex));
|
2013-03-11 05:13:05 +04:00
|
|
|
ext4_ext_store_pblock(&zero_ex,
|
|
|
|
ext4_ext_pblock(ex));
|
|
|
|
}
|
|
|
|
} else {
|
2012-10-10 09:04:58 +04:00
|
|
|
err = ext4_ext_zeroout(inode, &orig_ex);
|
2013-03-11 05:13:05 +04:00
|
|
|
zero_ex.ee_block = orig_ex.ee_block;
|
2013-04-03 20:27:18 +04:00
|
|
|
zero_ex.ee_len = cpu_to_le16(
|
|
|
|
ext4_ext_get_actual_len(&orig_ex));
|
2013-03-11 05:13:05 +04:00
|
|
|
ext4_ext_store_pblock(&zero_ex,
|
|
|
|
ext4_ext_pblock(&orig_ex));
|
|
|
|
}
|
2012-10-10 09:04:58 +04:00
|
|
|
|
2011-05-03 20:23:07 +04:00
|
|
|
if (err)
|
|
|
|
goto fix_extent_len;
|
|
|
|
/* update the extent length and mark as initialized */
|
2012-04-13 04:32:25 +04:00
|
|
|
ex->ee_len = cpu_to_le16(ee_len);
|
2012-08-17 17:44:17 +04:00
|
|
|
ext4_ext_try_to_merge(handle, inode, path, ex);
|
|
|
|
err = ext4_ext_dirty(handle, inode, path + path->p_depth);
|
2013-03-11 05:13:05 +04:00
|
|
|
if (err)
|
|
|
|
goto fix_extent_len;
|
|
|
|
|
|
|
|
/* update extent status tree */
|
2013-08-28 22:47:06 +04:00
|
|
|
err = ext4_zeroout_es(inode, &zero_ex);
|
2013-03-11 05:13:05 +04:00
|
|
|
|
2011-05-03 20:23:07 +04:00
|
|
|
goto out;
|
|
|
|
} else if (err)
|
|
|
|
goto fix_extent_len;
|
|
|
|
|
|
|
|
out:
|
|
|
|
ext4_ext_show_leaf(inode, path);
|
|
|
|
return err;
|
|
|
|
|
|
|
|
fix_extent_len:
|
|
|
|
ex->ee_len = orig_ex.ee_len;
|
2014-07-28 06:30:29 +04:00
|
|
|
ext4_ext_dirty(handle, inode, path + path->p_depth);
|
2011-05-03 20:23:07 +04:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* ext4_split_extents() splits an extent and mark extent which is covered
|
|
|
|
* by @map as split_flags indicates
|
|
|
|
*
|
2013-08-28 22:40:12 +04:00
|
|
|
* It may result in splitting the extent into multiple extents (up to three)
|
2011-05-03 20:23:07 +04:00
|
|
|
* There are three possibilities:
|
|
|
|
* a> There is no split required
|
|
|
|
* b> Splits in two extents: Split is happening at either end of the extent
|
|
|
|
* c> Splits in three extents: Somone is splitting in middle of the extent
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
static int ext4_split_extent(handle_t *handle,
|
|
|
|
struct inode *inode,
|
2014-09-01 22:37:09 +04:00
|
|
|
struct ext4_ext_path **ppath,
|
2011-05-03 20:23:07 +04:00
|
|
|
struct ext4_map_blocks *map,
|
|
|
|
int split_flag,
|
|
|
|
int flags)
|
|
|
|
{
|
2014-09-01 22:37:09 +04:00
|
|
|
struct ext4_ext_path *path = *ppath;
|
2011-05-03 20:23:07 +04:00
|
|
|
ext4_lblk_t ee_block;
|
|
|
|
struct ext4_extent *ex;
|
|
|
|
unsigned int ee_len, depth;
|
|
|
|
int err = 0;
|
2014-04-21 07:45:47 +04:00
|
|
|
int unwritten;
|
2011-05-03 20:23:07 +04:00
|
|
|
int split_flag1, flags1;
|
2013-03-11 05:20:23 +04:00
|
|
|
int allocated = map->m_len;
|
2011-05-03 20:23:07 +04:00
|
|
|
|
|
|
|
depth = ext_depth(inode);
|
|
|
|
ex = path[depth].p_ext;
|
|
|
|
ee_block = le32_to_cpu(ex->ee_block);
|
|
|
|
ee_len = ext4_ext_get_actual_len(ex);
|
2014-04-21 07:45:47 +04:00
|
|
|
unwritten = ext4_ext_is_unwritten(ex);
|
2011-05-03 20:23:07 +04:00
|
|
|
|
|
|
|
if (map->m_lblk + map->m_len < ee_block + ee_len) {
|
2012-10-10 09:04:58 +04:00
|
|
|
split_flag1 = split_flag & EXT4_EXT_MAY_ZEROOUT;
|
2011-05-03 20:23:07 +04:00
|
|
|
flags1 = flags | EXT4_GET_BLOCKS_PRE_IO;
|
2014-04-21 07:45:47 +04:00
|
|
|
if (unwritten)
|
|
|
|
split_flag1 |= EXT4_EXT_MARK_UNWRIT1 |
|
|
|
|
EXT4_EXT_MARK_UNWRIT2;
|
2012-10-10 09:04:58 +04:00
|
|
|
if (split_flag & EXT4_EXT_DATA_VALID2)
|
|
|
|
split_flag1 |= EXT4_EXT_DATA_VALID1;
|
2014-09-01 22:37:09 +04:00
|
|
|
err = ext4_split_extent_at(handle, inode, ppath,
|
2011-05-03 20:23:07 +04:00
|
|
|
map->m_lblk + map->m_len, split_flag1, flags1);
|
2011-05-23 04:49:12 +04:00
|
|
|
if (err)
|
|
|
|
goto out;
|
2013-03-11 05:20:23 +04:00
|
|
|
} else {
|
|
|
|
allocated = ee_len - (map->m_lblk - ee_block);
|
2011-05-03 20:23:07 +04:00
|
|
|
}
|
ext4: ext4_split_extent should take care of extent zeroout
When ext4_split_extent_at() ends up doing zeroout & conversion to
initialized instead of split & conversion, ext4_split_extent() gets
confused and can wrongly mark the extent back as uninitialized
resulting in end IO code getting confused from large unwritten extents
and may result in data loss.
The example of problematic behavior is:
lblk len lblk len
ext4_split_extent() (ex=[1000,30,uninit], map=[1010,10])
ext4_split_extent_at() (split [1000,30,uninit] at 1020)
ext4_ext_insert_extent() -> ENOSPC
ext4_ext_zeroout()
-> extent [1000,30] is now initialized
ext4_split_extent_at() (split [1000,30,init] at 1010,
MARK_UNINIT1 | MARK_UNINIT2)
-> extent is split and parts marked as uninitialized
Fix the problem by rechecking extent type after the first
ext4_split_extent_at() returns. None of split_flags can not be applied
to initialized extent so this patch also add BUG_ON to prevent similar
issues in future.
TESTCASE: https://github.com/dmonakhov/xfstests/commit/b8a55eb5ce28c6ff29e620ab090902fcd5833597
Signed-off-by: Dmitry Monakhov <dmonakhov@openvz.org>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Reviewed-by: Jan Kara <jack@suse.cz>
2013-03-04 09:34:34 +04:00
|
|
|
/*
|
|
|
|
* Update path is required because previous ext4_split_extent_at() may
|
|
|
|
* result in split of original leaf or extent zeroout.
|
|
|
|
*/
|
2014-09-01 22:43:09 +04:00
|
|
|
path = ext4_find_extent(inode, map->m_lblk, ppath, 0);
|
2011-05-03 20:23:07 +04:00
|
|
|
if (IS_ERR(path))
|
|
|
|
return PTR_ERR(path);
|
ext4: ext4_split_extent should take care of extent zeroout
When ext4_split_extent_at() ends up doing zeroout & conversion to
initialized instead of split & conversion, ext4_split_extent() gets
confused and can wrongly mark the extent back as uninitialized
resulting in end IO code getting confused from large unwritten extents
and may result in data loss.
The example of problematic behavior is:
lblk len lblk len
ext4_split_extent() (ex=[1000,30,uninit], map=[1010,10])
ext4_split_extent_at() (split [1000,30,uninit] at 1020)
ext4_ext_insert_extent() -> ENOSPC
ext4_ext_zeroout()
-> extent [1000,30] is now initialized
ext4_split_extent_at() (split [1000,30,init] at 1010,
MARK_UNINIT1 | MARK_UNINIT2)
-> extent is split and parts marked as uninitialized
Fix the problem by rechecking extent type after the first
ext4_split_extent_at() returns. None of split_flags can not be applied
to initialized extent so this patch also add BUG_ON to prevent similar
issues in future.
TESTCASE: https://github.com/dmonakhov/xfstests/commit/b8a55eb5ce28c6ff29e620ab090902fcd5833597
Signed-off-by: Dmitry Monakhov <dmonakhov@openvz.org>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Reviewed-by: Jan Kara <jack@suse.cz>
2013-03-04 09:34:34 +04:00
|
|
|
depth = ext_depth(inode);
|
|
|
|
ex = path[depth].p_ext;
|
2014-04-13 23:41:13 +04:00
|
|
|
if (!ex) {
|
|
|
|
EXT4_ERROR_INODE(inode, "unexpected hole at %lu",
|
|
|
|
(unsigned long) map->m_lblk);
|
2015-10-17 23:16:04 +03:00
|
|
|
return -EFSCORRUPTED;
|
2014-04-13 23:41:13 +04:00
|
|
|
}
|
2014-04-21 07:45:47 +04:00
|
|
|
unwritten = ext4_ext_is_unwritten(ex);
|
ext4: ext4_split_extent should take care of extent zeroout
When ext4_split_extent_at() ends up doing zeroout & conversion to
initialized instead of split & conversion, ext4_split_extent() gets
confused and can wrongly mark the extent back as uninitialized
resulting in end IO code getting confused from large unwritten extents
and may result in data loss.
The example of problematic behavior is:
lblk len lblk len
ext4_split_extent() (ex=[1000,30,uninit], map=[1010,10])
ext4_split_extent_at() (split [1000,30,uninit] at 1020)
ext4_ext_insert_extent() -> ENOSPC
ext4_ext_zeroout()
-> extent [1000,30] is now initialized
ext4_split_extent_at() (split [1000,30,init] at 1010,
MARK_UNINIT1 | MARK_UNINIT2)
-> extent is split and parts marked as uninitialized
Fix the problem by rechecking extent type after the first
ext4_split_extent_at() returns. None of split_flags can not be applied
to initialized extent so this patch also add BUG_ON to prevent similar
issues in future.
TESTCASE: https://github.com/dmonakhov/xfstests/commit/b8a55eb5ce28c6ff29e620ab090902fcd5833597
Signed-off-by: Dmitry Monakhov <dmonakhov@openvz.org>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Reviewed-by: Jan Kara <jack@suse.cz>
2013-03-04 09:34:34 +04:00
|
|
|
split_flag1 = 0;
|
2011-05-03 20:23:07 +04:00
|
|
|
|
|
|
|
if (map->m_lblk >= ee_block) {
|
ext4: ext4_split_extent should take care of extent zeroout
When ext4_split_extent_at() ends up doing zeroout & conversion to
initialized instead of split & conversion, ext4_split_extent() gets
confused and can wrongly mark the extent back as uninitialized
resulting in end IO code getting confused from large unwritten extents
and may result in data loss.
The example of problematic behavior is:
lblk len lblk len
ext4_split_extent() (ex=[1000,30,uninit], map=[1010,10])
ext4_split_extent_at() (split [1000,30,uninit] at 1020)
ext4_ext_insert_extent() -> ENOSPC
ext4_ext_zeroout()
-> extent [1000,30] is now initialized
ext4_split_extent_at() (split [1000,30,init] at 1010,
MARK_UNINIT1 | MARK_UNINIT2)
-> extent is split and parts marked as uninitialized
Fix the problem by rechecking extent type after the first
ext4_split_extent_at() returns. None of split_flags can not be applied
to initialized extent so this patch also add BUG_ON to prevent similar
issues in future.
TESTCASE: https://github.com/dmonakhov/xfstests/commit/b8a55eb5ce28c6ff29e620ab090902fcd5833597
Signed-off-by: Dmitry Monakhov <dmonakhov@openvz.org>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Reviewed-by: Jan Kara <jack@suse.cz>
2013-03-04 09:34:34 +04:00
|
|
|
split_flag1 = split_flag & EXT4_EXT_DATA_VALID2;
|
2014-04-21 07:45:47 +04:00
|
|
|
if (unwritten) {
|
|
|
|
split_flag1 |= EXT4_EXT_MARK_UNWRIT1;
|
ext4: ext4_split_extent should take care of extent zeroout
When ext4_split_extent_at() ends up doing zeroout & conversion to
initialized instead of split & conversion, ext4_split_extent() gets
confused and can wrongly mark the extent back as uninitialized
resulting in end IO code getting confused from large unwritten extents
and may result in data loss.
The example of problematic behavior is:
lblk len lblk len
ext4_split_extent() (ex=[1000,30,uninit], map=[1010,10])
ext4_split_extent_at() (split [1000,30,uninit] at 1020)
ext4_ext_insert_extent() -> ENOSPC
ext4_ext_zeroout()
-> extent [1000,30] is now initialized
ext4_split_extent_at() (split [1000,30,init] at 1010,
MARK_UNINIT1 | MARK_UNINIT2)
-> extent is split and parts marked as uninitialized
Fix the problem by rechecking extent type after the first
ext4_split_extent_at() returns. None of split_flags can not be applied
to initialized extent so this patch also add BUG_ON to prevent similar
issues in future.
TESTCASE: https://github.com/dmonakhov/xfstests/commit/b8a55eb5ce28c6ff29e620ab090902fcd5833597
Signed-off-by: Dmitry Monakhov <dmonakhov@openvz.org>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Reviewed-by: Jan Kara <jack@suse.cz>
2013-03-04 09:34:34 +04:00
|
|
|
split_flag1 |= split_flag & (EXT4_EXT_MAY_ZEROOUT |
|
2014-04-21 07:45:47 +04:00
|
|
|
EXT4_EXT_MARK_UNWRIT2);
|
ext4: ext4_split_extent should take care of extent zeroout
When ext4_split_extent_at() ends up doing zeroout & conversion to
initialized instead of split & conversion, ext4_split_extent() gets
confused and can wrongly mark the extent back as uninitialized
resulting in end IO code getting confused from large unwritten extents
and may result in data loss.
The example of problematic behavior is:
lblk len lblk len
ext4_split_extent() (ex=[1000,30,uninit], map=[1010,10])
ext4_split_extent_at() (split [1000,30,uninit] at 1020)
ext4_ext_insert_extent() -> ENOSPC
ext4_ext_zeroout()
-> extent [1000,30] is now initialized
ext4_split_extent_at() (split [1000,30,init] at 1010,
MARK_UNINIT1 | MARK_UNINIT2)
-> extent is split and parts marked as uninitialized
Fix the problem by rechecking extent type after the first
ext4_split_extent_at() returns. None of split_flags can not be applied
to initialized extent so this patch also add BUG_ON to prevent similar
issues in future.
TESTCASE: https://github.com/dmonakhov/xfstests/commit/b8a55eb5ce28c6ff29e620ab090902fcd5833597
Signed-off-by: Dmitry Monakhov <dmonakhov@openvz.org>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Reviewed-by: Jan Kara <jack@suse.cz>
2013-03-04 09:34:34 +04:00
|
|
|
}
|
2014-09-01 22:37:09 +04:00
|
|
|
err = ext4_split_extent_at(handle, inode, ppath,
|
2011-05-03 20:23:07 +04:00
|
|
|
map->m_lblk, split_flag1, flags);
|
|
|
|
if (err)
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
ext4_ext_show_leaf(inode, path);
|
|
|
|
out:
|
2013-03-11 05:20:23 +04:00
|
|
|
return err ? err : allocated;
|
2011-05-03 20:23:07 +04:00
|
|
|
}
|
|
|
|
|
2007-07-18 05:42:38 +04:00
|
|
|
/*
|
2010-05-17 03:00:00 +04:00
|
|
|
* This function is called by ext4_ext_map_blocks() if someone tries to write
|
2014-04-21 07:45:47 +04:00
|
|
|
* to an unwritten extent. It may result in splitting the unwritten
|
2011-03-31 05:57:33 +04:00
|
|
|
* extent into multiple extents (up to three - one initialized and two
|
2014-04-21 07:45:47 +04:00
|
|
|
* unwritten).
|
2007-07-18 05:42:38 +04:00
|
|
|
* There are three possibilities:
|
|
|
|
* a> There is no split required: Entire extent should be initialized
|
|
|
|
* b> Splits in two extents: Write is happening at either end of the extent
|
|
|
|
* c> Splits in three extents: Somone is writing in middle of the extent
|
2011-10-27 19:43:23 +04:00
|
|
|
*
|
|
|
|
* Pre-conditions:
|
2014-04-21 07:45:47 +04:00
|
|
|
* - The extent pointed to by 'path' is unwritten.
|
2011-10-27 19:43:23 +04:00
|
|
|
* - The extent pointed to by 'path' contains a superset
|
|
|
|
* of the logical span [map->m_lblk, map->m_lblk + map->m_len).
|
|
|
|
*
|
|
|
|
* Post-conditions on success:
|
|
|
|
* - the returned value is the number of blocks beyond map->l_lblk
|
|
|
|
* that are allocated and initialized.
|
|
|
|
* It is guaranteed to be >= map->m_len.
|
2007-07-18 05:42:38 +04:00
|
|
|
*/
|
2008-01-29 07:58:27 +03:00
|
|
|
static int ext4_ext_convert_to_initialized(handle_t *handle,
|
2010-05-17 03:00:00 +04:00
|
|
|
struct inode *inode,
|
|
|
|
struct ext4_map_blocks *map,
|
2014-09-01 22:37:09 +04:00
|
|
|
struct ext4_ext_path **ppath,
|
2013-04-10 06:11:22 +04:00
|
|
|
int flags)
|
2007-07-18 05:42:38 +04:00
|
|
|
{
|
2014-09-01 22:37:09 +04:00
|
|
|
struct ext4_ext_path *path = *ppath;
|
2012-08-17 17:54:17 +04:00
|
|
|
struct ext4_sb_info *sbi;
|
2011-10-27 19:43:23 +04:00
|
|
|
struct ext4_extent_header *eh;
|
2011-05-03 20:25:07 +04:00
|
|
|
struct ext4_map_blocks split_map;
|
|
|
|
struct ext4_extent zero_ex;
|
2013-04-04 07:33:27 +04:00
|
|
|
struct ext4_extent *ex, *abut_ex;
|
2010-05-16 14:00:00 +04:00
|
|
|
ext4_lblk_t ee_block, eof_block;
|
2013-04-04 07:33:27 +04:00
|
|
|
unsigned int ee_len, depth, map_len = map->m_len;
|
|
|
|
int allocated = 0, max_zeroout = 0;
|
2007-07-18 05:42:38 +04:00
|
|
|
int err = 0;
|
2011-05-03 20:25:07 +04:00
|
|
|
int split_flag = 0;
|
2010-05-16 14:00:00 +04:00
|
|
|
|
|
|
|
ext_debug("ext4_ext_convert_to_initialized: inode %lu, logical"
|
|
|
|
"block %llu, max_blocks %u\n", inode->i_ino,
|
2013-04-04 07:33:27 +04:00
|
|
|
(unsigned long long)map->m_lblk, map_len);
|
2010-05-16 14:00:00 +04:00
|
|
|
|
2012-08-17 17:54:17 +04:00
|
|
|
sbi = EXT4_SB(inode->i_sb);
|
2010-05-16 14:00:00 +04:00
|
|
|
eof_block = (inode->i_size + inode->i_sb->s_blocksize - 1) >>
|
|
|
|
inode->i_sb->s_blocksize_bits;
|
2013-04-04 07:33:27 +04:00
|
|
|
if (eof_block < map->m_lblk + map_len)
|
|
|
|
eof_block = map->m_lblk + map_len;
|
2007-07-18 05:42:38 +04:00
|
|
|
|
|
|
|
depth = ext_depth(inode);
|
2011-10-27 19:43:23 +04:00
|
|
|
eh = path[depth].p_hdr;
|
2007-07-18 05:42:38 +04:00
|
|
|
ex = path[depth].p_ext;
|
|
|
|
ee_block = le32_to_cpu(ex->ee_block);
|
|
|
|
ee_len = ext4_ext_get_actual_len(ex);
|
2013-03-11 05:13:05 +04:00
|
|
|
zero_ex.ee_len = 0;
|
2007-07-18 05:42:38 +04:00
|
|
|
|
2011-10-27 19:43:23 +04:00
|
|
|
trace_ext4_ext_convert_to_initialized_enter(inode, map, ex);
|
|
|
|
|
|
|
|
/* Pre-conditions */
|
2014-04-21 07:45:47 +04:00
|
|
|
BUG_ON(!ext4_ext_is_unwritten(ex));
|
2011-10-27 19:43:23 +04:00
|
|
|
BUG_ON(!in_range(map->m_lblk, ee_block, ee_len));
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Attempt to transfer newly initialized blocks from the currently
|
2014-04-21 07:45:47 +04:00
|
|
|
* unwritten extent to its neighbor. This is much cheaper
|
2011-10-27 19:43:23 +04:00
|
|
|
* than an insertion followed by a merge as those involve costly
|
2013-04-04 07:33:27 +04:00
|
|
|
* memmove() calls. Transferring to the left is the common case in
|
|
|
|
* steady state for workloads doing fallocate(FALLOC_FL_KEEP_SIZE)
|
|
|
|
* followed by append writes.
|
2011-10-27 19:43:23 +04:00
|
|
|
*
|
|
|
|
* Limitations of the current logic:
|
2013-04-04 07:33:27 +04:00
|
|
|
* - L1: we do not deal with writes covering the whole extent.
|
2011-10-27 19:43:23 +04:00
|
|
|
* This would require removing the extent if the transfer
|
|
|
|
* is possible.
|
2013-04-04 07:33:27 +04:00
|
|
|
* - L2: we only attempt to merge with an extent stored in the
|
2011-10-27 19:43:23 +04:00
|
|
|
* same extent tree node.
|
|
|
|
*/
|
2013-04-04 07:33:27 +04:00
|
|
|
if ((map->m_lblk == ee_block) &&
|
|
|
|
/* See if we can merge left */
|
|
|
|
(map_len < ee_len) && /*L1*/
|
|
|
|
(ex > EXT_FIRST_EXTENT(eh))) { /*L2*/
|
2011-10-27 19:43:23 +04:00
|
|
|
ext4_lblk_t prev_lblk;
|
|
|
|
ext4_fsblk_t prev_pblk, ee_pblk;
|
2013-04-04 07:33:27 +04:00
|
|
|
unsigned int prev_len;
|
2011-10-27 19:43:23 +04:00
|
|
|
|
2013-04-04 07:33:27 +04:00
|
|
|
abut_ex = ex - 1;
|
|
|
|
prev_lblk = le32_to_cpu(abut_ex->ee_block);
|
|
|
|
prev_len = ext4_ext_get_actual_len(abut_ex);
|
|
|
|
prev_pblk = ext4_ext_pblock(abut_ex);
|
2011-10-27 19:43:23 +04:00
|
|
|
ee_pblk = ext4_ext_pblock(ex);
|
|
|
|
|
|
|
|
/*
|
2013-04-04 07:33:27 +04:00
|
|
|
* A transfer of blocks from 'ex' to 'abut_ex' is allowed
|
2011-10-27 19:43:23 +04:00
|
|
|
* upon those conditions:
|
2013-04-04 07:33:27 +04:00
|
|
|
* - C1: abut_ex is initialized,
|
|
|
|
* - C2: abut_ex is logically abutting ex,
|
|
|
|
* - C3: abut_ex is physically abutting ex,
|
|
|
|
* - C4: abut_ex can receive the additional blocks without
|
2011-10-27 19:43:23 +04:00
|
|
|
* overflowing the (initialized) length limit.
|
|
|
|
*/
|
2014-04-21 07:45:47 +04:00
|
|
|
if ((!ext4_ext_is_unwritten(abut_ex)) && /*C1*/
|
2011-10-27 19:43:23 +04:00
|
|
|
((prev_lblk + prev_len) == ee_block) && /*C2*/
|
|
|
|
((prev_pblk + prev_len) == ee_pblk) && /*C3*/
|
2013-04-04 07:33:27 +04:00
|
|
|
(prev_len < (EXT_INIT_MAX_LEN - map_len))) { /*C4*/
|
2011-10-27 19:43:23 +04:00
|
|
|
err = ext4_ext_get_access(handle, inode, path + depth);
|
|
|
|
if (err)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
trace_ext4_ext_convert_to_initialized_fastpath(inode,
|
2013-04-04 07:33:27 +04:00
|
|
|
map, ex, abut_ex);
|
2011-10-27 19:43:23 +04:00
|
|
|
|
2013-04-04 07:33:27 +04:00
|
|
|
/* Shift the start of ex by 'map_len' blocks */
|
|
|
|
ex->ee_block = cpu_to_le32(ee_block + map_len);
|
|
|
|
ext4_ext_store_pblock(ex, ee_pblk + map_len);
|
|
|
|
ex->ee_len = cpu_to_le16(ee_len - map_len);
|
2014-04-21 07:45:47 +04:00
|
|
|
ext4_ext_mark_unwritten(ex); /* Restore the flag */
|
2011-10-27 19:43:23 +04:00
|
|
|
|
2013-04-04 07:33:27 +04:00
|
|
|
/* Extend abut_ex by 'map_len' blocks */
|
|
|
|
abut_ex->ee_len = cpu_to_le16(prev_len + map_len);
|
2011-10-27 19:43:23 +04:00
|
|
|
|
2013-04-04 07:33:27 +04:00
|
|
|
/* Result: number of initialized blocks past m_lblk */
|
|
|
|
allocated = map_len;
|
|
|
|
}
|
|
|
|
} else if (((map->m_lblk + map_len) == (ee_block + ee_len)) &&
|
|
|
|
(map_len < ee_len) && /*L1*/
|
|
|
|
ex < EXT_LAST_EXTENT(eh)) { /*L2*/
|
|
|
|
/* See if we can merge right */
|
|
|
|
ext4_lblk_t next_lblk;
|
|
|
|
ext4_fsblk_t next_pblk, ee_pblk;
|
|
|
|
unsigned int next_len;
|
|
|
|
|
|
|
|
abut_ex = ex + 1;
|
|
|
|
next_lblk = le32_to_cpu(abut_ex->ee_block);
|
|
|
|
next_len = ext4_ext_get_actual_len(abut_ex);
|
|
|
|
next_pblk = ext4_ext_pblock(abut_ex);
|
|
|
|
ee_pblk = ext4_ext_pblock(ex);
|
2011-10-27 19:43:23 +04:00
|
|
|
|
2013-04-04 07:33:27 +04:00
|
|
|
/*
|
|
|
|
* A transfer of blocks from 'ex' to 'abut_ex' is allowed
|
|
|
|
* upon those conditions:
|
|
|
|
* - C1: abut_ex is initialized,
|
|
|
|
* - C2: abut_ex is logically abutting ex,
|
|
|
|
* - C3: abut_ex is physically abutting ex,
|
|
|
|
* - C4: abut_ex can receive the additional blocks without
|
|
|
|
* overflowing the (initialized) length limit.
|
|
|
|
*/
|
2014-04-21 07:45:47 +04:00
|
|
|
if ((!ext4_ext_is_unwritten(abut_ex)) && /*C1*/
|
2013-04-04 07:33:27 +04:00
|
|
|
((map->m_lblk + map_len) == next_lblk) && /*C2*/
|
|
|
|
((ee_pblk + ee_len) == next_pblk) && /*C3*/
|
|
|
|
(next_len < (EXT_INIT_MAX_LEN - map_len))) { /*C4*/
|
|
|
|
err = ext4_ext_get_access(handle, inode, path + depth);
|
|
|
|
if (err)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
trace_ext4_ext_convert_to_initialized_fastpath(inode,
|
|
|
|
map, ex, abut_ex);
|
|
|
|
|
|
|
|
/* Shift the start of abut_ex by 'map_len' blocks */
|
|
|
|
abut_ex->ee_block = cpu_to_le32(next_lblk - map_len);
|
|
|
|
ext4_ext_store_pblock(abut_ex, next_pblk - map_len);
|
|
|
|
ex->ee_len = cpu_to_le16(ee_len - map_len);
|
2014-04-21 07:45:47 +04:00
|
|
|
ext4_ext_mark_unwritten(ex); /* Restore the flag */
|
2013-04-04 07:33:27 +04:00
|
|
|
|
|
|
|
/* Extend abut_ex by 'map_len' blocks */
|
|
|
|
abut_ex->ee_len = cpu_to_le16(next_len + map_len);
|
2011-10-27 19:43:23 +04:00
|
|
|
|
|
|
|
/* Result: number of initialized blocks past m_lblk */
|
2013-04-04 07:33:27 +04:00
|
|
|
allocated = map_len;
|
2011-10-27 19:43:23 +04:00
|
|
|
}
|
|
|
|
}
|
2013-04-04 07:33:27 +04:00
|
|
|
if (allocated) {
|
|
|
|
/* Mark the block containing both extents as dirty */
|
|
|
|
ext4_ext_dirty(handle, inode, path + depth);
|
|
|
|
|
|
|
|
/* Update path to point to the right extent */
|
|
|
|
path[depth].p_ext = abut_ex;
|
|
|
|
goto out;
|
|
|
|
} else
|
|
|
|
allocated = ee_len - (map->m_lblk - ee_block);
|
2011-10-27 19:43:23 +04:00
|
|
|
|
2011-05-03 20:25:07 +04:00
|
|
|
WARN_ON(map->m_lblk < ee_block);
|
2010-05-16 14:00:00 +04:00
|
|
|
/*
|
|
|
|
* It is safe to convert extent to initialized via explicit
|
2014-01-06 23:05:23 +04:00
|
|
|
* zeroout only if extent is fully inside i_size or new_size.
|
2010-05-16 14:00:00 +04:00
|
|
|
*/
|
2011-05-03 20:25:07 +04:00
|
|
|
split_flag |= ee_block + ee_len <= eof_block ? EXT4_EXT_MAY_ZEROOUT : 0;
|
2010-05-16 14:00:00 +04:00
|
|
|
|
2012-08-17 17:54:17 +04:00
|
|
|
if (EXT4_EXT_MAY_ZEROOUT & split_flag)
|
|
|
|
max_zeroout = sbi->s_extent_max_zeroout_kb >>
|
2013-03-12 20:40:04 +04:00
|
|
|
(inode->i_sb->s_blocksize_bits - 10);
|
2012-08-17 17:54:17 +04:00
|
|
|
|
2015-10-03 17:49:29 +03:00
|
|
|
if (ext4_encrypted_inode(inode))
|
|
|
|
max_zeroout = 0;
|
|
|
|
|
2012-08-17 17:54:17 +04:00
|
|
|
/* If extent is less than s_max_zeroout_kb, zeroout directly */
|
|
|
|
if (max_zeroout && (ee_len <= max_zeroout)) {
|
2011-05-03 20:25:07 +04:00
|
|
|
err = ext4_ext_zeroout(inode, ex);
|
2008-04-17 18:38:59 +04:00
|
|
|
if (err)
|
2008-08-03 02:51:32 +04:00
|
|
|
goto out;
|
2013-03-11 05:13:05 +04:00
|
|
|
zero_ex.ee_block = ex->ee_block;
|
2013-04-03 20:27:18 +04:00
|
|
|
zero_ex.ee_len = cpu_to_le16(ext4_ext_get_actual_len(ex));
|
2013-03-11 05:13:05 +04:00
|
|
|
ext4_ext_store_pblock(&zero_ex, ext4_ext_pblock(ex));
|
2008-08-03 02:51:32 +04:00
|
|
|
|
|
|
|
err = ext4_ext_get_access(handle, inode, path + depth);
|
|
|
|
if (err)
|
|
|
|
goto out;
|
2011-05-03 20:25:07 +04:00
|
|
|
ext4_ext_mark_initialized(ex);
|
2012-08-17 17:44:17 +04:00
|
|
|
ext4_ext_try_to_merge(handle, inode, path, ex);
|
|
|
|
err = ext4_ext_dirty(handle, inode, path + path->p_depth);
|
2011-05-03 20:25:07 +04:00
|
|
|
goto out;
|
2007-07-18 05:42:38 +04:00
|
|
|
}
|
2011-05-03 20:25:07 +04:00
|
|
|
|
2007-07-18 05:42:38 +04:00
|
|
|
/*
|
2011-05-03 20:25:07 +04:00
|
|
|
* four cases:
|
|
|
|
* 1. split the extent into three extents.
|
|
|
|
* 2. split the extent into two extents, zeroout the first half.
|
|
|
|
* 3. split the extent into two extents, zeroout the second half.
|
|
|
|
* 4. split the extent into two extents with out zeroout.
|
2007-07-18 05:42:38 +04:00
|
|
|
*/
|
2011-05-03 20:25:07 +04:00
|
|
|
split_map.m_lblk = map->m_lblk;
|
|
|
|
split_map.m_len = map->m_len;
|
|
|
|
|
2012-08-17 17:54:17 +04:00
|
|
|
if (max_zeroout && (allocated > map->m_len)) {
|
|
|
|
if (allocated <= max_zeroout) {
|
2011-05-03 20:25:07 +04:00
|
|
|
/* case 3 */
|
|
|
|
zero_ex.ee_block =
|
2011-05-16 18:11:09 +04:00
|
|
|
cpu_to_le32(map->m_lblk);
|
|
|
|
zero_ex.ee_len = cpu_to_le16(allocated);
|
2011-05-03 20:25:07 +04:00
|
|
|
ext4_ext_store_pblock(&zero_ex,
|
|
|
|
ext4_ext_pblock(ex) + map->m_lblk - ee_block);
|
|
|
|
err = ext4_ext_zeroout(inode, &zero_ex);
|
2007-07-18 05:42:38 +04:00
|
|
|
if (err)
|
|
|
|
goto out;
|
2011-05-03 20:25:07 +04:00
|
|
|
split_map.m_lblk = map->m_lblk;
|
|
|
|
split_map.m_len = allocated;
|
2012-08-17 17:54:17 +04:00
|
|
|
} else if (map->m_lblk - ee_block + map->m_len < max_zeroout) {
|
2011-05-03 20:25:07 +04:00
|
|
|
/* case 2 */
|
|
|
|
if (map->m_lblk != ee_block) {
|
|
|
|
zero_ex.ee_block = ex->ee_block;
|
|
|
|
zero_ex.ee_len = cpu_to_le16(map->m_lblk -
|
|
|
|
ee_block);
|
|
|
|
ext4_ext_store_pblock(&zero_ex,
|
|
|
|
ext4_ext_pblock(ex));
|
|
|
|
err = ext4_ext_zeroout(inode, &zero_ex);
|
|
|
|
if (err)
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
split_map.m_lblk = ee_block;
|
2011-05-16 18:11:09 +04:00
|
|
|
split_map.m_len = map->m_lblk - ee_block + map->m_len;
|
|
|
|
allocated = map->m_len;
|
2007-07-18 05:42:38 +04:00
|
|
|
}
|
|
|
|
}
|
2011-05-03 20:25:07 +04:00
|
|
|
|
2014-10-30 17:53:17 +03:00
|
|
|
err = ext4_split_extent(handle, inode, ppath, &split_map, split_flag,
|
|
|
|
flags);
|
|
|
|
if (err > 0)
|
|
|
|
err = 0;
|
2007-07-18 05:42:38 +04:00
|
|
|
out:
|
2013-03-11 05:13:05 +04:00
|
|
|
/* If we have gotten a failure, don't zero out status tree */
|
|
|
|
if (!err)
|
2013-08-28 22:47:06 +04:00
|
|
|
err = ext4_zeroout_es(inode, &zero_ex);
|
2007-07-18 05:42:38 +04:00
|
|
|
return err ? err : allocated;
|
|
|
|
}
|
|
|
|
|
2009-09-28 23:49:08 +04:00
|
|
|
/*
|
2010-05-17 03:00:00 +04:00
|
|
|
* This function is called by ext4_ext_map_blocks() from
|
2009-09-28 23:49:08 +04:00
|
|
|
* ext4_get_blocks_dio_write() when DIO to write
|
2014-04-21 07:45:47 +04:00
|
|
|
* to an unwritten extent.
|
2009-09-28 23:49:08 +04:00
|
|
|
*
|
2014-04-21 07:45:47 +04:00
|
|
|
* Writing to an unwritten extent may result in splitting the unwritten
|
|
|
|
* extent into multiple initialized/unwritten extents (up to three)
|
2009-09-28 23:49:08 +04:00
|
|
|
* There are three possibilities:
|
2014-04-21 07:45:47 +04:00
|
|
|
* a> There is no split required: Entire extent should be unwritten
|
2009-09-28 23:49:08 +04:00
|
|
|
* b> Splits in two extents: Write is happening at either end of the extent
|
|
|
|
* c> Splits in three extents: Somone is writing in middle of the extent
|
|
|
|
*
|
2014-03-19 02:05:35 +04:00
|
|
|
* This works the same way in the case of initialized -> unwritten conversion.
|
|
|
|
*
|
2009-09-28 23:49:08 +04:00
|
|
|
* One of more index blocks maybe needed if the extent tree grow after
|
2014-04-21 07:45:47 +04:00
|
|
|
* the unwritten extent split. To prevent ENOSPC occur at the IO
|
|
|
|
* complete, we need to split the unwritten extent before DIO submit
|
|
|
|
* the IO. The unwritten extent called at this time will be split
|
|
|
|
* into three unwritten extent(at most). After IO complete, the part
|
2009-09-28 23:49:08 +04:00
|
|
|
* being filled will be convert to initialized by the end_io callback function
|
|
|
|
* via ext4_convert_unwritten_extents().
|
2009-11-06 12:01:23 +03:00
|
|
|
*
|
2014-04-21 07:45:47 +04:00
|
|
|
* Returns the size of unwritten extent to be written on success.
|
2009-09-28 23:49:08 +04:00
|
|
|
*/
|
2014-03-19 02:05:35 +04:00
|
|
|
static int ext4_split_convert_extents(handle_t *handle,
|
2009-09-28 23:49:08 +04:00
|
|
|
struct inode *inode,
|
2010-05-17 03:00:00 +04:00
|
|
|
struct ext4_map_blocks *map,
|
2014-09-01 22:37:09 +04:00
|
|
|
struct ext4_ext_path **ppath,
|
2009-09-28 23:49:08 +04:00
|
|
|
int flags)
|
|
|
|
{
|
2014-09-01 22:37:09 +04:00
|
|
|
struct ext4_ext_path *path = *ppath;
|
2011-05-03 20:25:07 +04:00
|
|
|
ext4_lblk_t eof_block;
|
|
|
|
ext4_lblk_t ee_block;
|
|
|
|
struct ext4_extent *ex;
|
|
|
|
unsigned int ee_len;
|
|
|
|
int split_flag = 0, depth;
|
2010-05-16 14:00:00 +04:00
|
|
|
|
2014-03-19 02:05:35 +04:00
|
|
|
ext_debug("%s: inode %lu, logical block %llu, max_blocks %u\n",
|
|
|
|
__func__, inode->i_ino,
|
|
|
|
(unsigned long long)map->m_lblk, map->m_len);
|
2010-05-16 14:00:00 +04:00
|
|
|
|
|
|
|
eof_block = (inode->i_size + inode->i_sb->s_blocksize - 1) >>
|
|
|
|
inode->i_sb->s_blocksize_bits;
|
2010-05-17 03:00:00 +04:00
|
|
|
if (eof_block < map->m_lblk + map->m_len)
|
|
|
|
eof_block = map->m_lblk + map->m_len;
|
2010-05-16 14:00:00 +04:00
|
|
|
/*
|
|
|
|
* It is safe to convert extent to initialized via explicit
|
|
|
|
* zeroout only if extent is fully insde i_size or new_size.
|
|
|
|
*/
|
2011-05-03 20:25:07 +04:00
|
|
|
depth = ext_depth(inode);
|
|
|
|
ex = path[depth].p_ext;
|
|
|
|
ee_block = le32_to_cpu(ex->ee_block);
|
|
|
|
ee_len = ext4_ext_get_actual_len(ex);
|
2009-09-28 23:49:08 +04:00
|
|
|
|
2014-03-19 02:05:35 +04:00
|
|
|
/* Convert to unwritten */
|
|
|
|
if (flags & EXT4_GET_BLOCKS_CONVERT_UNWRITTEN) {
|
|
|
|
split_flag |= EXT4_EXT_DATA_VALID1;
|
|
|
|
/* Convert to initialized */
|
|
|
|
} else if (flags & EXT4_GET_BLOCKS_CONVERT) {
|
|
|
|
split_flag |= ee_block + ee_len <= eof_block ?
|
|
|
|
EXT4_EXT_MAY_ZEROOUT : 0;
|
2014-04-21 07:45:47 +04:00
|
|
|
split_flag |= (EXT4_EXT_MARK_UNWRIT2 | EXT4_EXT_DATA_VALID2);
|
2014-03-19 02:05:35 +04:00
|
|
|
}
|
2011-05-03 20:25:07 +04:00
|
|
|
flags |= EXT4_GET_BLOCKS_PRE_IO;
|
2014-09-01 22:37:09 +04:00
|
|
|
return ext4_split_extent(handle, inode, ppath, map, split_flag, flags);
|
2009-09-28 23:49:08 +04:00
|
|
|
}
|
2011-05-03 19:45:29 +04:00
|
|
|
|
2010-03-02 21:28:44 +03:00
|
|
|
static int ext4_convert_unwritten_extents_endio(handle_t *handle,
|
2012-10-10 09:04:58 +04:00
|
|
|
struct inode *inode,
|
|
|
|
struct ext4_map_blocks *map,
|
2014-09-01 22:37:09 +04:00
|
|
|
struct ext4_ext_path **ppath)
|
2009-09-28 23:49:08 +04:00
|
|
|
{
|
2014-09-01 22:37:09 +04:00
|
|
|
struct ext4_ext_path *path = *ppath;
|
2009-09-28 23:49:08 +04:00
|
|
|
struct ext4_extent *ex;
|
2012-10-10 09:04:58 +04:00
|
|
|
ext4_lblk_t ee_block;
|
|
|
|
unsigned int ee_len;
|
2009-09-28 23:49:08 +04:00
|
|
|
int depth;
|
|
|
|
int err = 0;
|
|
|
|
|
|
|
|
depth = ext_depth(inode);
|
|
|
|
ex = path[depth].p_ext;
|
2012-10-10 09:04:58 +04:00
|
|
|
ee_block = le32_to_cpu(ex->ee_block);
|
|
|
|
ee_len = ext4_ext_get_actual_len(ex);
|
2009-09-28 23:49:08 +04:00
|
|
|
|
2011-05-03 19:45:29 +04:00
|
|
|
ext_debug("ext4_convert_unwritten_extents_endio: inode %lu, logical"
|
|
|
|
"block %llu, max_blocks %u\n", inode->i_ino,
|
2012-10-10 09:04:58 +04:00
|
|
|
(unsigned long long)ee_block, ee_len);
|
|
|
|
|
2013-03-04 09:41:05 +04:00
|
|
|
/* If extent is larger than requested it is a clear sign that we still
|
|
|
|
* have some extent state machine issues left. So extent_split is still
|
|
|
|
* required.
|
|
|
|
* TODO: Once all related issues will be fixed this situation should be
|
|
|
|
* illegal.
|
|
|
|
*/
|
2012-10-10 09:04:58 +04:00
|
|
|
if (ee_block != map->m_lblk || ee_len > map->m_len) {
|
2013-03-04 09:41:05 +04:00
|
|
|
#ifdef EXT4_DEBUG
|
|
|
|
ext4_warning("Inode (%ld) finished: extent logical block %llu,"
|
|
|
|
" len %u; IO logical block %llu, len %u\n",
|
|
|
|
inode->i_ino, (unsigned long long)ee_block, ee_len,
|
|
|
|
(unsigned long long)map->m_lblk, map->m_len);
|
|
|
|
#endif
|
2014-09-01 22:37:09 +04:00
|
|
|
err = ext4_split_convert_extents(handle, inode, map, ppath,
|
2014-03-19 02:05:35 +04:00
|
|
|
EXT4_GET_BLOCKS_CONVERT);
|
2012-10-10 09:04:58 +04:00
|
|
|
if (err < 0)
|
2014-09-01 22:37:09 +04:00
|
|
|
return err;
|
2014-09-01 22:43:09 +04:00
|
|
|
path = ext4_find_extent(inode, map->m_lblk, ppath, 0);
|
2014-09-01 22:37:09 +04:00
|
|
|
if (IS_ERR(path))
|
|
|
|
return PTR_ERR(path);
|
2012-10-10 09:04:58 +04:00
|
|
|
depth = ext_depth(inode);
|
|
|
|
ex = path[depth].p_ext;
|
|
|
|
}
|
2011-05-03 19:45:29 +04:00
|
|
|
|
2009-09-28 23:49:08 +04:00
|
|
|
err = ext4_ext_get_access(handle, inode, path + depth);
|
|
|
|
if (err)
|
|
|
|
goto out;
|
|
|
|
/* first mark the extent as initialized */
|
|
|
|
ext4_ext_mark_initialized(ex);
|
|
|
|
|
2011-05-03 19:45:29 +04:00
|
|
|
/* note: ext4_ext_correct_indexes() isn't needed here because
|
|
|
|
* borders are not changed
|
2009-09-28 23:49:08 +04:00
|
|
|
*/
|
2012-08-17 17:44:17 +04:00
|
|
|
ext4_ext_try_to_merge(handle, inode, path, ex);
|
2011-05-03 19:45:29 +04:00
|
|
|
|
2009-09-28 23:49:08 +04:00
|
|
|
/* Mark modified extent as dirty */
|
2012-08-17 17:44:17 +04:00
|
|
|
err = ext4_ext_dirty(handle, inode, path + path->p_depth);
|
2009-09-28 23:49:08 +04:00
|
|
|
out:
|
|
|
|
ext4_ext_show_leaf(inode, path);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2009-12-30 07:39:06 +03:00
|
|
|
static void unmap_underlying_metadata_blocks(struct block_device *bdev,
|
|
|
|
sector_t block, int count)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
unmap_underlying_metadata(bdev, block + i);
|
|
|
|
}
|
|
|
|
|
2010-10-28 05:23:12 +04:00
|
|
|
/*
|
|
|
|
* Handle EOFBLOCKS_FL flag, clearing it if necessary
|
|
|
|
*/
|
|
|
|
static int check_eofblocks_fl(handle_t *handle, struct inode *inode,
|
2011-01-10 21:03:35 +03:00
|
|
|
ext4_lblk_t lblk,
|
2010-10-28 05:23:12 +04:00
|
|
|
struct ext4_ext_path *path,
|
|
|
|
unsigned int len)
|
|
|
|
{
|
|
|
|
int i, depth;
|
|
|
|
struct ext4_extent_header *eh;
|
2011-03-23 21:08:27 +03:00
|
|
|
struct ext4_extent *last_ex;
|
2010-10-28 05:23:12 +04:00
|
|
|
|
|
|
|
if (!ext4_test_inode_flag(inode, EXT4_INODE_EOFBLOCKS))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
depth = ext_depth(inode);
|
|
|
|
eh = path[depth].p_hdr;
|
|
|
|
|
2012-03-22 05:47:55 +04:00
|
|
|
/*
|
|
|
|
* We're going to remove EOFBLOCKS_FL entirely in future so we
|
|
|
|
* do not care for this case anymore. Simply remove the flag
|
|
|
|
* if there are no extents.
|
|
|
|
*/
|
|
|
|
if (unlikely(!eh->eh_entries))
|
|
|
|
goto out;
|
2010-10-28 05:23:12 +04:00
|
|
|
last_ex = EXT_LAST_EXTENT(eh);
|
|
|
|
/*
|
|
|
|
* We should clear the EOFBLOCKS_FL flag if we are writing the
|
|
|
|
* last block in the last extent in the file. We test this by
|
|
|
|
* first checking to see if the caller to
|
|
|
|
* ext4_ext_get_blocks() was interested in the last block (or
|
|
|
|
* a block beyond the last block) in the current extent. If
|
|
|
|
* this turns out to be false, we can bail out from this
|
|
|
|
* function immediately.
|
|
|
|
*/
|
2011-01-10 21:03:35 +03:00
|
|
|
if (lblk + len < le32_to_cpu(last_ex->ee_block) +
|
2010-10-28 05:23:12 +04:00
|
|
|
ext4_ext_get_actual_len(last_ex))
|
|
|
|
return 0;
|
|
|
|
/*
|
|
|
|
* If the caller does appear to be planning to write at or
|
|
|
|
* beyond the end of the current extent, we then test to see
|
|
|
|
* if the current extent is the last extent in the file, by
|
|
|
|
* checking to make sure it was reached via the rightmost node
|
|
|
|
* at each level of the tree.
|
|
|
|
*/
|
|
|
|
for (i = depth-1; i >= 0; i--)
|
|
|
|
if (path[i].p_idx != EXT_LAST_INDEX(path[i].p_hdr))
|
|
|
|
return 0;
|
2012-03-22 05:47:55 +04:00
|
|
|
out:
|
2010-10-28 05:23:12 +04:00
|
|
|
ext4_clear_inode_flag(inode, EXT4_INODE_EOFBLOCKS);
|
|
|
|
return ext4_mark_inode_dirty(handle, inode);
|
|
|
|
}
|
|
|
|
|
2011-09-10 03:04:51 +04:00
|
|
|
/**
|
|
|
|
* ext4_find_delalloc_range: find delayed allocated block in the given range.
|
|
|
|
*
|
2012-11-09 06:57:35 +04:00
|
|
|
* Return 1 if there is a delalloc block in the range, otherwise 0.
|
2011-09-10 03:04:51 +04:00
|
|
|
*/
|
2013-02-18 09:28:47 +04:00
|
|
|
int ext4_find_delalloc_range(struct inode *inode,
|
|
|
|
ext4_lblk_t lblk_start,
|
|
|
|
ext4_lblk_t lblk_end)
|
2011-09-10 03:04:51 +04:00
|
|
|
{
|
2012-11-09 06:57:35 +04:00
|
|
|
struct extent_status es;
|
2011-09-10 03:04:51 +04:00
|
|
|
|
2013-05-03 10:15:52 +04:00
|
|
|
ext4_es_find_delayed_extent_range(inode, lblk_start, lblk_end, &es);
|
2013-02-18 09:26:51 +04:00
|
|
|
if (es.es_len == 0)
|
2012-11-09 06:57:35 +04:00
|
|
|
return 0; /* there is no delay extent in this tree */
|
2013-02-18 09:26:51 +04:00
|
|
|
else if (es.es_lblk <= lblk_start &&
|
|
|
|
lblk_start < es.es_lblk + es.es_len)
|
2012-11-09 06:57:35 +04:00
|
|
|
return 1;
|
2013-02-18 09:26:51 +04:00
|
|
|
else if (lblk_start <= es.es_lblk && es.es_lblk <= lblk_end)
|
2012-11-09 06:57:35 +04:00
|
|
|
return 1;
|
2011-09-10 03:04:51 +04:00
|
|
|
else
|
2012-11-09 06:57:35 +04:00
|
|
|
return 0;
|
2011-09-10 03:04:51 +04:00
|
|
|
}
|
|
|
|
|
2012-11-09 06:57:35 +04:00
|
|
|
int ext4_find_delalloc_cluster(struct inode *inode, ext4_lblk_t lblk)
|
2011-09-10 03:04:51 +04:00
|
|
|
{
|
|
|
|
struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
|
|
|
|
ext4_lblk_t lblk_start, lblk_end;
|
2013-12-20 18:29:35 +04:00
|
|
|
lblk_start = EXT4_LBLK_CMASK(sbi, lblk);
|
2011-09-10 03:04:51 +04:00
|
|
|
lblk_end = lblk_start + sbi->s_cluster_ratio - 1;
|
|
|
|
|
2012-11-09 06:57:35 +04:00
|
|
|
return ext4_find_delalloc_range(inode, lblk_start, lblk_end);
|
2011-09-10 03:04:51 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Determines how many complete clusters (out of those specified by the 'map')
|
|
|
|
* are under delalloc and were reserved quota for.
|
|
|
|
* This function is called when we are writing out the blocks that were
|
|
|
|
* originally written with their allocation delayed, but then the space was
|
|
|
|
* allocated using fallocate() before the delayed allocation could be resolved.
|
|
|
|
* The cases to look for are:
|
|
|
|
* ('=' indicated delayed allocated blocks
|
|
|
|
* '-' indicates non-delayed allocated blocks)
|
|
|
|
* (a) partial clusters towards beginning and/or end outside of allocated range
|
|
|
|
* are not delalloc'ed.
|
|
|
|
* Ex:
|
|
|
|
* |----c---=|====c====|====c====|===-c----|
|
|
|
|
* |++++++ allocated ++++++|
|
|
|
|
* ==> 4 complete clusters in above example
|
|
|
|
*
|
|
|
|
* (b) partial cluster (outside of allocated range) towards either end is
|
|
|
|
* marked for delayed allocation. In this case, we will exclude that
|
|
|
|
* cluster.
|
|
|
|
* Ex:
|
|
|
|
* |----====c========|========c========|
|
|
|
|
* |++++++ allocated ++++++|
|
|
|
|
* ==> 1 complete clusters in above example
|
|
|
|
*
|
|
|
|
* Ex:
|
|
|
|
* |================c================|
|
|
|
|
* |++++++ allocated ++++++|
|
|
|
|
* ==> 0 complete clusters in above example
|
|
|
|
*
|
|
|
|
* The ext4_da_update_reserve_space will be called only if we
|
|
|
|
* determine here that there were some "entire" clusters that span
|
|
|
|
* this 'allocated' range.
|
|
|
|
* In the non-bigalloc case, this function will just end up returning num_blks
|
|
|
|
* without ever calling ext4_find_delalloc_range.
|
|
|
|
*/
|
|
|
|
static unsigned int
|
|
|
|
get_reserved_cluster_alloc(struct inode *inode, ext4_lblk_t lblk_start,
|
|
|
|
unsigned int num_blks)
|
|
|
|
{
|
|
|
|
struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
|
|
|
|
ext4_lblk_t alloc_cluster_start, alloc_cluster_end;
|
|
|
|
ext4_lblk_t lblk_from, lblk_to, c_offset;
|
|
|
|
unsigned int allocated_clusters = 0;
|
|
|
|
|
|
|
|
alloc_cluster_start = EXT4_B2C(sbi, lblk_start);
|
|
|
|
alloc_cluster_end = EXT4_B2C(sbi, lblk_start + num_blks - 1);
|
|
|
|
|
|
|
|
/* max possible clusters for this allocation */
|
|
|
|
allocated_clusters = alloc_cluster_end - alloc_cluster_start + 1;
|
|
|
|
|
2011-09-10 03:18:51 +04:00
|
|
|
trace_ext4_get_reserved_cluster_alloc(inode, lblk_start, num_blks);
|
|
|
|
|
2011-09-10 03:04:51 +04:00
|
|
|
/* Check towards left side */
|
2013-12-20 18:29:35 +04:00
|
|
|
c_offset = EXT4_LBLK_COFF(sbi, lblk_start);
|
2011-09-10 03:04:51 +04:00
|
|
|
if (c_offset) {
|
2013-12-20 18:29:35 +04:00
|
|
|
lblk_from = EXT4_LBLK_CMASK(sbi, lblk_start);
|
2011-09-10 03:04:51 +04:00
|
|
|
lblk_to = lblk_from + c_offset - 1;
|
|
|
|
|
2012-11-09 06:57:35 +04:00
|
|
|
if (ext4_find_delalloc_range(inode, lblk_from, lblk_to))
|
2011-09-10 03:04:51 +04:00
|
|
|
allocated_clusters--;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Now check towards right. */
|
2013-12-20 18:29:35 +04:00
|
|
|
c_offset = EXT4_LBLK_COFF(sbi, lblk_start + num_blks);
|
2011-09-10 03:04:51 +04:00
|
|
|
if (allocated_clusters && c_offset) {
|
|
|
|
lblk_from = lblk_start + num_blks;
|
|
|
|
lblk_to = lblk_from + (sbi->s_cluster_ratio - c_offset) - 1;
|
|
|
|
|
2012-11-09 06:57:35 +04:00
|
|
|
if (ext4_find_delalloc_range(inode, lblk_from, lblk_to))
|
2011-09-10 03:04:51 +04:00
|
|
|
allocated_clusters--;
|
|
|
|
}
|
|
|
|
|
|
|
|
return allocated_clusters;
|
|
|
|
}
|
|
|
|
|
2014-03-19 02:05:35 +04:00
|
|
|
static int
|
2014-09-01 22:35:09 +04:00
|
|
|
convert_initialized_extent(handle_t *handle, struct inode *inode,
|
|
|
|
struct ext4_map_blocks *map,
|
2016-02-23 06:58:55 +03:00
|
|
|
struct ext4_ext_path **ppath,
|
2016-02-12 09:23:00 +03:00
|
|
|
unsigned int allocated)
|
2014-03-19 02:05:35 +04:00
|
|
|
{
|
2014-09-01 22:36:09 +04:00
|
|
|
struct ext4_ext_path *path = *ppath;
|
2014-09-01 22:35:09 +04:00
|
|
|
struct ext4_extent *ex;
|
|
|
|
ext4_lblk_t ee_block;
|
|
|
|
unsigned int ee_len;
|
|
|
|
int depth;
|
2014-03-19 02:05:35 +04:00
|
|
|
int err = 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Make sure that the extent is no bigger than we support with
|
2014-04-21 07:45:47 +04:00
|
|
|
* unwritten extent
|
2014-03-19 02:05:35 +04:00
|
|
|
*/
|
2014-04-21 07:45:47 +04:00
|
|
|
if (map->m_len > EXT_UNWRITTEN_MAX_LEN)
|
|
|
|
map->m_len = EXT_UNWRITTEN_MAX_LEN / 2;
|
2014-03-19 02:05:35 +04:00
|
|
|
|
2014-09-01 22:35:09 +04:00
|
|
|
depth = ext_depth(inode);
|
|
|
|
ex = path[depth].p_ext;
|
|
|
|
ee_block = le32_to_cpu(ex->ee_block);
|
|
|
|
ee_len = ext4_ext_get_actual_len(ex);
|
|
|
|
|
|
|
|
ext_debug("%s: inode %lu, logical"
|
|
|
|
"block %llu, max_blocks %u\n", __func__, inode->i_ino,
|
|
|
|
(unsigned long long)ee_block, ee_len);
|
|
|
|
|
|
|
|
if (ee_block != map->m_lblk || ee_len > map->m_len) {
|
2014-09-01 22:37:09 +04:00
|
|
|
err = ext4_split_convert_extents(handle, inode, map, ppath,
|
2014-09-01 22:35:09 +04:00
|
|
|
EXT4_GET_BLOCKS_CONVERT_UNWRITTEN);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
2014-09-01 22:43:09 +04:00
|
|
|
path = ext4_find_extent(inode, map->m_lblk, ppath, 0);
|
2014-09-01 22:35:09 +04:00
|
|
|
if (IS_ERR(path))
|
|
|
|
return PTR_ERR(path);
|
|
|
|
depth = ext_depth(inode);
|
|
|
|
ex = path[depth].p_ext;
|
|
|
|
if (!ex) {
|
|
|
|
EXT4_ERROR_INODE(inode, "unexpected hole at %lu",
|
|
|
|
(unsigned long) map->m_lblk);
|
2015-10-17 23:16:04 +03:00
|
|
|
return -EFSCORRUPTED;
|
2014-09-01 22:35:09 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
err = ext4_ext_get_access(handle, inode, path + depth);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
/* first mark the extent as unwritten */
|
|
|
|
ext4_ext_mark_unwritten(ex);
|
|
|
|
|
|
|
|
/* note: ext4_ext_correct_indexes() isn't needed here because
|
|
|
|
* borders are not changed
|
|
|
|
*/
|
|
|
|
ext4_ext_try_to_merge(handle, inode, path, ex);
|
|
|
|
|
|
|
|
/* Mark modified extent as dirty */
|
|
|
|
err = ext4_ext_dirty(handle, inode, path + path->p_depth);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
ext4_ext_show_leaf(inode, path);
|
|
|
|
|
|
|
|
ext4_update_inode_fsync_trans(handle, inode, 1);
|
|
|
|
err = check_eofblocks_fl(handle, inode, map->m_lblk, path, map->m_len);
|
|
|
|
if (err)
|
|
|
|
return err;
|
2014-03-19 02:05:35 +04:00
|
|
|
map->m_flags |= EXT4_MAP_UNWRITTEN;
|
|
|
|
if (allocated > map->m_len)
|
|
|
|
allocated = map->m_len;
|
|
|
|
map->m_len = allocated;
|
2014-09-01 22:35:09 +04:00
|
|
|
return allocated;
|
2014-03-19 02:05:35 +04:00
|
|
|
}
|
|
|
|
|
2009-09-28 23:49:08 +04:00
|
|
|
static int
|
2014-04-21 07:45:47 +04:00
|
|
|
ext4_ext_handle_unwritten_extents(handle_t *handle, struct inode *inode,
|
2010-05-17 03:00:00 +04:00
|
|
|
struct ext4_map_blocks *map,
|
2014-09-01 22:37:09 +04:00
|
|
|
struct ext4_ext_path **ppath, int flags,
|
2010-05-17 03:00:00 +04:00
|
|
|
unsigned int allocated, ext4_fsblk_t newblock)
|
2009-09-28 23:49:08 +04:00
|
|
|
{
|
2014-09-01 22:37:09 +04:00
|
|
|
struct ext4_ext_path *path = *ppath;
|
2009-09-28 23:49:08 +04:00
|
|
|
int ret = 0;
|
|
|
|
int err = 0;
|
|
|
|
|
2014-04-21 07:45:47 +04:00
|
|
|
ext_debug("ext4_ext_handle_unwritten_extents: inode %lu, logical "
|
2011-12-29 04:00:25 +04:00
|
|
|
"block %llu, max_blocks %u, flags %x, allocated %u\n",
|
2010-05-17 03:00:00 +04:00
|
|
|
inode->i_ino, (unsigned long long)map->m_lblk, map->m_len,
|
2009-09-28 23:49:08 +04:00
|
|
|
flags, allocated);
|
|
|
|
ext4_ext_show_leaf(inode, path);
|
|
|
|
|
2013-04-10 06:11:22 +04:00
|
|
|
/*
|
2014-04-21 07:45:47 +04:00
|
|
|
* When writing into unwritten space, we should not fail to
|
2013-04-10 06:11:22 +04:00
|
|
|
* allocate metadata blocks for the new extent block if needed.
|
|
|
|
*/
|
|
|
|
flags |= EXT4_GET_BLOCKS_METADATA_NOFAIL;
|
|
|
|
|
2014-04-21 07:45:47 +04:00
|
|
|
trace_ext4_ext_handle_unwritten_extents(inode, map, flags,
|
2012-11-08 23:33:43 +04:00
|
|
|
allocated, newblock);
|
2011-09-10 03:18:51 +04:00
|
|
|
|
2010-03-02 21:28:44 +03:00
|
|
|
/* get_block() before submit the IO, split the extent */
|
2014-05-12 20:55:07 +04:00
|
|
|
if (flags & EXT4_GET_BLOCKS_PRE_IO) {
|
2014-09-01 22:37:09 +04:00
|
|
|
ret = ext4_split_convert_extents(handle, inode, map, ppath,
|
|
|
|
flags | EXT4_GET_BLOCKS_CONVERT);
|
2012-09-29 07:36:25 +04:00
|
|
|
if (ret <= 0)
|
|
|
|
goto out;
|
2013-02-18 09:28:04 +04:00
|
|
|
map->m_flags |= EXT4_MAP_UNWRITTEN;
|
2009-09-28 23:49:08 +04:00
|
|
|
goto out;
|
|
|
|
}
|
2010-03-02 21:28:44 +03:00
|
|
|
/* IO end_io complete, convert the filled extent to written */
|
2014-05-12 20:55:07 +04:00
|
|
|
if (flags & EXT4_GET_BLOCKS_CONVERT) {
|
2015-12-07 23:10:26 +03:00
|
|
|
if (flags & EXT4_GET_BLOCKS_ZERO) {
|
|
|
|
if (allocated > map->m_len)
|
|
|
|
allocated = map->m_len;
|
|
|
|
err = ext4_issue_zeroout(inode, map->m_lblk, newblock,
|
|
|
|
allocated);
|
|
|
|
if (err < 0)
|
|
|
|
goto out2;
|
|
|
|
}
|
2012-10-10 09:04:58 +04:00
|
|
|
ret = ext4_convert_unwritten_extents_endio(handle, inode, map,
|
2014-09-01 22:37:09 +04:00
|
|
|
ppath);
|
2010-10-28 05:23:12 +04:00
|
|
|
if (ret >= 0) {
|
2009-12-09 07:51:10 +03:00
|
|
|
ext4_update_inode_fsync_trans(handle, inode, 1);
|
2011-01-10 21:03:35 +03:00
|
|
|
err = check_eofblocks_fl(handle, inode, map->m_lblk,
|
|
|
|
path, map->m_len);
|
2010-10-28 05:23:12 +04:00
|
|
|
} else
|
|
|
|
err = ret;
|
2013-03-11 05:08:52 +04:00
|
|
|
map->m_flags |= EXT4_MAP_MAPPED;
|
2014-02-12 19:42:45 +04:00
|
|
|
map->m_pblk = newblock;
|
2013-03-11 05:08:52 +04:00
|
|
|
if (allocated > map->m_len)
|
|
|
|
allocated = map->m_len;
|
|
|
|
map->m_len = allocated;
|
2009-09-28 23:49:08 +04:00
|
|
|
goto out2;
|
|
|
|
}
|
|
|
|
/* buffered IO case */
|
|
|
|
/*
|
|
|
|
* repeat fallocate creation request
|
|
|
|
* we already have an unwritten extent
|
|
|
|
*/
|
2014-04-21 07:45:47 +04:00
|
|
|
if (flags & EXT4_GET_BLOCKS_UNWRIT_EXT) {
|
2013-02-18 09:28:04 +04:00
|
|
|
map->m_flags |= EXT4_MAP_UNWRITTEN;
|
2009-09-28 23:49:08 +04:00
|
|
|
goto map_out;
|
2013-02-18 09:28:04 +04:00
|
|
|
}
|
2009-09-28 23:49:08 +04:00
|
|
|
|
|
|
|
/* buffered READ or buffered write_begin() lookup */
|
|
|
|
if ((flags & EXT4_GET_BLOCKS_CREATE) == 0) {
|
|
|
|
/*
|
|
|
|
* We have blocks reserved already. We
|
|
|
|
* return allocated blocks so that delalloc
|
|
|
|
* won't do block reservation for us. But
|
|
|
|
* the buffer head will be unmapped so that
|
|
|
|
* a read from the block returns 0s.
|
|
|
|
*/
|
2010-05-17 03:00:00 +04:00
|
|
|
map->m_flags |= EXT4_MAP_UNWRITTEN;
|
2009-09-28 23:49:08 +04:00
|
|
|
goto out1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* buffered write, writepage time, convert*/
|
2014-09-01 22:37:09 +04:00
|
|
|
ret = ext4_ext_convert_to_initialized(handle, inode, map, ppath, flags);
|
2011-10-25 16:15:12 +04:00
|
|
|
if (ret >= 0)
|
2009-12-09 07:51:10 +03:00
|
|
|
ext4_update_inode_fsync_trans(handle, inode, 1);
|
2009-09-28 23:49:08 +04:00
|
|
|
out:
|
|
|
|
if (ret <= 0) {
|
|
|
|
err = ret;
|
|
|
|
goto out2;
|
|
|
|
} else
|
|
|
|
allocated = ret;
|
2010-05-17 03:00:00 +04:00
|
|
|
map->m_flags |= EXT4_MAP_NEW;
|
2009-12-30 07:39:06 +03:00
|
|
|
/*
|
|
|
|
* if we allocated more blocks than requested
|
|
|
|
* we need to make sure we unmap the extra block
|
|
|
|
* allocated. The actual needed block will get
|
|
|
|
* unmapped later when we find the buffer_head marked
|
|
|
|
* new.
|
|
|
|
*/
|
2010-05-17 03:00:00 +04:00
|
|
|
if (allocated > map->m_len) {
|
2009-12-30 07:39:06 +03:00
|
|
|
unmap_underlying_metadata_blocks(inode->i_sb->s_bdev,
|
2010-05-17 03:00:00 +04:00
|
|
|
newblock + map->m_len,
|
|
|
|
allocated - map->m_len);
|
|
|
|
allocated = map->m_len;
|
2009-12-30 07:39:06 +03:00
|
|
|
}
|
2013-03-11 05:20:23 +04:00
|
|
|
map->m_len = allocated;
|
2010-01-25 12:00:31 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If we have done fallocate with the offset that is already
|
|
|
|
* delayed allocated, we would have block reservation
|
|
|
|
* and quota reservation done in the delayed write path.
|
|
|
|
* But fallocate would have already updated quota and block
|
|
|
|
* count for this offset. So cancel these reservation
|
|
|
|
*/
|
2011-09-10 03:04:51 +04:00
|
|
|
if (flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE) {
|
|
|
|
unsigned int reserved_clusters;
|
|
|
|
reserved_clusters = get_reserved_cluster_alloc(inode,
|
|
|
|
map->m_lblk, map->m_len);
|
|
|
|
if (reserved_clusters)
|
|
|
|
ext4_da_update_reserve_space(inode,
|
|
|
|
reserved_clusters,
|
|
|
|
0);
|
|
|
|
}
|
2010-01-25 12:00:31 +03:00
|
|
|
|
2009-09-28 23:49:08 +04:00
|
|
|
map_out:
|
2010-05-17 03:00:00 +04:00
|
|
|
map->m_flags |= EXT4_MAP_MAPPED;
|
2011-10-25 16:15:12 +04:00
|
|
|
if ((flags & EXT4_GET_BLOCKS_KEEP_SIZE) == 0) {
|
|
|
|
err = check_eofblocks_fl(handle, inode, map->m_lblk, path,
|
|
|
|
map->m_len);
|
|
|
|
if (err < 0)
|
|
|
|
goto out2;
|
|
|
|
}
|
2009-09-28 23:49:08 +04:00
|
|
|
out1:
|
2010-05-17 03:00:00 +04:00
|
|
|
if (allocated > map->m_len)
|
|
|
|
allocated = map->m_len;
|
2009-09-28 23:49:08 +04:00
|
|
|
ext4_ext_show_leaf(inode, path);
|
2010-05-17 03:00:00 +04:00
|
|
|
map->m_pblk = newblock;
|
|
|
|
map->m_len = allocated;
|
2009-09-28 23:49:08 +04:00
|
|
|
out2:
|
|
|
|
return err ? err : allocated;
|
|
|
|
}
|
2010-10-28 05:23:12 +04:00
|
|
|
|
2011-09-10 02:52:51 +04:00
|
|
|
/*
|
|
|
|
* get_implied_cluster_alloc - check to see if the requested
|
|
|
|
* allocation (in the map structure) overlaps with a cluster already
|
|
|
|
* allocated in an extent.
|
2011-09-10 03:18:51 +04:00
|
|
|
* @sb The filesystem superblock structure
|
2011-09-10 02:52:51 +04:00
|
|
|
* @map The requested lblk->pblk mapping
|
|
|
|
* @ex The extent structure which might contain an implied
|
|
|
|
* cluster allocation
|
|
|
|
*
|
|
|
|
* This function is called by ext4_ext_map_blocks() after we failed to
|
|
|
|
* find blocks that were already in the inode's extent tree. Hence,
|
|
|
|
* we know that the beginning of the requested region cannot overlap
|
|
|
|
* the extent from the inode's extent tree. There are three cases we
|
|
|
|
* want to catch. The first is this case:
|
|
|
|
*
|
|
|
|
* |--- cluster # N--|
|
|
|
|
* |--- extent ---| |---- requested region ---|
|
|
|
|
* |==========|
|
|
|
|
*
|
|
|
|
* The second case that we need to test for is this one:
|
|
|
|
*
|
|
|
|
* |--------- cluster # N ----------------|
|
|
|
|
* |--- requested region --| |------- extent ----|
|
|
|
|
* |=======================|
|
|
|
|
*
|
|
|
|
* The third case is when the requested region lies between two extents
|
|
|
|
* within the same cluster:
|
|
|
|
* |------------- cluster # N-------------|
|
|
|
|
* |----- ex -----| |---- ex_right ----|
|
|
|
|
* |------ requested region ------|
|
|
|
|
* |================|
|
|
|
|
*
|
|
|
|
* In each of the above cases, we need to set the map->m_pblk and
|
|
|
|
* map->m_len so it corresponds to the return the extent labelled as
|
|
|
|
* "|====|" from cluster #N, since it is already in use for data in
|
|
|
|
* cluster EXT4_B2C(sbi, map->m_lblk). We will then return 1 to
|
|
|
|
* signal to ext4_ext_map_blocks() that map->m_pblk should be treated
|
|
|
|
* as a new "allocated" block region. Otherwise, we will return 0 and
|
|
|
|
* ext4_ext_map_blocks() will then allocate one or more new clusters
|
|
|
|
* by calling ext4_mb_new_blocks().
|
|
|
|
*/
|
2011-09-10 03:18:51 +04:00
|
|
|
static int get_implied_cluster_alloc(struct super_block *sb,
|
2011-09-10 02:52:51 +04:00
|
|
|
struct ext4_map_blocks *map,
|
|
|
|
struct ext4_extent *ex,
|
|
|
|
struct ext4_ext_path *path)
|
|
|
|
{
|
2011-09-10 03:18:51 +04:00
|
|
|
struct ext4_sb_info *sbi = EXT4_SB(sb);
|
2013-12-20 18:29:35 +04:00
|
|
|
ext4_lblk_t c_offset = EXT4_LBLK_COFF(sbi, map->m_lblk);
|
2011-09-10 02:52:51 +04:00
|
|
|
ext4_lblk_t ex_cluster_start, ex_cluster_end;
|
2011-12-19 02:39:02 +04:00
|
|
|
ext4_lblk_t rr_cluster_start;
|
2011-09-10 02:52:51 +04:00
|
|
|
ext4_lblk_t ee_block = le32_to_cpu(ex->ee_block);
|
|
|
|
ext4_fsblk_t ee_start = ext4_ext_pblock(ex);
|
|
|
|
unsigned short ee_len = ext4_ext_get_actual_len(ex);
|
|
|
|
|
|
|
|
/* The extent passed in that we are trying to match */
|
|
|
|
ex_cluster_start = EXT4_B2C(sbi, ee_block);
|
|
|
|
ex_cluster_end = EXT4_B2C(sbi, ee_block + ee_len - 1);
|
|
|
|
|
|
|
|
/* The requested region passed into ext4_map_blocks() */
|
|
|
|
rr_cluster_start = EXT4_B2C(sbi, map->m_lblk);
|
|
|
|
|
|
|
|
if ((rr_cluster_start == ex_cluster_end) ||
|
|
|
|
(rr_cluster_start == ex_cluster_start)) {
|
|
|
|
if (rr_cluster_start == ex_cluster_end)
|
|
|
|
ee_start += ee_len - 1;
|
2013-12-20 18:29:35 +04:00
|
|
|
map->m_pblk = EXT4_PBLK_CMASK(sbi, ee_start) + c_offset;
|
2011-09-10 02:52:51 +04:00
|
|
|
map->m_len = min(map->m_len,
|
|
|
|
(unsigned) sbi->s_cluster_ratio - c_offset);
|
|
|
|
/*
|
|
|
|
* Check for and handle this case:
|
|
|
|
*
|
|
|
|
* |--------- cluster # N-------------|
|
|
|
|
* |------- extent ----|
|
|
|
|
* |--- requested region ---|
|
|
|
|
* |===========|
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (map->m_lblk < ee_block)
|
|
|
|
map->m_len = min(map->m_len, ee_block - map->m_lblk);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check for the case where there is already another allocated
|
|
|
|
* block to the right of 'ex' but before the end of the cluster.
|
|
|
|
*
|
|
|
|
* |------------- cluster # N-------------|
|
|
|
|
* |----- ex -----| |---- ex_right ----|
|
|
|
|
* |------ requested region ------|
|
|
|
|
* |================|
|
|
|
|
*/
|
|
|
|
if (map->m_lblk > ee_block) {
|
|
|
|
ext4_lblk_t next = ext4_ext_next_allocated_block(path);
|
|
|
|
map->m_len = min(map->m_len, next - map->m_lblk);
|
|
|
|
}
|
2011-09-10 03:18:51 +04:00
|
|
|
|
|
|
|
trace_ext4_get_implied_cluster_alloc_exit(sb, map, 1);
|
2011-09-10 02:52:51 +04:00
|
|
|
return 1;
|
|
|
|
}
|
2011-09-10 03:18:51 +04:00
|
|
|
|
|
|
|
trace_ext4_get_implied_cluster_alloc_exit(sb, map, 0);
|
2011-09-10 02:52:51 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-01-29 07:58:27 +03:00
|
|
|
/*
|
2008-02-25 23:29:55 +03:00
|
|
|
* Block allocation/map/preallocation routine for extents based files
|
|
|
|
*
|
|
|
|
*
|
2008-01-29 07:58:27 +03:00
|
|
|
* Need to be called with
|
2008-01-29 07:58:26 +03:00
|
|
|
* down_read(&EXT4_I(inode)->i_data_sem) if not allocating file system block
|
|
|
|
* (ie, create is zero). Otherwise down_write(&EXT4_I(inode)->i_data_sem)
|
2008-02-25 23:29:55 +03:00
|
|
|
*
|
|
|
|
* return > 0, number of of blocks already mapped/allocated
|
|
|
|
* if create == 0 and these are pre-allocated blocks
|
|
|
|
* buffer head is unmapped
|
|
|
|
* otherwise blocks are mapped
|
|
|
|
*
|
|
|
|
* return = 0, if plain look up failed (blocks have not been allocated)
|
|
|
|
* buffer head is unmapped
|
|
|
|
*
|
|
|
|
* return < 0, error case.
|
2008-01-29 07:58:27 +03:00
|
|
|
*/
|
2010-05-17 03:00:00 +04:00
|
|
|
int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
|
|
|
|
struct ext4_map_blocks *map, int flags)
|
2006-10-11 12:21:03 +04:00
|
|
|
{
|
|
|
|
struct ext4_ext_path *path = NULL;
|
2011-09-10 02:52:51 +04:00
|
|
|
struct ext4_extent newex, *ex, *ex2;
|
|
|
|
struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
|
2011-03-22 04:38:05 +03:00
|
|
|
ext4_fsblk_t newblock = 0;
|
2014-02-20 03:52:39 +04:00
|
|
|
int free_on_err = 0, err = 0, depth, ret;
|
2011-09-10 02:52:51 +04:00
|
|
|
unsigned int allocated = 0, offset = 0;
|
2011-10-29 17:23:38 +04:00
|
|
|
unsigned int allocated_clusters = 0;
|
2008-01-29 08:19:52 +03:00
|
|
|
struct ext4_allocation_request ar;
|
2011-09-10 02:52:51 +04:00
|
|
|
ext4_lblk_t cluster_offset;
|
2014-11-25 19:41:49 +03:00
|
|
|
bool map_from_cluster = false;
|
2006-10-11 12:21:03 +04:00
|
|
|
|
2009-09-01 16:44:37 +04:00
|
|
|
ext_debug("blocks %u/%u requested for inode %lu\n",
|
2010-05-17 03:00:00 +04:00
|
|
|
map->m_lblk, map->m_len, inode->i_ino);
|
2011-03-22 04:38:05 +03:00
|
|
|
trace_ext4_ext_map_blocks_enter(inode, map->m_lblk, map->m_len, flags);
|
2006-10-11 12:21:03 +04:00
|
|
|
|
|
|
|
/* find extent for this block */
|
2014-09-01 22:43:09 +04:00
|
|
|
path = ext4_find_extent(inode, map->m_lblk, NULL, 0);
|
2006-10-11 12:21:03 +04:00
|
|
|
if (IS_ERR(path)) {
|
|
|
|
err = PTR_ERR(path);
|
|
|
|
path = NULL;
|
|
|
|
goto out2;
|
|
|
|
}
|
|
|
|
|
|
|
|
depth = ext_depth(inode);
|
|
|
|
|
|
|
|
/*
|
2006-10-11 12:21:07 +04:00
|
|
|
* consistent leaf must not be empty;
|
|
|
|
* this situation is possible, though, _during_ tree modification;
|
2014-09-01 22:43:09 +04:00
|
|
|
* this is why assert can't be put in ext4_find_extent()
|
2006-10-11 12:21:03 +04:00
|
|
|
*/
|
2010-03-02 19:46:09 +03:00
|
|
|
if (unlikely(path[depth].p_ext == NULL && depth != 0)) {
|
|
|
|
EXT4_ERROR_INODE(inode, "bad extent address "
|
2010-05-17 07:00:00 +04:00
|
|
|
"lblock: %lu, depth: %d pblock %lld",
|
|
|
|
(unsigned long) map->m_lblk, depth,
|
|
|
|
path[depth].p_block);
|
2015-10-17 23:16:04 +03:00
|
|
|
err = -EFSCORRUPTED;
|
2009-12-14 17:53:52 +03:00
|
|
|
goto out2;
|
|
|
|
}
|
2006-10-11 12:21:03 +04:00
|
|
|
|
2006-12-07 07:41:33 +03:00
|
|
|
ex = path[depth].p_ext;
|
|
|
|
if (ex) {
|
2008-01-29 07:58:27 +03:00
|
|
|
ext4_lblk_t ee_block = le32_to_cpu(ex->ee_block);
|
2010-10-28 05:30:14 +04:00
|
|
|
ext4_fsblk_t ee_start = ext4_ext_pblock(ex);
|
2007-07-18 05:42:41 +04:00
|
|
|
unsigned short ee_len;
|
2006-10-11 12:21:06 +04:00
|
|
|
|
2014-03-19 02:05:35 +04:00
|
|
|
|
2006-10-11 12:21:06 +04:00
|
|
|
/*
|
2014-04-21 07:45:47 +04:00
|
|
|
* unwritten extents are treated as holes, except that
|
2007-07-18 05:42:38 +04:00
|
|
|
* we split out initialized portions during a write.
|
2006-10-11 12:21:06 +04:00
|
|
|
*/
|
2007-07-18 05:42:41 +04:00
|
|
|
ee_len = ext4_ext_get_actual_len(ex);
|
2011-09-10 03:18:51 +04:00
|
|
|
|
|
|
|
trace_ext4_ext_show_extent(inode, ee_block, ee_start, ee_len);
|
|
|
|
|
2006-10-11 12:21:07 +04:00
|
|
|
/* if found extent covers block, simply return it */
|
2010-05-17 03:00:00 +04:00
|
|
|
if (in_range(map->m_lblk, ee_block, ee_len)) {
|
|
|
|
newblock = map->m_lblk - ee_block + ee_start;
|
2006-10-11 12:21:07 +04:00
|
|
|
/* number of remaining blocks in the extent */
|
2010-05-17 03:00:00 +04:00
|
|
|
allocated = ee_len - (map->m_lblk - ee_block);
|
|
|
|
ext_debug("%u fit into %u:%d -> %llu\n", map->m_lblk,
|
|
|
|
ee_block, ee_len, newblock);
|
2007-07-18 05:42:38 +04:00
|
|
|
|
2014-03-19 02:05:35 +04:00
|
|
|
/*
|
|
|
|
* If the extent is initialized check whether the
|
|
|
|
* caller wants to convert it to unwritten.
|
|
|
|
*/
|
2014-04-21 07:45:47 +04:00
|
|
|
if ((!ext4_ext_is_unwritten(ex)) &&
|
2014-03-19 02:05:35 +04:00
|
|
|
(flags & EXT4_GET_BLOCKS_CONVERT_UNWRITTEN)) {
|
2014-09-01 22:35:09 +04:00
|
|
|
allocated = convert_initialized_extent(
|
2014-09-01 22:36:09 +04:00
|
|
|
handle, inode, map, &path,
|
2016-02-23 06:58:55 +03:00
|
|
|
allocated);
|
2014-03-19 02:05:35 +04:00
|
|
|
goto out2;
|
2014-04-21 07:45:47 +04:00
|
|
|
} else if (!ext4_ext_is_unwritten(ex))
|
2012-03-20 07:05:43 +04:00
|
|
|
goto out;
|
2013-02-18 09:31:07 +04:00
|
|
|
|
2014-04-21 07:45:47 +04:00
|
|
|
ret = ext4_ext_handle_unwritten_extents(
|
2014-09-01 22:37:09 +04:00
|
|
|
handle, inode, map, &path, flags,
|
2012-03-20 07:05:43 +04:00
|
|
|
allocated, newblock);
|
2014-02-20 03:52:39 +04:00
|
|
|
if (ret < 0)
|
|
|
|
err = ret;
|
|
|
|
else
|
|
|
|
allocated = ret;
|
2014-03-14 07:14:46 +04:00
|
|
|
goto out2;
|
2006-10-11 12:21:03 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2006-10-11 12:21:07 +04:00
|
|
|
* requested block isn't allocated yet;
|
2006-10-11 12:21:03 +04:00
|
|
|
* we couldn't try to create block if create flag is zero
|
|
|
|
*/
|
2009-05-14 08:58:52 +04:00
|
|
|
if ((flags & EXT4_GET_BLOCKS_CREATE) == 0) {
|
2016-03-10 06:46:57 +03:00
|
|
|
ext4_lblk_t hole_start, hole_len;
|
|
|
|
|
2016-03-10 06:54:00 +03:00
|
|
|
hole_start = map->m_lblk;
|
|
|
|
hole_len = ext4_ext_determine_hole(inode, path, &hole_start);
|
2007-07-18 05:42:38 +04:00
|
|
|
/*
|
|
|
|
* put just found gap into cache to speed up
|
|
|
|
* subsequent requests
|
|
|
|
*/
|
2016-03-10 06:46:57 +03:00
|
|
|
ext4_ext_put_gap_in_cache(inode, hole_start, hole_len);
|
2016-03-10 06:54:00 +03:00
|
|
|
|
|
|
|
/* Update hole_len to reflect hole size after map->m_lblk */
|
|
|
|
if (hole_start != map->m_lblk)
|
|
|
|
hole_len -= map->m_lblk - hole_start;
|
|
|
|
map->m_pblk = 0;
|
|
|
|
map->m_len = min_t(unsigned int, map->m_len, hole_len);
|
|
|
|
|
2006-10-11 12:21:03 +04:00
|
|
|
goto out2;
|
|
|
|
}
|
2011-09-10 02:52:51 +04:00
|
|
|
|
2006-10-11 12:21:03 +04:00
|
|
|
/*
|
2008-10-10 17:40:52 +04:00
|
|
|
* Okay, we need to do block allocation.
|
2006-10-11 12:21:24 +04:00
|
|
|
*/
|
2011-09-10 02:52:51 +04:00
|
|
|
newex.ee_block = cpu_to_le32(map->m_lblk);
|
2014-01-06 23:00:23 +04:00
|
|
|
cluster_offset = EXT4_LBLK_COFF(sbi, map->m_lblk);
|
2011-09-10 02:52:51 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If we are doing bigalloc, check to see if the extent returned
|
2014-09-01 22:43:09 +04:00
|
|
|
* by ext4_find_extent() implies a cluster we can use.
|
2011-09-10 02:52:51 +04:00
|
|
|
*/
|
|
|
|
if (cluster_offset && ex &&
|
2011-09-10 03:18:51 +04:00
|
|
|
get_implied_cluster_alloc(inode->i_sb, map, ex, path)) {
|
2011-09-10 02:52:51 +04:00
|
|
|
ar.len = allocated = map->m_len;
|
|
|
|
newblock = map->m_pblk;
|
2014-11-25 19:41:49 +03:00
|
|
|
map_from_cluster = true;
|
2011-09-10 02:52:51 +04:00
|
|
|
goto got_allocated_blocks;
|
|
|
|
}
|
2006-10-11 12:21:03 +04:00
|
|
|
|
2008-01-29 08:19:52 +03:00
|
|
|
/* find neighbour allocated blocks */
|
2010-05-17 03:00:00 +04:00
|
|
|
ar.lleft = map->m_lblk;
|
2008-01-29 08:19:52 +03:00
|
|
|
err = ext4_ext_search_left(inode, path, &ar.lleft, &ar.pleft);
|
|
|
|
if (err)
|
|
|
|
goto out2;
|
2010-05-17 03:00:00 +04:00
|
|
|
ar.lright = map->m_lblk;
|
2011-09-10 02:52:51 +04:00
|
|
|
ex2 = NULL;
|
|
|
|
err = ext4_ext_search_right(inode, path, &ar.lright, &ar.pright, &ex2);
|
2008-01-29 08:19:52 +03:00
|
|
|
if (err)
|
|
|
|
goto out2;
|
2007-05-24 21:04:13 +04:00
|
|
|
|
2011-09-10 02:52:51 +04:00
|
|
|
/* Check if the extent after searching to the right implies a
|
|
|
|
* cluster we can use. */
|
|
|
|
if ((sbi->s_cluster_ratio > 1) && ex2 &&
|
2011-09-10 03:18:51 +04:00
|
|
|
get_implied_cluster_alloc(inode->i_sb, map, ex2, path)) {
|
2011-09-10 02:52:51 +04:00
|
|
|
ar.len = allocated = map->m_len;
|
|
|
|
newblock = map->m_pblk;
|
2014-11-25 19:41:49 +03:00
|
|
|
map_from_cluster = true;
|
2011-09-10 02:52:51 +04:00
|
|
|
goto got_allocated_blocks;
|
|
|
|
}
|
|
|
|
|
2007-07-18 17:02:56 +04:00
|
|
|
/*
|
|
|
|
* See if request is beyond maximum number of blocks we can have in
|
|
|
|
* a single extent. For an initialized extent this limit is
|
2014-04-21 07:45:47 +04:00
|
|
|
* EXT_INIT_MAX_LEN and for an unwritten extent this limit is
|
|
|
|
* EXT_UNWRITTEN_MAX_LEN.
|
2007-07-18 17:02:56 +04:00
|
|
|
*/
|
2010-05-17 03:00:00 +04:00
|
|
|
if (map->m_len > EXT_INIT_MAX_LEN &&
|
2014-04-21 07:45:47 +04:00
|
|
|
!(flags & EXT4_GET_BLOCKS_UNWRIT_EXT))
|
2010-05-17 03:00:00 +04:00
|
|
|
map->m_len = EXT_INIT_MAX_LEN;
|
2014-04-21 07:45:47 +04:00
|
|
|
else if (map->m_len > EXT_UNWRITTEN_MAX_LEN &&
|
|
|
|
(flags & EXT4_GET_BLOCKS_UNWRIT_EXT))
|
|
|
|
map->m_len = EXT_UNWRITTEN_MAX_LEN;
|
2007-07-18 17:02:56 +04:00
|
|
|
|
2010-05-17 03:00:00 +04:00
|
|
|
/* Check if we can really insert (m_lblk)::(m_lblk + m_len) extent */
|
|
|
|
newex.ee_len = cpu_to_le16(map->m_len);
|
2011-09-10 02:52:51 +04:00
|
|
|
err = ext4_ext_check_overlap(sbi, inode, &newex, path);
|
2007-05-24 21:04:13 +04:00
|
|
|
if (err)
|
2008-01-29 07:58:27 +03:00
|
|
|
allocated = ext4_ext_get_actual_len(&newex);
|
2007-05-24 21:04:13 +04:00
|
|
|
else
|
2010-05-17 03:00:00 +04:00
|
|
|
allocated = map->m_len;
|
2008-01-29 08:19:52 +03:00
|
|
|
|
|
|
|
/* allocate new block */
|
|
|
|
ar.inode = inode;
|
2010-05-17 03:00:00 +04:00
|
|
|
ar.goal = ext4_ext_find_goal(inode, path, map->m_lblk);
|
|
|
|
ar.logical = map->m_lblk;
|
2011-09-10 02:52:51 +04:00
|
|
|
/*
|
|
|
|
* We calculate the offset from the beginning of the cluster
|
|
|
|
* for the logical block number, since when we allocate a
|
|
|
|
* physical cluster, the physical block should start at the
|
|
|
|
* same offset from the beginning of the cluster. This is
|
|
|
|
* needed so that future calls to get_implied_cluster_alloc()
|
|
|
|
* work correctly.
|
|
|
|
*/
|
2013-12-20 18:29:35 +04:00
|
|
|
offset = EXT4_LBLK_COFF(sbi, map->m_lblk);
|
2011-09-10 02:52:51 +04:00
|
|
|
ar.len = EXT4_NUM_B2C(sbi, offset+allocated);
|
|
|
|
ar.goal -= offset;
|
|
|
|
ar.logical -= offset;
|
2008-01-29 08:19:52 +03:00
|
|
|
if (S_ISREG(inode->i_mode))
|
|
|
|
ar.flags = EXT4_MB_HINT_DATA;
|
|
|
|
else
|
|
|
|
/* disable in-core preallocation for non-regular files */
|
|
|
|
ar.flags = 0;
|
2011-05-25 15:41:54 +04:00
|
|
|
if (flags & EXT4_GET_BLOCKS_NO_NORMALIZE)
|
|
|
|
ar.flags |= EXT4_MB_HINT_NOPREALLOC;
|
2014-09-05 02:07:25 +04:00
|
|
|
if (flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE)
|
|
|
|
ar.flags |= EXT4_MB_DELALLOC_RESERVED;
|
2015-06-21 08:25:29 +03:00
|
|
|
if (flags & EXT4_GET_BLOCKS_METADATA_NOFAIL)
|
|
|
|
ar.flags |= EXT4_MB_USE_RESERVED;
|
2008-01-29 08:19:52 +03:00
|
|
|
newblock = ext4_mb_new_blocks(handle, &ar, &err);
|
2006-10-11 12:21:03 +04:00
|
|
|
if (!newblock)
|
|
|
|
goto out2;
|
2009-09-01 16:44:37 +04:00
|
|
|
ext_debug("allocate new block: goal %llu, found %llu/%u\n",
|
2008-11-05 08:14:04 +03:00
|
|
|
ar.goal, newblock, allocated);
|
2011-09-10 02:52:51 +04:00
|
|
|
free_on_err = 1;
|
2011-09-10 03:04:51 +04:00
|
|
|
allocated_clusters = ar.len;
|
2011-09-10 02:52:51 +04:00
|
|
|
ar.len = EXT4_C2B(sbi, ar.len) - offset;
|
|
|
|
if (ar.len > allocated)
|
|
|
|
ar.len = allocated;
|
2006-10-11 12:21:03 +04:00
|
|
|
|
2011-09-10 02:52:51 +04:00
|
|
|
got_allocated_blocks:
|
2006-10-11 12:21:03 +04:00
|
|
|
/* try to insert new extent into found leaf and return */
|
2011-09-10 02:52:51 +04:00
|
|
|
ext4_ext_store_pblock(&newex, newblock + offset);
|
2008-01-29 08:19:52 +03:00
|
|
|
newex.ee_len = cpu_to_le16(ar.len);
|
2014-04-21 07:45:47 +04:00
|
|
|
/* Mark unwritten */
|
|
|
|
if (flags & EXT4_GET_BLOCKS_UNWRIT_EXT){
|
|
|
|
ext4_ext_mark_unwritten(&newex);
|
2013-02-18 09:28:04 +04:00
|
|
|
map->m_flags |= EXT4_MAP_UNWRITTEN;
|
2009-09-28 23:48:29 +04:00
|
|
|
}
|
2010-02-24 17:52:53 +03:00
|
|
|
|
2011-10-25 16:15:12 +04:00
|
|
|
err = 0;
|
|
|
|
if ((flags & EXT4_GET_BLOCKS_KEEP_SIZE) == 0)
|
|
|
|
err = check_eofblocks_fl(handle, inode, map->m_lblk,
|
|
|
|
path, ar.len);
|
2011-07-11 04:07:25 +04:00
|
|
|
if (!err)
|
2014-09-01 22:37:09 +04:00
|
|
|
err = ext4_ext_insert_extent(handle, inode, &path,
|
2011-07-11 04:07:25 +04:00
|
|
|
&newex, flags);
|
2012-09-29 07:36:25 +04:00
|
|
|
|
2011-09-10 02:52:51 +04:00
|
|
|
if (err && free_on_err) {
|
ext4: fix i_blocks/quota accounting when extent insertion fails
The current implementation of ext4_free_blocks() always calls
dquot_free_block This looks quite sensible in the most cases: blocks
to be freed are associated with inode and were accounted in quota and
i_blocks some time ago.
However, there is a case when blocks to free were not accounted by the
time calling ext4_free_blocks() yet:
1. delalloc is on, write_begin pre-allocated some space in quota
2. write-back happens, ext4 allocates some blocks in ext4_ext_map_blocks()
3. then ext4_ext_map_blocks() gets an error (e.g. ENOSPC) from
ext4_ext_insert_extent() and calls ext4_free_blocks().
In this scenario, ext4_free_blocks() calls dquot_free_block() who, in
turn, decrements i_blocks for blocks which were not accounted yet (due
to delalloc) After clean umount, e2fsck reports something like:
> Inode 21, i_blocks is 5080, should be 5128. Fix<y>?
because i_blocks was erroneously decremented as explained above.
The patch fixes the problem by passing the new flag
EXT4_FREE_BLOCKS_NO_QUOT_UPDATE to ext4_free_blocks(), to request
that the dquot_free_block() call be skipped.
Signed-off-by: Maxim Patlasov <maxim.patlasov@gmail.com>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Cc: stable@kernel.org
2011-07-11 03:37:48 +04:00
|
|
|
int fb_flags = flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE ?
|
|
|
|
EXT4_FREE_BLOCKS_NO_QUOT_UPDATE : 0;
|
2007-05-24 21:04:25 +04:00
|
|
|
/* free data blocks we just allocated */
|
2008-01-29 08:19:52 +03:00
|
|
|
/* not a good idea to call discard here directly,
|
|
|
|
* but otherwise we'd need to call it every free() */
|
2008-10-10 17:40:52 +04:00
|
|
|
ext4_discard_preallocations(inode);
|
2013-07-15 08:09:37 +04:00
|
|
|
ext4_free_blocks(handle, inode, NULL, newblock,
|
|
|
|
EXT4_C2B(sbi, allocated_clusters), fb_flags);
|
2006-10-11 12:21:03 +04:00
|
|
|
goto out2;
|
2007-05-24 21:04:25 +04:00
|
|
|
}
|
2006-10-11 12:21:03 +04:00
|
|
|
|
|
|
|
/* previous routine could use block we allocated */
|
2010-10-28 05:30:14 +04:00
|
|
|
newblock = ext4_ext_pblock(&newex);
|
2008-01-29 07:58:27 +03:00
|
|
|
allocated = ext4_ext_get_actual_len(&newex);
|
2010-05-17 03:00:00 +04:00
|
|
|
if (allocated > map->m_len)
|
|
|
|
allocated = map->m_len;
|
|
|
|
map->m_flags |= EXT4_MAP_NEW;
|
2006-10-11 12:21:03 +04:00
|
|
|
|
2010-01-25 12:00:31 +03:00
|
|
|
/*
|
|
|
|
* Update reserved blocks/metadata blocks after successful
|
|
|
|
* block allocation which had been deferred till now.
|
|
|
|
*/
|
2011-09-10 03:04:51 +04:00
|
|
|
if (flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE) {
|
2011-10-29 17:23:38 +04:00
|
|
|
unsigned int reserved_clusters;
|
2011-09-10 03:04:51 +04:00
|
|
|
/*
|
2011-10-29 17:23:38 +04:00
|
|
|
* Check how many clusters we had reserved this allocated range
|
2011-09-10 03:04:51 +04:00
|
|
|
*/
|
|
|
|
reserved_clusters = get_reserved_cluster_alloc(inode,
|
|
|
|
map->m_lblk, allocated);
|
2015-04-03 07:17:31 +03:00
|
|
|
if (!map_from_cluster) {
|
2011-09-10 03:04:51 +04:00
|
|
|
BUG_ON(allocated_clusters < reserved_clusters);
|
|
|
|
if (reserved_clusters < allocated_clusters) {
|
2011-09-10 03:20:51 +04:00
|
|
|
struct ext4_inode_info *ei = EXT4_I(inode);
|
2011-09-10 03:04:51 +04:00
|
|
|
int reservation = allocated_clusters -
|
|
|
|
reserved_clusters;
|
|
|
|
/*
|
|
|
|
* It seems we claimed few clusters outside of
|
|
|
|
* the range of this allocation. We should give
|
|
|
|
* it back to the reservation pool. This can
|
|
|
|
* happen in the following case:
|
|
|
|
*
|
|
|
|
* * Suppose s_cluster_ratio is 4 (i.e., each
|
|
|
|
* cluster has 4 blocks. Thus, the clusters
|
|
|
|
* are [0-3],[4-7],[8-11]...
|
|
|
|
* * First comes delayed allocation write for
|
|
|
|
* logical blocks 10 & 11. Since there were no
|
|
|
|
* previous delayed allocated blocks in the
|
|
|
|
* range [8-11], we would reserve 1 cluster
|
|
|
|
* for this write.
|
|
|
|
* * Next comes write for logical blocks 3 to 8.
|
|
|
|
* In this case, we will reserve 2 clusters
|
|
|
|
* (for [0-3] and [4-7]; and not for [8-11] as
|
|
|
|
* that range has a delayed allocated blocks.
|
|
|
|
* Thus total reserved clusters now becomes 3.
|
|
|
|
* * Now, during the delayed allocation writeout
|
|
|
|
* time, we will first write blocks [3-8] and
|
|
|
|
* allocate 3 clusters for writing these
|
|
|
|
* blocks. Also, we would claim all these
|
|
|
|
* three clusters above.
|
|
|
|
* * Now when we come here to writeout the
|
|
|
|
* blocks [10-11], we would expect to claim
|
|
|
|
* the reservation of 1 cluster we had made
|
|
|
|
* (and we would claim it since there are no
|
|
|
|
* more delayed allocated blocks in the range
|
|
|
|
* [8-11]. But our reserved cluster count had
|
|
|
|
* already gone to 0.
|
|
|
|
*
|
|
|
|
* Thus, at the step 4 above when we determine
|
|
|
|
* that there are still some unwritten delayed
|
|
|
|
* allocated blocks outside of our current
|
|
|
|
* block range, we should increment the
|
|
|
|
* reserved clusters count so that when the
|
|
|
|
* remaining blocks finally gets written, we
|
|
|
|
* could claim them.
|
|
|
|
*/
|
2011-09-10 03:20:51 +04:00
|
|
|
dquot_reserve_block(inode,
|
|
|
|
EXT4_C2B(sbi, reservation));
|
|
|
|
spin_lock(&ei->i_block_reservation_lock);
|
|
|
|
ei->i_reserved_data_blocks += reservation;
|
|
|
|
spin_unlock(&ei->i_block_reservation_lock);
|
2011-09-10 03:04:51 +04:00
|
|
|
}
|
2013-03-11 06:46:30 +04:00
|
|
|
/*
|
|
|
|
* We will claim quota for all newly allocated blocks.
|
|
|
|
* We're updating the reserved space *after* the
|
|
|
|
* correction above so we do not accidentally free
|
|
|
|
* all the metadata reservation because we might
|
|
|
|
* actually need it later on.
|
|
|
|
*/
|
|
|
|
ext4_da_update_reserve_space(inode, allocated_clusters,
|
|
|
|
1);
|
2011-09-10 03:04:51 +04:00
|
|
|
}
|
|
|
|
}
|
2010-01-25 12:00:31 +03:00
|
|
|
|
2009-12-09 07:51:10 +03:00
|
|
|
/*
|
|
|
|
* Cache the extent and update transaction to commit on fdatasync only
|
2014-04-21 07:45:47 +04:00
|
|
|
* when it is _not_ an unwritten extent.
|
2009-12-09 07:51:10 +03:00
|
|
|
*/
|
2014-04-21 07:45:47 +04:00
|
|
|
if ((flags & EXT4_GET_BLOCKS_UNWRIT_EXT) == 0)
|
2009-12-09 07:51:10 +03:00
|
|
|
ext4_update_inode_fsync_trans(handle, inode, 1);
|
2013-02-18 09:31:07 +04:00
|
|
|
else
|
2009-12-09 07:51:10 +03:00
|
|
|
ext4_update_inode_fsync_trans(handle, inode, 0);
|
2006-10-11 12:21:03 +04:00
|
|
|
out:
|
2010-05-17 03:00:00 +04:00
|
|
|
if (allocated > map->m_len)
|
|
|
|
allocated = map->m_len;
|
2006-10-11 12:21:03 +04:00
|
|
|
ext4_ext_show_leaf(inode, path);
|
2010-05-17 03:00:00 +04:00
|
|
|
map->m_flags |= EXT4_MAP_MAPPED;
|
|
|
|
map->m_pblk = newblock;
|
|
|
|
map->m_len = allocated;
|
2006-10-11 12:21:03 +04:00
|
|
|
out2:
|
2014-09-01 22:39:09 +04:00
|
|
|
ext4_ext_drop_refs(path);
|
|
|
|
kfree(path);
|
2011-05-25 15:41:46 +04:00
|
|
|
|
2013-07-16 18:28:47 +04:00
|
|
|
trace_ext4_ext_map_blocks_exit(inode, flags, map,
|
|
|
|
err ? err : allocated);
|
2012-03-20 07:05:43 +04:00
|
|
|
return err ? err : allocated;
|
2006-10-11 12:21:03 +04:00
|
|
|
}
|
|
|
|
|
2013-04-03 20:47:17 +04:00
|
|
|
void ext4_ext_truncate(handle_t *handle, struct inode *inode)
|
2006-10-11 12:21:03 +04:00
|
|
|
{
|
|
|
|
struct super_block *sb = inode->i_sb;
|
2008-01-29 07:58:27 +03:00
|
|
|
ext4_lblk_t last_block;
|
2006-10-11 12:21:03 +04:00
|
|
|
int err = 0;
|
|
|
|
|
|
|
|
/*
|
2006-10-11 12:21:07 +04:00
|
|
|
* TODO: optimization is possible here.
|
|
|
|
* Probably we need not scan at all,
|
|
|
|
* because page truncation is enough.
|
2006-10-11 12:21:03 +04:00
|
|
|
*/
|
|
|
|
|
|
|
|
/* we have to know where to truncate from in crash case */
|
|
|
|
EXT4_I(inode)->i_disksize = inode->i_size;
|
|
|
|
ext4_mark_inode_dirty(handle, inode);
|
|
|
|
|
|
|
|
last_block = (inode->i_size + sb->s_blocksize - 1)
|
|
|
|
>> EXT4_BLOCK_SIZE_BITS(sb);
|
2013-07-15 08:09:19 +04:00
|
|
|
retry:
|
2012-11-09 06:57:32 +04:00
|
|
|
err = ext4_es_remove_extent(inode, last_block,
|
|
|
|
EXT_MAX_BLOCKS - last_block);
|
2013-07-29 20:12:56 +04:00
|
|
|
if (err == -ENOMEM) {
|
2013-07-15 08:09:19 +04:00
|
|
|
cond_resched();
|
|
|
|
congestion_wait(BLK_RW_ASYNC, HZ/50);
|
|
|
|
goto retry;
|
|
|
|
}
|
|
|
|
if (err) {
|
|
|
|
ext4_std_error(inode->i_sb, err);
|
|
|
|
return;
|
|
|
|
}
|
ext4: rewrite punch hole to use ext4_ext_remove_space()
This commit rewrites ext4 punch hole implementation to use
ext4_ext_remove_space() instead of its home gown way of doing this via
ext4_ext_map_blocks(). There are several reasons for changing this.
Firstly it is quite non obvious that punching hole needs to
ext4_ext_map_blocks() to punch a hole, especially given that this
function should map blocks, not unmap it. It also required a lot of new
code in ext4_ext_map_blocks().
Secondly the design of it is not very effective. The reason is that we
are trying to punch out blocks in ext4_ext_punch_hole() in opposite
direction than in ext4_ext_rm_leaf() which causes the ext4_ext_rm_leaf()
to iterate through the whole tree from the end to the start to find the
requested extent for every extent we are going to punch out.
And finally the current implementation does not use the existing code,
but bring a lot of new code, which is IMO unnecessary since there
already is some infrastructure we can use. Specifically
ext4_ext_remove_space().
This commit changes ext4_ext_remove_space() to accept 'end' parameter so
we can not only truncate to the end of file, but also remove the space
in the middle of the file (punch a hole). Moreover, because the last
block to punch out, might be in the middle of the extent, we have to
split the extent at 'end + 1' so ext4_ext_rm_leaf() can easily either
remove the whole fist part of split extent, or change its size.
ext4_ext_remove_space() is then used to actually remove the space
(extents) from within the hole, instead of ext4_ext_map_blocks().
Note that this also fix the issue with punch hole, where we would forget
to remove empty index blocks from the extent tree, resulting in double
free block error and file system corruption. This is simply because we
now use different code path, where this problem does not exist.
This has been tested with fsx running for several days and xfstests,
plus xfstest #251 with '-o discard' run on the loop image (which
converts discard requestes into punch hole to the backing file). All of
it on 1K and 4K file system block size.
Signed-off-by: Lukas Czerner <lczerner@redhat.com>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
2012-03-20 07:03:19 +04:00
|
|
|
err = ext4_ext_remove_space(inode, last_block, EXT_MAX_BLOCKS - 1);
|
2013-07-15 08:09:19 +04:00
|
|
|
ext4_std_error(inode->i_sb, err);
|
2006-10-11 12:21:03 +04:00
|
|
|
}
|
|
|
|
|
2014-03-19 02:03:51 +04:00
|
|
|
static int ext4_alloc_file_blocks(struct file *file, ext4_lblk_t offset,
|
2014-08-28 02:40:00 +04:00
|
|
|
ext4_lblk_t len, loff_t new_size,
|
|
|
|
int flags, int mode)
|
2014-03-19 02:03:51 +04:00
|
|
|
{
|
|
|
|
struct inode *inode = file_inode(file);
|
|
|
|
handle_t *handle;
|
|
|
|
int ret = 0;
|
|
|
|
int ret2 = 0;
|
|
|
|
int retries = 0;
|
2015-06-15 07:20:46 +03:00
|
|
|
int depth = 0;
|
2014-03-19 02:03:51 +04:00
|
|
|
struct ext4_map_blocks map;
|
|
|
|
unsigned int credits;
|
2014-08-28 02:40:00 +04:00
|
|
|
loff_t epos;
|
2014-03-19 02:03:51 +04:00
|
|
|
|
|
|
|
map.m_lblk = offset;
|
2014-08-28 02:40:00 +04:00
|
|
|
map.m_len = len;
|
2014-03-19 02:03:51 +04:00
|
|
|
/*
|
|
|
|
* Don't normalize the request if it can fit in one extent so
|
|
|
|
* that it doesn't get unnecessarily split into multiple
|
|
|
|
* extents.
|
|
|
|
*/
|
2014-04-21 07:45:47 +04:00
|
|
|
if (len <= EXT_UNWRITTEN_MAX_LEN)
|
2014-03-19 02:03:51 +04:00
|
|
|
flags |= EXT4_GET_BLOCKS_NO_NORMALIZE;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* credits to insert 1 extent into extent tree
|
|
|
|
*/
|
|
|
|
credits = ext4_chunk_trans_blocks(inode, len);
|
2015-06-15 07:20:46 +03:00
|
|
|
/*
|
|
|
|
* We can only call ext_depth() on extent based inodes
|
|
|
|
*/
|
|
|
|
if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))
|
|
|
|
depth = ext_depth(inode);
|
|
|
|
else
|
|
|
|
depth = -1;
|
2014-03-19 02:03:51 +04:00
|
|
|
|
|
|
|
retry:
|
2014-08-28 02:40:00 +04:00
|
|
|
while (ret >= 0 && len) {
|
2015-06-15 07:20:46 +03:00
|
|
|
/*
|
|
|
|
* Recalculate credits when extent tree depth changes.
|
|
|
|
*/
|
|
|
|
if (depth >= 0 && depth != ext_depth(inode)) {
|
|
|
|
credits = ext4_chunk_trans_blocks(inode, len);
|
|
|
|
depth = ext_depth(inode);
|
|
|
|
}
|
|
|
|
|
2014-03-19 02:03:51 +04:00
|
|
|
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;
|
|
|
|
}
|
2014-08-28 02:40:00 +04:00
|
|
|
map.m_lblk += ret;
|
|
|
|
map.m_len = len = len - ret;
|
|
|
|
epos = (loff_t)map.m_lblk << inode->i_blkbits;
|
|
|
|
inode->i_ctime = ext4_current_time(inode);
|
|
|
|
if (new_size) {
|
|
|
|
if (epos > new_size)
|
|
|
|
epos = new_size;
|
|
|
|
if (ext4_update_inode_size(inode, epos) & 0x1)
|
|
|
|
inode->i_mtime = inode->i_ctime;
|
|
|
|
} else {
|
|
|
|
if (epos > inode->i_size)
|
|
|
|
ext4_set_inode_flag(inode,
|
|
|
|
EXT4_INODE_EOFBLOCKS);
|
|
|
|
}
|
|
|
|
ext4_mark_inode_dirty(handle, inode);
|
2014-03-19 02:03:51 +04:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2014-03-19 02:05:35 +04:00
|
|
|
static long ext4_zero_range(struct file *file, loff_t offset,
|
|
|
|
loff_t len, int mode)
|
|
|
|
{
|
|
|
|
struct inode *inode = file_inode(file);
|
|
|
|
handle_t *handle = NULL;
|
|
|
|
unsigned int max_blocks;
|
|
|
|
loff_t new_size = 0;
|
|
|
|
int ret = 0;
|
|
|
|
int flags;
|
2014-08-28 02:33:49 +04:00
|
|
|
int credits;
|
2014-08-28 02:40:00 +04:00
|
|
|
int partial_begin, partial_end;
|
2014-03-19 02:05:35 +04:00
|
|
|
loff_t start, end;
|
|
|
|
ext4_lblk_t lblk;
|
|
|
|
unsigned int blkbits = inode->i_blkbits;
|
|
|
|
|
|
|
|
trace_ext4_zero_range(inode, offset, len, mode);
|
|
|
|
|
2014-04-18 19:50:35 +04:00
|
|
|
if (!S_ISREG(inode->i_mode))
|
|
|
|
return -EINVAL;
|
|
|
|
|
2014-05-27 20:48:55 +04:00
|
|
|
/* Call ext4_force_commit to flush all data in case of data=journal. */
|
|
|
|
if (ext4_should_journal_data(inode)) {
|
|
|
|
ret = ext4_force_commit(inode->i_sb);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-03-19 02:05:35 +04:00
|
|
|
/*
|
|
|
|
* Round up offset. This is not fallocate, we neet to zero out
|
|
|
|
* blocks, so convert interior block aligned part of the range to
|
|
|
|
* unwritten and possibly manually zero out unaligned parts of the
|
|
|
|
* range.
|
|
|
|
*/
|
|
|
|
start = round_up(offset, 1 << blkbits);
|
|
|
|
end = round_down((offset + len), 1 << blkbits);
|
|
|
|
|
|
|
|
if (start < offset || end > offset + len)
|
|
|
|
return -EINVAL;
|
2014-08-28 02:40:00 +04:00
|
|
|
partial_begin = offset & ((1 << blkbits) - 1);
|
|
|
|
partial_end = (offset + len) & ((1 << blkbits) - 1);
|
2014-03-19 02:05:35 +04:00
|
|
|
|
|
|
|
lblk = start >> blkbits;
|
|
|
|
max_blocks = (end >> blkbits);
|
|
|
|
if (max_blocks < lblk)
|
|
|
|
max_blocks = 0;
|
|
|
|
else
|
|
|
|
max_blocks -= lblk;
|
|
|
|
|
2016-01-22 23:40:57 +03:00
|
|
|
inode_lock(inode);
|
2014-03-19 02:05:35 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Indirect files do not support unwritten extnets
|
|
|
|
*/
|
|
|
|
if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))) {
|
|
|
|
ret = -EOPNOTSUPP;
|
|
|
|
goto out_mutex;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(mode & FALLOC_FL_KEEP_SIZE) &&
|
|
|
|
offset + len > i_size_read(inode)) {
|
|
|
|
new_size = offset + len;
|
|
|
|
ret = inode_newsize_ok(inode, new_size);
|
|
|
|
if (ret)
|
|
|
|
goto out_mutex;
|
|
|
|
}
|
|
|
|
|
2015-04-03 07:09:13 +03:00
|
|
|
flags = EXT4_GET_BLOCKS_CREATE_UNWRIT_EXT;
|
|
|
|
if (mode & FALLOC_FL_KEEP_SIZE)
|
|
|
|
flags |= EXT4_GET_BLOCKS_KEEP_SIZE;
|
|
|
|
|
2015-12-07 22:29:17 +03:00
|
|
|
/* Wait all existing dio workers, newcomers will block on i_mutex */
|
|
|
|
ext4_inode_block_unlocked_dio(inode);
|
|
|
|
inode_dio_wait(inode);
|
|
|
|
|
2015-04-03 07:09:13 +03:00
|
|
|
/* Preallocate the range including the unaligned edges */
|
|
|
|
if (partial_begin || partial_end) {
|
|
|
|
ret = ext4_alloc_file_blocks(file,
|
|
|
|
round_down(offset, 1 << blkbits) >> blkbits,
|
|
|
|
(round_up((offset + len), 1 << blkbits) -
|
|
|
|
round_down(offset, 1 << blkbits)) >> blkbits,
|
|
|
|
new_size, flags, mode);
|
|
|
|
if (ret)
|
2015-12-07 22:29:17 +03:00
|
|
|
goto out_dio;
|
2015-04-03 07:09:13 +03:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Zero range excluding the unaligned edges */
|
2014-03-19 02:05:35 +04:00
|
|
|
if (max_blocks > 0) {
|
2015-04-03 07:09:13 +03:00
|
|
|
flags |= (EXT4_GET_BLOCKS_CONVERT_UNWRITTEN |
|
|
|
|
EXT4_EX_NOCACHE);
|
2014-03-19 02:05:35 +04:00
|
|
|
|
2015-12-07 22:28:03 +03:00
|
|
|
/*
|
|
|
|
* Prevent page faults from reinstantiating pages we have
|
|
|
|
* released from page cache.
|
|
|
|
*/
|
|
|
|
down_write(&EXT4_I(inode)->i_mmap_sem);
|
2015-12-07 22:34:49 +03:00
|
|
|
ret = ext4_update_disksize_before_punch(inode, offset, len);
|
|
|
|
if (ret) {
|
|
|
|
up_write(&EXT4_I(inode)->i_mmap_sem);
|
|
|
|
goto out_dio;
|
|
|
|
}
|
2015-12-07 22:28:03 +03:00
|
|
|
/* Now release the pages and zero block aligned part of pages */
|
|
|
|
truncate_pagecache_range(inode, start, end - 1);
|
|
|
|
inode->i_mtime = inode->i_ctime = ext4_current_time(inode);
|
|
|
|
|
2014-09-01 22:32:09 +04:00
|
|
|
ret = ext4_alloc_file_blocks(file, lblk, max_blocks, new_size,
|
|
|
|
flags, mode);
|
2015-12-07 22:28:03 +03:00
|
|
|
up_write(&EXT4_I(inode)->i_mmap_sem);
|
2014-09-01 22:32:09 +04:00
|
|
|
if (ret)
|
|
|
|
goto out_dio;
|
2014-03-19 02:05:35 +04:00
|
|
|
}
|
2014-08-28 02:40:00 +04:00
|
|
|
if (!partial_begin && !partial_end)
|
|
|
|
goto out_dio;
|
|
|
|
|
2014-08-28 02:33:49 +04:00
|
|
|
/*
|
|
|
|
* In worst case we have to writeout two nonadjacent unwritten
|
|
|
|
* blocks and update the inode
|
|
|
|
*/
|
|
|
|
credits = (2 * ext4_ext_index_trans_blocks(inode, 2)) + 1;
|
|
|
|
if (ext4_should_journal_data(inode))
|
|
|
|
credits += 2;
|
|
|
|
handle = ext4_journal_start(inode, EXT4_HT_MISC, credits);
|
2014-03-19 02:05:35 +04:00
|
|
|
if (IS_ERR(handle)) {
|
|
|
|
ret = PTR_ERR(handle);
|
|
|
|
ext4_std_error(inode->i_sb, ret);
|
|
|
|
goto out_dio;
|
|
|
|
}
|
|
|
|
|
|
|
|
inode->i_mtime = inode->i_ctime = ext4_current_time(inode);
|
2014-04-01 08:59:21 +04:00
|
|
|
if (new_size) {
|
2014-08-24 01:48:28 +04:00
|
|
|
ext4_update_inode_size(inode, new_size);
|
2014-04-01 08:59:21 +04:00
|
|
|
} else {
|
2014-03-19 02:05:35 +04:00
|
|
|
/*
|
|
|
|
* Mark that we allocate beyond EOF so the subsequent truncate
|
|
|
|
* can proceed even if the new size is the same as i_size.
|
|
|
|
*/
|
|
|
|
if ((offset + len) > i_size_read(inode))
|
|
|
|
ext4_set_inode_flag(inode, EXT4_INODE_EOFBLOCKS);
|
|
|
|
}
|
|
|
|
ext4_mark_inode_dirty(handle, inode);
|
|
|
|
|
|
|
|
/* Zero out partial block at the edges of the range */
|
|
|
|
ret = ext4_zero_partial_blocks(handle, inode, offset, len);
|
|
|
|
|
|
|
|
if (file->f_flags & O_SYNC)
|
|
|
|
ext4_handle_sync(handle);
|
|
|
|
|
|
|
|
ext4_journal_stop(handle);
|
|
|
|
out_dio:
|
|
|
|
ext4_inode_resume_unlocked_dio(inode);
|
|
|
|
out_mutex:
|
2016-01-22 23:40:57 +03:00
|
|
|
inode_unlock(inode);
|
2014-03-19 02:05:35 +04:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2007-07-18 05:42:41 +04:00
|
|
|
/*
|
2011-01-14 15:07:43 +03:00
|
|
|
* preallocate space for a file. This implements ext4's fallocate file
|
2007-07-18 05:42:41 +04:00
|
|
|
* operation, which gets called from sys_fallocate system call.
|
|
|
|
* For block-mapped files, posix_fallocate should fall back to the method
|
|
|
|
* of writing zeroes to the required new blocks (the same behavior which is
|
|
|
|
* expected for file systems which do not support fallocate() system call).
|
|
|
|
*/
|
2011-01-14 15:07:43 +03:00
|
|
|
long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
|
2007-07-18 05:42:41 +04:00
|
|
|
{
|
2013-01-24 02:07:38 +04:00
|
|
|
struct inode *inode = file_inode(file);
|
2014-03-19 01:44:35 +04:00
|
|
|
loff_t new_size = 0;
|
2008-11-05 08:14:04 +03:00
|
|
|
unsigned int max_blocks;
|
2007-07-18 05:42:41 +04:00
|
|
|
int ret = 0;
|
2011-10-25 16:15:12 +04:00
|
|
|
int flags;
|
2014-03-19 02:03:51 +04:00
|
|
|
ext4_lblk_t lblk;
|
|
|
|
unsigned int blkbits = inode->i_blkbits;
|
2007-07-18 05:42:41 +04:00
|
|
|
|
2015-04-12 07:55:10 +03:00
|
|
|
/*
|
|
|
|
* Encrypted inodes can't handle collapse range or insert
|
|
|
|
* range since we would need to re-encrypt blocks with a
|
|
|
|
* different IV or XTS tweak (which are based on the logical
|
|
|
|
* block number).
|
|
|
|
*
|
|
|
|
* XXX It's not clear why zero range isn't working, but we'll
|
|
|
|
* leave it disabled for encrypted inodes for now. This is a
|
|
|
|
* bug we should fix....
|
|
|
|
*/
|
|
|
|
if (ext4_encrypted_inode(inode) &&
|
2015-06-09 08:55:03 +03:00
|
|
|
(mode & (FALLOC_FL_COLLAPSE_RANGE | FALLOC_FL_INSERT_RANGE |
|
|
|
|
FALLOC_FL_ZERO_RANGE)))
|
2015-04-12 07:55:10 +03:00
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
2011-05-25 15:41:50 +04:00
|
|
|
/* Return error if mode is not supported */
|
2014-02-24 00:18:59 +04:00
|
|
|
if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE |
|
2015-06-09 08:55:03 +03:00
|
|
|
FALLOC_FL_COLLAPSE_RANGE | FALLOC_FL_ZERO_RANGE |
|
|
|
|
FALLOC_FL_INSERT_RANGE))
|
2011-05-25 15:41:50 +04:00
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
if (mode & FALLOC_FL_PUNCH_HOLE)
|
2013-07-01 16:12:38 +04:00
|
|
|
return ext4_punch_hole(inode, offset, len);
|
2011-05-25 15:41:50 +04:00
|
|
|
|
2012-12-10 23:06:03 +04:00
|
|
|
ret = ext4_convert_inline_data(inode);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
2014-04-13 06:53:53 +04:00
|
|
|
if (mode & FALLOC_FL_COLLAPSE_RANGE)
|
|
|
|
return ext4_collapse_range(inode, offset, len);
|
|
|
|
|
2015-06-09 08:55:03 +03:00
|
|
|
if (mode & FALLOC_FL_INSERT_RANGE)
|
|
|
|
return ext4_insert_range(inode, offset, len);
|
|
|
|
|
2014-03-19 02:05:35 +04:00
|
|
|
if (mode & FALLOC_FL_ZERO_RANGE)
|
|
|
|
return ext4_zero_range(file, offset, len, mode);
|
|
|
|
|
2011-03-22 04:38:05 +03:00
|
|
|
trace_ext4_fallocate_enter(inode, offset, len, mode);
|
2014-03-19 02:03:51 +04:00
|
|
|
lblk = offset >> blkbits;
|
2008-04-29 16:11:12 +04:00
|
|
|
/*
|
|
|
|
* We can't just convert len to max_blocks because
|
|
|
|
* If blocksize = 4096 offset = 3072 and len = 2048
|
|
|
|
*/
|
2007-07-18 05:42:41 +04:00
|
|
|
max_blocks = (EXT4_BLOCK_ALIGN(len + offset, blkbits) >> blkbits)
|
2014-03-19 02:03:51 +04:00
|
|
|
- lblk;
|
|
|
|
|
2014-04-21 07:45:47 +04:00
|
|
|
flags = EXT4_GET_BLOCKS_CREATE_UNWRIT_EXT;
|
2014-03-19 02:03:51 +04:00
|
|
|
if (mode & FALLOC_FL_KEEP_SIZE)
|
|
|
|
flags |= EXT4_GET_BLOCKS_KEEP_SIZE;
|
|
|
|
|
2016-01-22 23:40:57 +03:00
|
|
|
inode_lock(inode);
|
2014-03-19 01:44:35 +04:00
|
|
|
|
2015-05-03 06:21:15 +03:00
|
|
|
/*
|
|
|
|
* We only support preallocation for extent-based files only
|
|
|
|
*/
|
|
|
|
if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))) {
|
|
|
|
ret = -EOPNOTSUPP;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2014-03-19 01:44:35 +04:00
|
|
|
if (!(mode & FALLOC_FL_KEEP_SIZE) &&
|
|
|
|
offset + len > i_size_read(inode)) {
|
|
|
|
new_size = offset + len;
|
|
|
|
ret = inode_newsize_ok(inode, new_size);
|
|
|
|
if (ret)
|
|
|
|
goto out;
|
2010-05-16 22:00:00 +04:00
|
|
|
}
|
2014-03-19 01:44:35 +04:00
|
|
|
|
2015-12-07 22:29:17 +03:00
|
|
|
/* Wait all existing dio workers, newcomers will block on i_mutex */
|
|
|
|
ext4_inode_block_unlocked_dio(inode);
|
|
|
|
inode_dio_wait(inode);
|
|
|
|
|
2014-08-28 02:40:00 +04:00
|
|
|
ret = ext4_alloc_file_blocks(file, lblk, max_blocks, new_size,
|
|
|
|
flags, mode);
|
2015-12-07 22:29:17 +03:00
|
|
|
ext4_inode_resume_unlocked_dio(inode);
|
2014-03-19 02:03:51 +04:00
|
|
|
if (ret)
|
|
|
|
goto out;
|
2014-03-19 01:44:35 +04:00
|
|
|
|
2014-08-28 02:40:00 +04:00
|
|
|
if (file->f_flags & O_SYNC && EXT4_SB(inode->i_sb)->s_journal) {
|
|
|
|
ret = jbd2_complete_transaction(EXT4_SB(inode->i_sb)->s_journal,
|
|
|
|
EXT4_I(inode)->i_sync_tid);
|
2014-03-19 01:44:35 +04:00
|
|
|
}
|
|
|
|
out:
|
2016-01-22 23:40:57 +03:00
|
|
|
inode_unlock(inode);
|
2014-03-19 02:03:51 +04:00
|
|
|
trace_ext4_fallocate_exit(inode, offset, max_blocks, ret);
|
|
|
|
return ret;
|
2007-07-18 05:42:41 +04:00
|
|
|
}
|
2008-10-07 08:46:36 +04:00
|
|
|
|
2009-09-28 23:49:08 +04:00
|
|
|
/*
|
|
|
|
* This function convert a range of blocks to written extents
|
|
|
|
* The caller of this function will pass the start offset and the size.
|
|
|
|
* all unwritten extents within this range will be converted to
|
|
|
|
* written extents.
|
|
|
|
*
|
|
|
|
* This function is called from the direct IO end io call back
|
|
|
|
* function, to convert the fallocated extents after IO is completed.
|
2009-11-10 18:48:08 +03:00
|
|
|
* Returns 0 on success.
|
2009-09-28 23:49:08 +04:00
|
|
|
*/
|
2013-06-04 21:21:11 +04:00
|
|
|
int ext4_convert_unwritten_extents(handle_t *handle, struct inode *inode,
|
|
|
|
loff_t offset, ssize_t len)
|
2009-09-28 23:49:08 +04:00
|
|
|
{
|
|
|
|
unsigned int max_blocks;
|
|
|
|
int ret = 0;
|
|
|
|
int ret2 = 0;
|
2010-05-17 04:00:00 +04:00
|
|
|
struct ext4_map_blocks map;
|
2009-09-28 23:49:08 +04:00
|
|
|
unsigned int credits, blkbits = inode->i_blkbits;
|
|
|
|
|
2010-05-17 04:00:00 +04:00
|
|
|
map.m_lblk = offset >> blkbits;
|
2009-09-28 23:49:08 +04:00
|
|
|
/*
|
|
|
|
* We can't just convert len to max_blocks because
|
|
|
|
* If blocksize = 4096 offset = 3072 and len = 2048
|
|
|
|
*/
|
2010-05-17 04:00:00 +04:00
|
|
|
max_blocks = ((EXT4_BLOCK_ALIGN(len + offset, blkbits) >> blkbits) -
|
|
|
|
map.m_lblk);
|
2009-09-28 23:49:08 +04:00
|
|
|
/*
|
2013-06-04 21:21:11 +04:00
|
|
|
* This is somewhat ugly but the idea is clear: When transaction is
|
|
|
|
* reserved, everything goes into it. Otherwise we rather start several
|
|
|
|
* smaller transactions for conversion of each extent separately.
|
2009-09-28 23:49:08 +04:00
|
|
|
*/
|
2013-06-04 21:21:11 +04:00
|
|
|
if (handle) {
|
|
|
|
handle = ext4_journal_start_reserved(handle,
|
|
|
|
EXT4_HT_EXT_CONVERT);
|
|
|
|
if (IS_ERR(handle))
|
|
|
|
return PTR_ERR(handle);
|
|
|
|
credits = 0;
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* credits to insert 1 extent into extent tree
|
|
|
|
*/
|
|
|
|
credits = ext4_chunk_trans_blocks(inode, max_blocks);
|
|
|
|
}
|
2009-09-28 23:49:08 +04:00
|
|
|
while (ret >= 0 && ret < max_blocks) {
|
2010-05-17 04:00:00 +04:00
|
|
|
map.m_lblk += ret;
|
|
|
|
map.m_len = (max_blocks -= ret);
|
2013-06-04 21:21:11 +04:00
|
|
|
if (credits) {
|
|
|
|
handle = ext4_journal_start(inode, EXT4_HT_MAP_BLOCKS,
|
|
|
|
credits);
|
|
|
|
if (IS_ERR(handle)) {
|
|
|
|
ret = PTR_ERR(handle);
|
|
|
|
break;
|
|
|
|
}
|
2009-09-28 23:49:08 +04:00
|
|
|
}
|
2010-05-17 04:00:00 +04:00
|
|
|
ret = ext4_map_blocks(handle, inode, &map,
|
2010-03-02 21:28:44 +03:00
|
|
|
EXT4_GET_BLOCKS_IO_CONVERT_EXT);
|
2013-01-29 06:21:12 +04:00
|
|
|
if (ret <= 0)
|
|
|
|
ext4_warning(inode->i_sb,
|
|
|
|
"inode #%lu: block %u: len %u: "
|
|
|
|
"ext4_ext_map_blocks returned %d",
|
|
|
|
inode->i_ino, map.m_lblk,
|
|
|
|
map.m_len, ret);
|
2009-09-28 23:49:08 +04:00
|
|
|
ext4_mark_inode_dirty(handle, inode);
|
2013-06-04 21:21:11 +04:00
|
|
|
if (credits)
|
|
|
|
ret2 = ext4_journal_stop(handle);
|
|
|
|
if (ret <= 0 || ret2)
|
2009-09-28 23:49:08 +04:00
|
|
|
break;
|
|
|
|
}
|
2013-06-04 21:21:11 +04:00
|
|
|
if (!credits)
|
|
|
|
ret2 = ext4_journal_stop(handle);
|
2009-09-28 23:49:08 +04:00
|
|
|
return ret > 0 ? ret2 : ret;
|
|
|
|
}
|
2011-02-28 01:25:47 +03:00
|
|
|
|
2008-10-07 08:46:36 +04:00
|
|
|
/*
|
2013-02-18 09:31:07 +04:00
|
|
|
* If newes is not existing extent (newes->ec_pblk equals zero) find
|
|
|
|
* delayed extent at start of newes and update newes accordingly and
|
2012-11-28 21:32:26 +04:00
|
|
|
* return start of the next delayed extent.
|
|
|
|
*
|
2013-02-18 09:31:07 +04:00
|
|
|
* If newes is existing extent (newes->ec_pblk is not equal zero)
|
2012-11-28 21:32:26 +04:00
|
|
|
* return start of next delayed extent or EXT_MAX_BLOCKS if no delayed
|
2013-02-18 09:31:07 +04:00
|
|
|
* extent found. Leave newes unmodified.
|
2008-10-07 08:46:36 +04:00
|
|
|
*/
|
2012-11-28 21:32:26 +04:00
|
|
|
static int ext4_find_delayed_extent(struct inode *inode,
|
2013-02-18 09:31:07 +04:00
|
|
|
struct extent_status *newes)
|
2008-10-07 08:46:36 +04:00
|
|
|
{
|
2012-11-09 06:57:37 +04:00
|
|
|
struct extent_status es;
|
2013-02-18 09:27:26 +04:00
|
|
|
ext4_lblk_t block, next_del;
|
2008-10-07 08:46:36 +04:00
|
|
|
|
2013-02-18 09:31:07 +04:00
|
|
|
if (newes->es_pblk == 0) {
|
2013-05-03 10:15:52 +04:00
|
|
|
ext4_es_find_delayed_extent_range(inode, newes->es_lblk,
|
|
|
|
newes->es_lblk + newes->es_len - 1, &es);
|
|
|
|
|
2011-02-28 01:25:47 +03:00
|
|
|
/*
|
2013-02-18 09:31:07 +04:00
|
|
|
* No extent in extent-tree contains block @newes->es_pblk,
|
2011-02-28 01:25:47 +03:00
|
|
|
* then the block may stay in 1)a hole or 2)delayed-extent.
|
|
|
|
*/
|
2013-02-18 09:26:51 +04:00
|
|
|
if (es.es_len == 0)
|
2012-11-09 06:57:37 +04:00
|
|
|
/* A hole found. */
|
2012-11-28 21:32:26 +04:00
|
|
|
return 0;
|
2012-11-09 06:57:37 +04:00
|
|
|
|
2013-02-18 09:31:07 +04:00
|
|
|
if (es.es_lblk > newes->es_lblk) {
|
2012-11-09 06:57:37 +04:00
|
|
|
/* A hole found. */
|
2013-02-18 09:31:07 +04:00
|
|
|
newes->es_len = min(es.es_lblk - newes->es_lblk,
|
|
|
|
newes->es_len);
|
2012-11-28 21:32:26 +04:00
|
|
|
return 0;
|
2008-10-07 08:46:36 +04:00
|
|
|
}
|
2011-02-28 01:25:47 +03:00
|
|
|
|
2013-02-18 09:31:07 +04:00
|
|
|
newes->es_len = es.es_lblk + es.es_len - newes->es_lblk;
|
2008-10-07 08:46:36 +04:00
|
|
|
}
|
|
|
|
|
2013-02-18 09:31:07 +04:00
|
|
|
block = newes->es_lblk + newes->es_len;
|
2013-05-03 10:15:52 +04:00
|
|
|
ext4_es_find_delayed_extent_range(inode, block, EXT_MAX_BLOCKS, &es);
|
2013-02-18 09:27:26 +04:00
|
|
|
if (es.es_len == 0)
|
|
|
|
next_del = EXT_MAX_BLOCKS;
|
|
|
|
else
|
|
|
|
next_del = es.es_lblk;
|
|
|
|
|
2012-11-28 21:32:26 +04:00
|
|
|
return next_del;
|
2008-10-07 08:46:36 +04:00
|
|
|
}
|
|
|
|
/* fiemap flags we can handle specified here */
|
|
|
|
#define EXT4_FIEMAP_FLAGS (FIEMAP_FLAG_SYNC|FIEMAP_FLAG_XATTR)
|
|
|
|
|
2008-11-22 23:04:59 +03:00
|
|
|
static int ext4_xattr_fiemap(struct inode *inode,
|
|
|
|
struct fiemap_extent_info *fieinfo)
|
2008-10-07 08:46:36 +04:00
|
|
|
{
|
|
|
|
__u64 physical = 0;
|
|
|
|
__u64 length;
|
|
|
|
__u32 flags = FIEMAP_EXTENT_LAST;
|
|
|
|
int blockbits = inode->i_sb->s_blocksize_bits;
|
|
|
|
int error = 0;
|
|
|
|
|
|
|
|
/* in-inode? */
|
2010-01-24 22:34:07 +03:00
|
|
|
if (ext4_test_inode_state(inode, EXT4_STATE_XATTR)) {
|
2008-10-07 08:46:36 +04:00
|
|
|
struct ext4_iloc iloc;
|
|
|
|
int offset; /* offset of xattr in inode */
|
|
|
|
|
|
|
|
error = ext4_get_inode_loc(inode, &iloc);
|
|
|
|
if (error)
|
|
|
|
return error;
|
2013-06-01 03:38:56 +04:00
|
|
|
physical = (__u64)iloc.bh->b_blocknr << blockbits;
|
2008-10-07 08:46:36 +04:00
|
|
|
offset = EXT4_GOOD_OLD_INODE_SIZE +
|
|
|
|
EXT4_I(inode)->i_extra_isize;
|
|
|
|
physical += offset;
|
|
|
|
length = EXT4_SB(inode->i_sb)->s_inode_size - offset;
|
|
|
|
flags |= FIEMAP_EXTENT_DATA_INLINE;
|
2010-04-04 01:44:16 +04:00
|
|
|
brelse(iloc.bh);
|
2008-10-07 08:46:36 +04:00
|
|
|
} else { /* external block */
|
2013-06-01 03:38:56 +04:00
|
|
|
physical = (__u64)EXT4_I(inode)->i_file_acl << blockbits;
|
2008-10-07 08:46:36 +04:00
|
|
|
length = inode->i_sb->s_blocksize;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (physical)
|
|
|
|
error = fiemap_fill_next_extent(fieinfo, 0, physical,
|
|
|
|
length, flags);
|
|
|
|
return (error < 0 ? error : 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
int ext4_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
|
|
|
|
__u64 start, __u64 len)
|
|
|
|
{
|
|
|
|
ext4_lblk_t start_blk;
|
|
|
|
int error = 0;
|
|
|
|
|
2012-12-10 23:06:02 +04:00
|
|
|
if (ext4_has_inline_data(inode)) {
|
|
|
|
int has_inline = 1;
|
|
|
|
|
2014-12-03 00:11:20 +03:00
|
|
|
error = ext4_inline_data_fiemap(inode, fieinfo, &has_inline,
|
|
|
|
start, len);
|
2012-12-10 23:06:02 +04:00
|
|
|
|
|
|
|
if (has_inline)
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
2013-08-17 06:05:14 +04:00
|
|
|
if (fieinfo->fi_flags & FIEMAP_FLAG_CACHE) {
|
|
|
|
error = ext4_ext_precache(inode);
|
|
|
|
if (error)
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
2008-10-07 08:46:36 +04:00
|
|
|
/* fallback to generic here if not in extents fmt */
|
2010-05-17 06:00:00 +04:00
|
|
|
if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)))
|
2015-01-02 23:16:00 +03:00
|
|
|
return generic_block_fiemap(inode, fieinfo, start, len,
|
|
|
|
ext4_get_block);
|
2008-10-07 08:46:36 +04:00
|
|
|
|
|
|
|
if (fiemap_check_flags(fieinfo, EXT4_FIEMAP_FLAGS))
|
|
|
|
return -EBADR;
|
|
|
|
|
|
|
|
if (fieinfo->fi_flags & FIEMAP_FLAG_XATTR) {
|
|
|
|
error = ext4_xattr_fiemap(inode, fieinfo);
|
|
|
|
} else {
|
2010-03-05 01:07:28 +03:00
|
|
|
ext4_lblk_t len_blks;
|
|
|
|
__u64 last_blk;
|
|
|
|
|
2008-10-07 08:46:36 +04:00
|
|
|
start_blk = start >> inode->i_sb->s_blocksize_bits;
|
2010-03-05 01:07:28 +03:00
|
|
|
last_blk = (start + len - 1) >> inode->i_sb->s_blocksize_bits;
|
2011-06-06 08:05:17 +04:00
|
|
|
if (last_blk >= EXT_MAX_BLOCKS)
|
|
|
|
last_blk = EXT_MAX_BLOCKS-1;
|
2010-03-05 01:07:28 +03:00
|
|
|
len_blks = ((ext4_lblk_t) last_blk) - start_blk + 1;
|
2008-10-07 08:46:36 +04:00
|
|
|
|
|
|
|
/*
|
2012-11-28 21:32:26 +04:00
|
|
|
* Walk the extent tree gathering extent information
|
|
|
|
* and pushing extents back to the user.
|
2008-10-07 08:46:36 +04:00
|
|
|
*/
|
2012-11-28 21:32:26 +04:00
|
|
|
error = ext4_fill_fiemap_extents(inode, start_blk,
|
|
|
|
len_blks, fieinfo);
|
2008-10-07 08:46:36 +04:00
|
|
|
}
|
|
|
|
return error;
|
|
|
|
}
|
2014-02-24 00:18:59 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* ext4_access_path:
|
|
|
|
* Function to access the path buffer for marking it dirty.
|
|
|
|
* It also checks if there are sufficient credits left in the journal handle
|
|
|
|
* to update path.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
ext4_access_path(handle_t *handle, struct inode *inode,
|
|
|
|
struct ext4_ext_path *path)
|
|
|
|
{
|
|
|
|
int credits, err;
|
|
|
|
|
|
|
|
if (!ext4_handle_valid(handle))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check if need to extend journal credits
|
|
|
|
* 3 for leaf, sb, and inode plus 2 (bmap and group
|
|
|
|
* descriptor) for each block group; assume two block
|
|
|
|
* groups
|
|
|
|
*/
|
|
|
|
if (handle->h_buffer_credits < 7) {
|
|
|
|
credits = ext4_writepage_trans_blocks(inode);
|
|
|
|
err = ext4_ext_truncate_extend_restart(handle, inode, credits);
|
|
|
|
/* EAGAIN is success */
|
|
|
|
if (err && err != -EAGAIN)
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = ext4_ext_get_access(handle, inode, path);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* ext4_ext_shift_path_extents:
|
|
|
|
* Shift the extents of a path structure lying between path[depth].p_ext
|
2015-06-09 08:55:03 +03:00
|
|
|
* and EXT_LAST_EXTENT(path[depth].p_hdr), by @shift blocks. @SHIFT tells
|
|
|
|
* if it is right shift or left shift operation.
|
2014-02-24 00:18:59 +04:00
|
|
|
*/
|
|
|
|
static int
|
|
|
|
ext4_ext_shift_path_extents(struct ext4_ext_path *path, ext4_lblk_t shift,
|
|
|
|
struct inode *inode, handle_t *handle,
|
2015-06-09 08:55:03 +03:00
|
|
|
enum SHIFT_DIRECTION SHIFT)
|
2014-02-24 00:18:59 +04:00
|
|
|
{
|
|
|
|
int depth, err = 0;
|
|
|
|
struct ext4_extent *ex_start, *ex_last;
|
|
|
|
bool update = 0;
|
|
|
|
depth = path->p_depth;
|
|
|
|
|
|
|
|
while (depth >= 0) {
|
|
|
|
if (depth == path->p_depth) {
|
|
|
|
ex_start = path[depth].p_ext;
|
|
|
|
if (!ex_start)
|
2015-10-17 23:16:04 +03:00
|
|
|
return -EFSCORRUPTED;
|
2014-02-24 00:18:59 +04:00
|
|
|
|
|
|
|
ex_last = EXT_LAST_EXTENT(path[depth].p_hdr);
|
|
|
|
|
|
|
|
err = ext4_access_path(handle, inode, path + depth);
|
|
|
|
if (err)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
if (ex_start == EXT_FIRST_EXTENT(path[depth].p_hdr))
|
|
|
|
update = 1;
|
|
|
|
|
|
|
|
while (ex_start <= ex_last) {
|
2015-06-09 08:55:03 +03:00
|
|
|
if (SHIFT == SHIFT_LEFT) {
|
|
|
|
le32_add_cpu(&ex_start->ee_block,
|
|
|
|
-shift);
|
|
|
|
/* Try to merge to the left. */
|
|
|
|
if ((ex_start >
|
|
|
|
EXT_FIRST_EXTENT(path[depth].p_hdr))
|
|
|
|
&&
|
|
|
|
ext4_ext_try_to_merge_right(inode,
|
|
|
|
path, ex_start - 1))
|
|
|
|
ex_last--;
|
|
|
|
else
|
|
|
|
ex_start++;
|
|
|
|
} else {
|
|
|
|
le32_add_cpu(&ex_last->ee_block, shift);
|
|
|
|
ext4_ext_try_to_merge_right(inode, path,
|
|
|
|
ex_last);
|
2014-04-18 18:55:24 +04:00
|
|
|
ex_last--;
|
2015-06-09 08:55:03 +03:00
|
|
|
}
|
2014-02-24 00:18:59 +04:00
|
|
|
}
|
|
|
|
err = ext4_ext_dirty(handle, inode, path + depth);
|
|
|
|
if (err)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
if (--depth < 0 || !update)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Update index too */
|
|
|
|
err = ext4_access_path(handle, inode, path + depth);
|
|
|
|
if (err)
|
|
|
|
goto out;
|
|
|
|
|
2015-06-09 08:55:03 +03:00
|
|
|
if (SHIFT == SHIFT_LEFT)
|
|
|
|
le32_add_cpu(&path[depth].p_idx->ei_block, -shift);
|
|
|
|
else
|
|
|
|
le32_add_cpu(&path[depth].p_idx->ei_block, shift);
|
2014-02-24 00:18:59 +04:00
|
|
|
err = ext4_ext_dirty(handle, inode, path + depth);
|
|
|
|
if (err)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
/* we are done if current index is not a starting index */
|
|
|
|
if (path[depth].p_idx != EXT_FIRST_INDEX(path[depth].p_hdr))
|
|
|
|
break;
|
|
|
|
|
|
|
|
depth--;
|
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* ext4_ext_shift_extents:
|
2015-06-09 08:55:03 +03:00
|
|
|
* All the extents which lies in the range from @start to the last allocated
|
|
|
|
* block for the @inode are shifted either towards left or right (depending
|
|
|
|
* upon @SHIFT) by @shift blocks.
|
2014-02-24 00:18:59 +04:00
|
|
|
* On success, 0 is returned, error otherwise.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
ext4_ext_shift_extents(struct inode *inode, handle_t *handle,
|
2015-06-09 08:55:03 +03:00
|
|
|
ext4_lblk_t start, ext4_lblk_t shift,
|
|
|
|
enum SHIFT_DIRECTION SHIFT)
|
2014-02-24 00:18:59 +04:00
|
|
|
{
|
|
|
|
struct ext4_ext_path *path;
|
|
|
|
int ret = 0, depth;
|
|
|
|
struct ext4_extent *extent;
|
2015-06-09 08:55:03 +03:00
|
|
|
ext4_lblk_t stop, *iterator, ex_start, ex_end;
|
2014-02-24 00:18:59 +04:00
|
|
|
|
|
|
|
/* Let path point to the last extent */
|
2014-09-01 22:43:09 +04:00
|
|
|
path = ext4_find_extent(inode, EXT_MAX_BLOCKS - 1, NULL, 0);
|
2014-02-24 00:18:59 +04:00
|
|
|
if (IS_ERR(path))
|
|
|
|
return PTR_ERR(path);
|
|
|
|
|
|
|
|
depth = path->p_depth;
|
|
|
|
extent = path[depth].p_ext;
|
2014-09-01 22:41:09 +04:00
|
|
|
if (!extent)
|
|
|
|
goto out;
|
2014-02-24 00:18:59 +04:00
|
|
|
|
2015-06-09 08:55:03 +03:00
|
|
|
stop = le32_to_cpu(extent->ee_block) +
|
2014-04-12 20:45:55 +04:00
|
|
|
ext4_ext_get_actual_len(extent);
|
2014-02-24 00:18:59 +04:00
|
|
|
|
2015-06-09 08:55:03 +03:00
|
|
|
/*
|
|
|
|
* In case of left shift, Don't start shifting extents until we make
|
|
|
|
* sure the hole is big enough to accommodate the shift.
|
|
|
|
*/
|
|
|
|
if (SHIFT == SHIFT_LEFT) {
|
|
|
|
path = ext4_find_extent(inode, start - 1, &path, 0);
|
|
|
|
if (IS_ERR(path))
|
|
|
|
return PTR_ERR(path);
|
|
|
|
depth = path->p_depth;
|
|
|
|
extent = path[depth].p_ext;
|
|
|
|
if (extent) {
|
|
|
|
ex_start = le32_to_cpu(extent->ee_block);
|
|
|
|
ex_end = le32_to_cpu(extent->ee_block) +
|
|
|
|
ext4_ext_get_actual_len(extent);
|
|
|
|
} else {
|
|
|
|
ex_start = 0;
|
|
|
|
ex_end = 0;
|
|
|
|
}
|
2014-02-24 00:18:59 +04:00
|
|
|
|
2015-06-09 08:55:03 +03:00
|
|
|
if ((start == ex_start && shift > ex_start) ||
|
|
|
|
(shift > start - ex_end)) {
|
|
|
|
ext4_ext_drop_refs(path);
|
|
|
|
kfree(path);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
2014-04-13 23:05:42 +04:00
|
|
|
}
|
2014-02-24 00:18:59 +04:00
|
|
|
|
2015-06-09 08:55:03 +03:00
|
|
|
/*
|
|
|
|
* In case of left shift, iterator points to start and it is increased
|
|
|
|
* till we reach stop. In case of right shift, iterator points to stop
|
|
|
|
* and it is decreased till we reach start.
|
|
|
|
*/
|
|
|
|
if (SHIFT == SHIFT_LEFT)
|
|
|
|
iterator = &start;
|
|
|
|
else
|
|
|
|
iterator = &stop;
|
2014-02-24 00:18:59 +04:00
|
|
|
|
|
|
|
/* Its safe to start updating extents */
|
2015-06-09 08:55:03 +03:00
|
|
|
while (start < stop) {
|
|
|
|
path = ext4_find_extent(inode, *iterator, &path, 0);
|
2014-02-24 00:18:59 +04:00
|
|
|
if (IS_ERR(path))
|
|
|
|
return PTR_ERR(path);
|
|
|
|
depth = path->p_depth;
|
|
|
|
extent = path[depth].p_ext;
|
2014-04-13 23:41:13 +04:00
|
|
|
if (!extent) {
|
|
|
|
EXT4_ERROR_INODE(inode, "unexpected hole at %lu",
|
2015-06-09 08:55:03 +03:00
|
|
|
(unsigned long) *iterator);
|
2015-10-17 23:16:04 +03:00
|
|
|
return -EFSCORRUPTED;
|
2014-04-13 23:41:13 +04:00
|
|
|
}
|
2015-06-09 08:55:03 +03:00
|
|
|
if (SHIFT == SHIFT_LEFT && *iterator >
|
|
|
|
le32_to_cpu(extent->ee_block)) {
|
2014-02-24 00:18:59 +04:00
|
|
|
/* Hole, move to the next extent */
|
2014-08-31 07:50:56 +04:00
|
|
|
if (extent < EXT_LAST_EXTENT(path[depth].p_hdr)) {
|
|
|
|
path[depth].p_ext++;
|
|
|
|
} else {
|
2015-06-09 08:55:03 +03:00
|
|
|
*iterator = ext4_ext_next_allocated_block(path);
|
2014-08-31 07:50:56 +04:00
|
|
|
continue;
|
2014-02-24 00:18:59 +04:00
|
|
|
}
|
|
|
|
}
|
2015-06-09 08:55:03 +03:00
|
|
|
|
|
|
|
if (SHIFT == SHIFT_LEFT) {
|
|
|
|
extent = EXT_LAST_EXTENT(path[depth].p_hdr);
|
|
|
|
*iterator = le32_to_cpu(extent->ee_block) +
|
|
|
|
ext4_ext_get_actual_len(extent);
|
|
|
|
} else {
|
|
|
|
extent = EXT_FIRST_EXTENT(path[depth].p_hdr);
|
|
|
|
*iterator = le32_to_cpu(extent->ee_block) > 0 ?
|
|
|
|
le32_to_cpu(extent->ee_block) - 1 : 0;
|
|
|
|
/* Update path extent in case we need to stop */
|
|
|
|
while (le32_to_cpu(extent->ee_block) < start)
|
|
|
|
extent++;
|
|
|
|
path[depth].p_ext = extent;
|
|
|
|
}
|
2014-02-24 00:18:59 +04:00
|
|
|
ret = ext4_ext_shift_path_extents(path, shift, inode,
|
2015-06-09 08:55:03 +03:00
|
|
|
handle, SHIFT);
|
2014-02-24 00:18:59 +04:00
|
|
|
if (ret)
|
|
|
|
break;
|
|
|
|
}
|
2014-09-01 22:41:09 +04:00
|
|
|
out:
|
|
|
|
ext4_ext_drop_refs(path);
|
|
|
|
kfree(path);
|
2014-02-24 00:18:59 +04:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* ext4_collapse_range:
|
|
|
|
* This implements the fallocate's collapse range functionality for ext4
|
|
|
|
* Returns: 0 and non-zero on error.
|
|
|
|
*/
|
|
|
|
int ext4_collapse_range(struct inode *inode, loff_t offset, loff_t len)
|
|
|
|
{
|
|
|
|
struct super_block *sb = inode->i_sb;
|
|
|
|
ext4_lblk_t punch_start, punch_stop;
|
|
|
|
handle_t *handle;
|
|
|
|
unsigned int credits;
|
2014-04-20 00:37:31 +04:00
|
|
|
loff_t new_size, ioffset;
|
2014-02-24 00:18:59 +04:00
|
|
|
int ret;
|
|
|
|
|
2015-05-15 07:24:10 +03:00
|
|
|
/*
|
|
|
|
* We need to test this early because xfstests assumes that a
|
|
|
|
* collapse range of (0, 1) will return EOPNOTSUPP if the file
|
|
|
|
* system does not support collapse range.
|
|
|
|
*/
|
|
|
|
if (!ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
2014-02-24 00:18:59 +04:00
|
|
|
/* Collapse range works only on fs block size aligned offsets. */
|
2014-07-29 18:45:31 +04:00
|
|
|
if (offset & (EXT4_CLUSTER_SIZE(sb) - 1) ||
|
|
|
|
len & (EXT4_CLUSTER_SIZE(sb) - 1))
|
2014-02-24 00:18:59 +04:00
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if (!S_ISREG(inode->i_mode))
|
2014-04-18 19:52:11 +04:00
|
|
|
return -EINVAL;
|
2014-02-24 00:18:59 +04:00
|
|
|
|
|
|
|
trace_ext4_collapse_range(inode, offset, len);
|
|
|
|
|
|
|
|
punch_start = offset >> EXT4_BLOCK_SIZE_BITS(sb);
|
|
|
|
punch_stop = (offset + len) >> EXT4_BLOCK_SIZE_BITS(sb);
|
|
|
|
|
2014-04-11 06:58:20 +04:00
|
|
|
/* Call ext4_force_commit to flush all data in case of data=journal. */
|
|
|
|
if (ext4_should_journal_data(inode)) {
|
|
|
|
ret = ext4_force_commit(inode->i_sb);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2016-01-22 23:40:57 +03:00
|
|
|
inode_lock(inode);
|
2014-04-12 17:56:41 +04:00
|
|
|
/*
|
|
|
|
* There is no need to overlap collapse range with EOF, in which case
|
|
|
|
* it is effectively a truncate operation
|
|
|
|
*/
|
|
|
|
if (offset + len >= i_size_read(inode)) {
|
|
|
|
ret = -EINVAL;
|
|
|
|
goto out_mutex;
|
|
|
|
}
|
|
|
|
|
2014-02-24 00:18:59 +04:00
|
|
|
/* Currently just for extent based files */
|
|
|
|
if (!ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) {
|
|
|
|
ret = -EOPNOTSUPP;
|
|
|
|
goto out_mutex;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Wait for existing dio to complete */
|
|
|
|
ext4_inode_block_unlocked_dio(inode);
|
|
|
|
inode_dio_wait(inode);
|
|
|
|
|
2015-12-07 22:28:03 +03:00
|
|
|
/*
|
|
|
|
* Prevent page faults from reinstantiating pages we have released from
|
|
|
|
* page cache.
|
|
|
|
*/
|
|
|
|
down_write(&EXT4_I(inode)->i_mmap_sem);
|
2015-12-07 22:31:11 +03:00
|
|
|
/*
|
|
|
|
* Need to round down offset to be aligned with page size boundary
|
|
|
|
* for page size > block size.
|
|
|
|
*/
|
|
|
|
ioffset = round_down(offset, PAGE_SIZE);
|
|
|
|
/*
|
|
|
|
* Write tail of the last page before removed range since it will get
|
|
|
|
* removed from the page cache below.
|
|
|
|
*/
|
|
|
|
ret = filemap_write_and_wait_range(inode->i_mapping, ioffset, offset);
|
|
|
|
if (ret)
|
|
|
|
goto out_mmap;
|
|
|
|
/*
|
|
|
|
* Write data that will be shifted to preserve them when discarding
|
|
|
|
* page cache below. We are also protected from pages becoming dirty
|
|
|
|
* by i_mmap_sem.
|
|
|
|
*/
|
|
|
|
ret = filemap_write_and_wait_range(inode->i_mapping, offset + len,
|
|
|
|
LLONG_MAX);
|
|
|
|
if (ret)
|
|
|
|
goto out_mmap;
|
2015-12-07 22:28:03 +03:00
|
|
|
truncate_pagecache(inode, ioffset);
|
|
|
|
|
2014-02-24 00:18:59 +04:00
|
|
|
credits = ext4_writepage_trans_blocks(inode);
|
|
|
|
handle = ext4_journal_start(inode, EXT4_HT_TRUNCATE, credits);
|
|
|
|
if (IS_ERR(handle)) {
|
|
|
|
ret = PTR_ERR(handle);
|
2015-12-07 22:28:03 +03:00
|
|
|
goto out_mmap;
|
2014-02-24 00:18:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
down_write(&EXT4_I(inode)->i_data_sem);
|
|
|
|
ext4_discard_preallocations(inode);
|
|
|
|
|
|
|
|
ret = ext4_es_remove_extent(inode, punch_start,
|
2014-04-18 18:43:21 +04:00
|
|
|
EXT_MAX_BLOCKS - punch_start);
|
2014-02-24 00:18:59 +04:00
|
|
|
if (ret) {
|
|
|
|
up_write(&EXT4_I(inode)->i_data_sem);
|
|
|
|
goto out_stop;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = ext4_ext_remove_space(inode, punch_start, punch_stop - 1);
|
|
|
|
if (ret) {
|
|
|
|
up_write(&EXT4_I(inode)->i_data_sem);
|
|
|
|
goto out_stop;
|
|
|
|
}
|
2014-04-18 18:50:23 +04:00
|
|
|
ext4_discard_preallocations(inode);
|
2014-02-24 00:18:59 +04:00
|
|
|
|
|
|
|
ret = ext4_ext_shift_extents(inode, handle, punch_stop,
|
2015-06-09 08:55:03 +03:00
|
|
|
punch_stop - punch_start, SHIFT_LEFT);
|
2014-02-24 00:18:59 +04:00
|
|
|
if (ret) {
|
|
|
|
up_write(&EXT4_I(inode)->i_data_sem);
|
|
|
|
goto out_stop;
|
|
|
|
}
|
|
|
|
|
|
|
|
new_size = i_size_read(inode) - len;
|
2014-04-18 18:48:25 +04:00
|
|
|
i_size_write(inode, new_size);
|
2014-02-24 00:18:59 +04:00
|
|
|
EXT4_I(inode)->i_disksize = new_size;
|
|
|
|
|
|
|
|
up_write(&EXT4_I(inode)->i_data_sem);
|
|
|
|
if (IS_SYNC(inode))
|
|
|
|
ext4_handle_sync(handle);
|
|
|
|
inode->i_mtime = inode->i_ctime = ext4_current_time(inode);
|
|
|
|
ext4_mark_inode_dirty(handle, inode);
|
|
|
|
|
|
|
|
out_stop:
|
|
|
|
ext4_journal_stop(handle);
|
2015-12-07 22:28:03 +03:00
|
|
|
out_mmap:
|
|
|
|
up_write(&EXT4_I(inode)->i_mmap_sem);
|
2014-02-24 00:18:59 +04:00
|
|
|
ext4_inode_resume_unlocked_dio(inode);
|
|
|
|
out_mutex:
|
2016-01-22 23:40:57 +03:00
|
|
|
inode_unlock(inode);
|
2014-02-24 00:18:59 +04:00
|
|
|
return ret;
|
|
|
|
}
|
2014-08-31 07:52:19 +04:00
|
|
|
|
2015-06-09 08:55:03 +03:00
|
|
|
/*
|
|
|
|
* ext4_insert_range:
|
|
|
|
* This function implements the FALLOC_FL_INSERT_RANGE flag of fallocate.
|
|
|
|
* The data blocks starting from @offset to the EOF are shifted by @len
|
|
|
|
* towards right to create a hole in the @inode. Inode size is increased
|
|
|
|
* by len bytes.
|
|
|
|
* Returns 0 on success, error otherwise.
|
|
|
|
*/
|
|
|
|
int ext4_insert_range(struct inode *inode, loff_t offset, loff_t len)
|
|
|
|
{
|
|
|
|
struct super_block *sb = inode->i_sb;
|
|
|
|
handle_t *handle;
|
|
|
|
struct ext4_ext_path *path;
|
|
|
|
struct ext4_extent *extent;
|
|
|
|
ext4_lblk_t offset_lblk, len_lblk, ee_start_lblk = 0;
|
|
|
|
unsigned int credits, ee_len;
|
|
|
|
int ret = 0, depth, split_flag = 0;
|
|
|
|
loff_t ioffset;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We need to test this early because xfstests assumes that an
|
|
|
|
* insert range of (0, 1) will return EOPNOTSUPP if the file
|
|
|
|
* system does not support insert range.
|
|
|
|
*/
|
|
|
|
if (!ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
/* Insert range works only on fs block size aligned offsets. */
|
|
|
|
if (offset & (EXT4_CLUSTER_SIZE(sb) - 1) ||
|
|
|
|
len & (EXT4_CLUSTER_SIZE(sb) - 1))
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if (!S_ISREG(inode->i_mode))
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
trace_ext4_insert_range(inode, offset, len);
|
|
|
|
|
|
|
|
offset_lblk = offset >> EXT4_BLOCK_SIZE_BITS(sb);
|
|
|
|
len_lblk = len >> EXT4_BLOCK_SIZE_BITS(sb);
|
|
|
|
|
|
|
|
/* Call ext4_force_commit to flush all data in case of data=journal */
|
|
|
|
if (ext4_should_journal_data(inode)) {
|
|
|
|
ret = ext4_force_commit(inode->i_sb);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2016-01-22 23:40:57 +03:00
|
|
|
inode_lock(inode);
|
2015-06-09 08:55:03 +03:00
|
|
|
/* Currently just for extent based files */
|
|
|
|
if (!ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) {
|
|
|
|
ret = -EOPNOTSUPP;
|
|
|
|
goto out_mutex;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check for wrap through zero */
|
|
|
|
if (inode->i_size + len > inode->i_sb->s_maxbytes) {
|
|
|
|
ret = -EFBIG;
|
|
|
|
goto out_mutex;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Offset should be less than i_size */
|
|
|
|
if (offset >= i_size_read(inode)) {
|
|
|
|
ret = -EINVAL;
|
|
|
|
goto out_mutex;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Wait for existing dio to complete */
|
|
|
|
ext4_inode_block_unlocked_dio(inode);
|
|
|
|
inode_dio_wait(inode);
|
|
|
|
|
2015-12-07 22:28:03 +03:00
|
|
|
/*
|
|
|
|
* Prevent page faults from reinstantiating pages we have released from
|
|
|
|
* page cache.
|
|
|
|
*/
|
|
|
|
down_write(&EXT4_I(inode)->i_mmap_sem);
|
2015-12-07 22:31:11 +03:00
|
|
|
/*
|
|
|
|
* Need to round down to align start offset to page size boundary
|
|
|
|
* for page size > block size.
|
|
|
|
*/
|
|
|
|
ioffset = round_down(offset, PAGE_SIZE);
|
|
|
|
/* Write out all dirty pages */
|
|
|
|
ret = filemap_write_and_wait_range(inode->i_mapping, ioffset,
|
|
|
|
LLONG_MAX);
|
|
|
|
if (ret)
|
|
|
|
goto out_mmap;
|
2015-12-07 22:28:03 +03:00
|
|
|
truncate_pagecache(inode, ioffset);
|
|
|
|
|
2015-06-09 08:55:03 +03:00
|
|
|
credits = ext4_writepage_trans_blocks(inode);
|
|
|
|
handle = ext4_journal_start(inode, EXT4_HT_TRUNCATE, credits);
|
|
|
|
if (IS_ERR(handle)) {
|
|
|
|
ret = PTR_ERR(handle);
|
2015-12-07 22:28:03 +03:00
|
|
|
goto out_mmap;
|
2015-06-09 08:55:03 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Expand file to avoid data loss if there is error while shifting */
|
|
|
|
inode->i_size += len;
|
|
|
|
EXT4_I(inode)->i_disksize += len;
|
|
|
|
inode->i_mtime = inode->i_ctime = ext4_current_time(inode);
|
|
|
|
ret = ext4_mark_inode_dirty(handle, inode);
|
|
|
|
if (ret)
|
|
|
|
goto out_stop;
|
|
|
|
|
|
|
|
down_write(&EXT4_I(inode)->i_data_sem);
|
|
|
|
ext4_discard_preallocations(inode);
|
|
|
|
|
|
|
|
path = ext4_find_extent(inode, offset_lblk, NULL, 0);
|
|
|
|
if (IS_ERR(path)) {
|
|
|
|
up_write(&EXT4_I(inode)->i_data_sem);
|
|
|
|
goto out_stop;
|
|
|
|
}
|
|
|
|
|
|
|
|
depth = ext_depth(inode);
|
|
|
|
extent = path[depth].p_ext;
|
|
|
|
if (extent) {
|
|
|
|
ee_start_lblk = le32_to_cpu(extent->ee_block);
|
|
|
|
ee_len = ext4_ext_get_actual_len(extent);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If offset_lblk is not the starting block of extent, split
|
|
|
|
* the extent @offset_lblk
|
|
|
|
*/
|
|
|
|
if ((offset_lblk > ee_start_lblk) &&
|
|
|
|
(offset_lblk < (ee_start_lblk + ee_len))) {
|
|
|
|
if (ext4_ext_is_unwritten(extent))
|
|
|
|
split_flag = EXT4_EXT_MARK_UNWRIT1 |
|
|
|
|
EXT4_EXT_MARK_UNWRIT2;
|
|
|
|
ret = ext4_split_extent_at(handle, inode, &path,
|
|
|
|
offset_lblk, split_flag,
|
|
|
|
EXT4_EX_NOCACHE |
|
|
|
|
EXT4_GET_BLOCKS_PRE_IO |
|
|
|
|
EXT4_GET_BLOCKS_METADATA_NOFAIL);
|
|
|
|
}
|
|
|
|
|
|
|
|
ext4_ext_drop_refs(path);
|
|
|
|
kfree(path);
|
|
|
|
if (ret < 0) {
|
|
|
|
up_write(&EXT4_I(inode)->i_data_sem);
|
|
|
|
goto out_stop;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = ext4_es_remove_extent(inode, offset_lblk,
|
|
|
|
EXT_MAX_BLOCKS - offset_lblk);
|
|
|
|
if (ret) {
|
|
|
|
up_write(&EXT4_I(inode)->i_data_sem);
|
|
|
|
goto out_stop;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* if offset_lblk lies in a hole which is at start of file, use
|
|
|
|
* ee_start_lblk to shift extents
|
|
|
|
*/
|
|
|
|
ret = ext4_ext_shift_extents(inode, handle,
|
|
|
|
ee_start_lblk > offset_lblk ? ee_start_lblk : offset_lblk,
|
|
|
|
len_lblk, SHIFT_RIGHT);
|
|
|
|
|
|
|
|
up_write(&EXT4_I(inode)->i_data_sem);
|
|
|
|
if (IS_SYNC(inode))
|
|
|
|
ext4_handle_sync(handle);
|
|
|
|
|
|
|
|
out_stop:
|
|
|
|
ext4_journal_stop(handle);
|
2015-12-07 22:28:03 +03:00
|
|
|
out_mmap:
|
|
|
|
up_write(&EXT4_I(inode)->i_mmap_sem);
|
2015-06-09 08:55:03 +03:00
|
|
|
ext4_inode_resume_unlocked_dio(inode);
|
|
|
|
out_mutex:
|
2016-01-22 23:40:57 +03:00
|
|
|
inode_unlock(inode);
|
2015-06-09 08:55:03 +03:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-08-31 07:52:19 +04:00
|
|
|
/**
|
|
|
|
* ext4_swap_extents - Swap extents between two inodes
|
|
|
|
*
|
|
|
|
* @inode1: First inode
|
|
|
|
* @inode2: Second inode
|
|
|
|
* @lblk1: Start block for first inode
|
|
|
|
* @lblk2: Start block for second inode
|
|
|
|
* @count: Number of blocks to swap
|
|
|
|
* @mark_unwritten: Mark second inode's extents as unwritten after swap
|
|
|
|
* @erp: Pointer to save error value
|
|
|
|
*
|
|
|
|
* This helper routine does exactly what is promise "swap extents". All other
|
|
|
|
* stuff such as page-cache locking consistency, bh mapping consistency or
|
|
|
|
* extent's data copying must be performed by caller.
|
|
|
|
* Locking:
|
|
|
|
* i_mutex is held for both inodes
|
|
|
|
* i_data_sem is locked for write for both inodes
|
|
|
|
* Assumptions:
|
|
|
|
* All pages from requested range are locked for both inodes
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
ext4_swap_extents(handle_t *handle, struct inode *inode1,
|
|
|
|
struct inode *inode2, ext4_lblk_t lblk1, ext4_lblk_t lblk2,
|
|
|
|
ext4_lblk_t count, int unwritten, int *erp)
|
|
|
|
{
|
|
|
|
struct ext4_ext_path *path1 = NULL;
|
|
|
|
struct ext4_ext_path *path2 = NULL;
|
|
|
|
int replaced_count = 0;
|
|
|
|
|
|
|
|
BUG_ON(!rwsem_is_locked(&EXT4_I(inode1)->i_data_sem));
|
|
|
|
BUG_ON(!rwsem_is_locked(&EXT4_I(inode2)->i_data_sem));
|
2016-01-22 23:40:57 +03:00
|
|
|
BUG_ON(!inode_is_locked(inode1));
|
|
|
|
BUG_ON(!inode_is_locked(inode2));
|
2014-08-31 07:52:19 +04:00
|
|
|
|
|
|
|
*erp = ext4_es_remove_extent(inode1, lblk1, count);
|
2014-08-31 23:03:14 +04:00
|
|
|
if (unlikely(*erp))
|
2014-08-31 07:52:19 +04:00
|
|
|
return 0;
|
|
|
|
*erp = ext4_es_remove_extent(inode2, lblk2, count);
|
2014-08-31 23:03:14 +04:00
|
|
|
if (unlikely(*erp))
|
2014-08-31 07:52:19 +04:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
while (count) {
|
|
|
|
struct ext4_extent *ex1, *ex2, tmp_ex;
|
|
|
|
ext4_lblk_t e1_blk, e2_blk;
|
|
|
|
int e1_len, e2_len, len;
|
|
|
|
int split = 0;
|
|
|
|
|
2014-09-01 22:43:09 +04:00
|
|
|
path1 = ext4_find_extent(inode1, lblk1, NULL, EXT4_EX_NOCACHE);
|
2015-08-12 13:29:44 +03:00
|
|
|
if (IS_ERR(path1)) {
|
2014-08-31 07:52:19 +04:00
|
|
|
*erp = PTR_ERR(path1);
|
2014-08-31 23:03:14 +04:00
|
|
|
path1 = NULL;
|
|
|
|
finish:
|
|
|
|
count = 0;
|
|
|
|
goto repeat;
|
2014-08-31 07:52:19 +04:00
|
|
|
}
|
2014-09-01 22:43:09 +04:00
|
|
|
path2 = ext4_find_extent(inode2, lblk2, NULL, EXT4_EX_NOCACHE);
|
2015-08-12 13:29:44 +03:00
|
|
|
if (IS_ERR(path2)) {
|
2014-08-31 07:52:19 +04:00
|
|
|
*erp = PTR_ERR(path2);
|
2014-08-31 23:03:14 +04:00
|
|
|
path2 = NULL;
|
|
|
|
goto finish;
|
2014-08-31 07:52:19 +04:00
|
|
|
}
|
|
|
|
ex1 = path1[path1->p_depth].p_ext;
|
|
|
|
ex2 = path2[path2->p_depth].p_ext;
|
|
|
|
/* Do we have somthing to swap ? */
|
|
|
|
if (unlikely(!ex2 || !ex1))
|
2014-08-31 23:03:14 +04:00
|
|
|
goto finish;
|
2014-08-31 07:52:19 +04:00
|
|
|
|
|
|
|
e1_blk = le32_to_cpu(ex1->ee_block);
|
|
|
|
e2_blk = le32_to_cpu(ex2->ee_block);
|
|
|
|
e1_len = ext4_ext_get_actual_len(ex1);
|
|
|
|
e2_len = ext4_ext_get_actual_len(ex2);
|
|
|
|
|
|
|
|
/* Hole handling */
|
|
|
|
if (!in_range(lblk1, e1_blk, e1_len) ||
|
|
|
|
!in_range(lblk2, e2_blk, e2_len)) {
|
|
|
|
ext4_lblk_t next1, next2;
|
|
|
|
|
|
|
|
/* if hole after extent, then go to next extent */
|
|
|
|
next1 = ext4_ext_next_allocated_block(path1);
|
|
|
|
next2 = ext4_ext_next_allocated_block(path2);
|
|
|
|
/* If hole before extent, then shift to that extent */
|
|
|
|
if (e1_blk > lblk1)
|
|
|
|
next1 = e1_blk;
|
|
|
|
if (e2_blk > lblk2)
|
|
|
|
next2 = e1_blk;
|
|
|
|
/* Do we have something to swap */
|
|
|
|
if (next1 == EXT_MAX_BLOCKS || next2 == EXT_MAX_BLOCKS)
|
2014-08-31 23:03:14 +04:00
|
|
|
goto finish;
|
2014-08-31 07:52:19 +04:00
|
|
|
/* Move to the rightest boundary */
|
|
|
|
len = next1 - lblk1;
|
|
|
|
if (len < next2 - lblk2)
|
|
|
|
len = next2 - lblk2;
|
|
|
|
if (len > count)
|
|
|
|
len = count;
|
|
|
|
lblk1 += len;
|
|
|
|
lblk2 += len;
|
|
|
|
count -= len;
|
|
|
|
goto repeat;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Prepare left boundary */
|
|
|
|
if (e1_blk < lblk1) {
|
|
|
|
split = 1;
|
|
|
|
*erp = ext4_force_split_extent_at(handle, inode1,
|
2014-09-01 22:37:09 +04:00
|
|
|
&path1, lblk1, 0);
|
2014-08-31 23:03:14 +04:00
|
|
|
if (unlikely(*erp))
|
|
|
|
goto finish;
|
2014-08-31 07:52:19 +04:00
|
|
|
}
|
|
|
|
if (e2_blk < lblk2) {
|
|
|
|
split = 1;
|
|
|
|
*erp = ext4_force_split_extent_at(handle, inode2,
|
2014-09-01 22:37:09 +04:00
|
|
|
&path2, lblk2, 0);
|
2014-08-31 23:03:14 +04:00
|
|
|
if (unlikely(*erp))
|
|
|
|
goto finish;
|
2014-08-31 07:52:19 +04:00
|
|
|
}
|
2014-09-01 22:37:09 +04:00
|
|
|
/* ext4_split_extent_at() may result in leaf extent split,
|
2014-08-31 07:52:19 +04:00
|
|
|
* path must to be revalidated. */
|
|
|
|
if (split)
|
|
|
|
goto repeat;
|
|
|
|
|
|
|
|
/* Prepare right boundary */
|
|
|
|
len = count;
|
|
|
|
if (len > e1_blk + e1_len - lblk1)
|
|
|
|
len = e1_blk + e1_len - lblk1;
|
|
|
|
if (len > e2_blk + e2_len - lblk2)
|
|
|
|
len = e2_blk + e2_len - lblk2;
|
|
|
|
|
|
|
|
if (len != e1_len) {
|
|
|
|
split = 1;
|
|
|
|
*erp = ext4_force_split_extent_at(handle, inode1,
|
2014-09-01 22:37:09 +04:00
|
|
|
&path1, lblk1 + len, 0);
|
2014-08-31 23:03:14 +04:00
|
|
|
if (unlikely(*erp))
|
|
|
|
goto finish;
|
2014-08-31 07:52:19 +04:00
|
|
|
}
|
|
|
|
if (len != e2_len) {
|
|
|
|
split = 1;
|
|
|
|
*erp = ext4_force_split_extent_at(handle, inode2,
|
2014-09-01 22:37:09 +04:00
|
|
|
&path2, lblk2 + len, 0);
|
2014-08-31 07:52:19 +04:00
|
|
|
if (*erp)
|
2014-08-31 23:03:14 +04:00
|
|
|
goto finish;
|
2014-08-31 07:52:19 +04:00
|
|
|
}
|
2014-09-01 22:37:09 +04:00
|
|
|
/* ext4_split_extent_at() may result in leaf extent split,
|
2014-08-31 07:52:19 +04:00
|
|
|
* path must to be revalidated. */
|
|
|
|
if (split)
|
|
|
|
goto repeat;
|
|
|
|
|
|
|
|
BUG_ON(e2_len != e1_len);
|
|
|
|
*erp = ext4_ext_get_access(handle, inode1, path1 + path1->p_depth);
|
2014-08-31 23:03:14 +04:00
|
|
|
if (unlikely(*erp))
|
|
|
|
goto finish;
|
2014-08-31 07:52:19 +04:00
|
|
|
*erp = ext4_ext_get_access(handle, inode2, path2 + path2->p_depth);
|
2014-08-31 23:03:14 +04:00
|
|
|
if (unlikely(*erp))
|
|
|
|
goto finish;
|
2014-08-31 07:52:19 +04:00
|
|
|
|
|
|
|
/* Both extents are fully inside boundaries. Swap it now */
|
|
|
|
tmp_ex = *ex1;
|
|
|
|
ext4_ext_store_pblock(ex1, ext4_ext_pblock(ex2));
|
|
|
|
ext4_ext_store_pblock(ex2, ext4_ext_pblock(&tmp_ex));
|
|
|
|
ex1->ee_len = cpu_to_le16(e2_len);
|
|
|
|
ex2->ee_len = cpu_to_le16(e1_len);
|
|
|
|
if (unwritten)
|
|
|
|
ext4_ext_mark_unwritten(ex2);
|
|
|
|
if (ext4_ext_is_unwritten(&tmp_ex))
|
|
|
|
ext4_ext_mark_unwritten(ex1);
|
|
|
|
|
|
|
|
ext4_ext_try_to_merge(handle, inode2, path2, ex2);
|
|
|
|
ext4_ext_try_to_merge(handle, inode1, path1, ex1);
|
|
|
|
*erp = ext4_ext_dirty(handle, inode2, path2 +
|
|
|
|
path2->p_depth);
|
2014-08-31 23:03:14 +04:00
|
|
|
if (unlikely(*erp))
|
|
|
|
goto finish;
|
2014-08-31 07:52:19 +04:00
|
|
|
*erp = ext4_ext_dirty(handle, inode1, path1 +
|
|
|
|
path1->p_depth);
|
|
|
|
/*
|
|
|
|
* Looks scarry ah..? second inode already points to new blocks,
|
|
|
|
* and it was successfully dirtied. But luckily error may happen
|
|
|
|
* only due to journal error, so full transaction will be
|
|
|
|
* aborted anyway.
|
|
|
|
*/
|
2014-08-31 23:03:14 +04:00
|
|
|
if (unlikely(*erp))
|
|
|
|
goto finish;
|
2014-08-31 07:52:19 +04:00
|
|
|
lblk1 += len;
|
|
|
|
lblk2 += len;
|
|
|
|
replaced_count += len;
|
|
|
|
count -= len;
|
|
|
|
|
|
|
|
repeat:
|
2014-09-01 22:39:09 +04:00
|
|
|
ext4_ext_drop_refs(path1);
|
|
|
|
kfree(path1);
|
|
|
|
ext4_ext_drop_refs(path2);
|
|
|
|
kfree(path2);
|
|
|
|
path1 = path2 = NULL;
|
2014-08-31 07:52:19 +04:00
|
|
|
}
|
|
|
|
return replaced_count;
|
|
|
|
}
|