Clean ups and miscellaneous bug fixes, in particular for the new

collapse_range and zero_range fallocate functions.  In addition,
 improve the scalability of adding and remove inodes from the orphan
 list.
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2.0.22 (GNU/Linux)
 
 iQIcBAABCAAGBQJTk9x7AAoJENNvdpvBGATwQQ4QAN85xkNWWiq0feLGZjUVTre/
 JUgRQWXZYVogAQckQoTDXqJt1qKYxO45A8oIoUMI4uzgcFJm7iJIZJAv3Hjd2ftz
 48RVwjWHblmBz6e+CdmETpzJUaJr3KXbnk3EDQzagWg3Q64dBU/yT0c4foBO8wfX
 FI1MNin70r5NGQv6Mp4xNUfMoU6liCrsMO2RWkyxY2rcmxy6tkpNO/NBAPwhmn0e
 vwKHvnnqKM08Frrt6Lz3MpXGAJ+rhTSvmL+qSRXQn9BcbphdGa4jy+i3HbviRX4N
 z77UZMgMbfK1V3YHm8KzmmbIHrmIARXUlCM7jp4HPSnb4qhyERrhVmGCJZ8civ6Q
 3Cm9WwA93PQDfRX6Kid3K1tR/ql+ryac55o9SM990osrWp4C0IH+P/CdlSN0GspN
 3pJTLHUVVcxF6gSnOD+q/JzM8Iudl87Rxb17wA+6eg3AJRaPoQSPJoqtwZ89ZwOz
 RiZGuugFp7gDOxqo32lJ53fivO/e1zxXxu0dVHHjOnHBVWX063hlcibTg8kvFWg1
 7bBvUkvgT5jR+UuDX81wPZ+c0kkmfk4gxT5sHg6RlMKeCYi3uuLmAYgla3AM4j9G
 GeNNdVTmilH7wMgYB2wxd0C5HofgKgM5YFLZWc0FVSXMeFs5ST2kbLMXAZqzrKPa
 szHFEJHIGZByXfkP/jix
 =C1ZV
 -----END PGP SIGNATURE-----

Merge tag 'ext4_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4

Pull ext4 updates from Ted Ts'o:
 "Clean ups and miscellaneous bug fixes, in particular for the new
  collapse_range and zero_range fallocate functions.  In addition,
  improve the scalability of adding and remove inodes from the orphan
  list"

* tag 'ext4_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4: (25 commits)
  ext4: handle symlink properly with inline_data
  ext4: fix wrong assert in ext4_mb_normalize_request()
  ext4: fix zeroing of page during writeback
  ext4: remove unused local variable "stored" from ext4_readdir(...)
  ext4: fix ZERO_RANGE test failure in data journalling
  ext4: reduce contention on s_orphan_lock
  ext4: use sbi in ext4_orphan_{add|del}()
  ext4: use EXT_MAX_BLOCKS in ext4_es_can_be_merged()
  ext4: add missing BUFFER_TRACE before ext4_journal_get_write_access
  ext4: remove unnecessary double parentheses
  ext4: do not destroy ext4_groupinfo_caches if ext4_mb_init() fails
  ext4: make local functions static
  ext4: fix block bitmap validation when bigalloc, ^flex_bg
  ext4: fix block bitmap initialization under sparse_super2
  ext4: find the group descriptors on a 1k-block bigalloc,meta_bg filesystem
  ext4: avoid unneeded lookup when xattr name is invalid
  ext4: fix data integrity sync in ordered mode
  ext4: remove obsoleted check
  ext4: add a new spinlock i_raw_lock to protect the ext4's raw inode
  ext4: fix locking for O_APPEND writes
  ...
This commit is contained in:
Linus Torvalds 2014-06-08 13:03:35 -07:00
commit f8409abdc5
23 changed files with 516 additions and 441 deletions

View file

@ -83,7 +83,7 @@ static inline int ext4_block_in_group(struct super_block *sb,
/* Return the number of clusters used for file system metadata; this /* Return the number of clusters used for file system metadata; this
* represents the overhead needed by the file system. * represents the overhead needed by the file system.
*/ */
unsigned ext4_num_overhead_clusters(struct super_block *sb, static unsigned ext4_num_overhead_clusters(struct super_block *sb,
ext4_group_t block_group, ext4_group_t block_group,
struct ext4_group_desc *gdp) struct ext4_group_desc *gdp)
{ {
@ -176,7 +176,8 @@ static unsigned int num_clusters_in_group(struct super_block *sb,
} }
/* Initializes an uninitialized block bitmap */ /* Initializes an uninitialized block bitmap */
void ext4_init_block_bitmap(struct super_block *sb, struct buffer_head *bh, static void ext4_init_block_bitmap(struct super_block *sb,
struct buffer_head *bh,
ext4_group_t block_group, ext4_group_t block_group,
struct ext4_group_desc *gdp) struct ext4_group_desc *gdp)
{ {
@ -307,6 +308,7 @@ static ext4_fsblk_t ext4_valid_block_bitmap(struct super_block *sb,
ext4_group_t block_group, ext4_group_t block_group,
struct buffer_head *bh) struct buffer_head *bh)
{ {
struct ext4_sb_info *sbi = EXT4_SB(sb);
ext4_grpblk_t offset; ext4_grpblk_t offset;
ext4_grpblk_t next_zero_bit; ext4_grpblk_t next_zero_bit;
ext4_fsblk_t blk; ext4_fsblk_t blk;
@ -326,14 +328,14 @@ static ext4_fsblk_t ext4_valid_block_bitmap(struct super_block *sb,
/* check whether block bitmap block number is set */ /* check whether block bitmap block number is set */
blk = ext4_block_bitmap(sb, desc); blk = ext4_block_bitmap(sb, desc);
offset = blk - group_first_block; offset = blk - group_first_block;
if (!ext4_test_bit(offset, bh->b_data)) if (!ext4_test_bit(EXT4_B2C(sbi, offset), bh->b_data))
/* bad block bitmap */ /* bad block bitmap */
return blk; return blk;
/* check whether the inode bitmap block number is set */ /* check whether the inode bitmap block number is set */
blk = ext4_inode_bitmap(sb, desc); blk = ext4_inode_bitmap(sb, desc);
offset = blk - group_first_block; offset = blk - group_first_block;
if (!ext4_test_bit(offset, bh->b_data)) if (!ext4_test_bit(EXT4_B2C(sbi, offset), bh->b_data))
/* bad block bitmap */ /* bad block bitmap */
return blk; return blk;
@ -341,15 +343,16 @@ static ext4_fsblk_t ext4_valid_block_bitmap(struct super_block *sb,
blk = ext4_inode_table(sb, desc); blk = ext4_inode_table(sb, desc);
offset = blk - group_first_block; offset = blk - group_first_block;
next_zero_bit = ext4_find_next_zero_bit(bh->b_data, next_zero_bit = ext4_find_next_zero_bit(bh->b_data,
offset + EXT4_SB(sb)->s_itb_per_group, EXT4_B2C(sbi, offset + EXT4_SB(sb)->s_itb_per_group),
offset); EXT4_B2C(sbi, offset));
if (next_zero_bit < offset + EXT4_SB(sb)->s_itb_per_group) if (next_zero_bit <
EXT4_B2C(sbi, offset + EXT4_SB(sb)->s_itb_per_group))
/* bad bitmap for inode tables */ /* bad bitmap for inode tables */
return blk; return blk;
return 0; return 0;
} }
void ext4_validate_block_bitmap(struct super_block *sb, static void ext4_validate_block_bitmap(struct super_block *sb,
struct ext4_group_desc *desc, struct ext4_group_desc *desc,
ext4_group_t block_group, ext4_group_t block_group,
struct buffer_head *bh) struct buffer_head *bh)
@ -708,16 +711,6 @@ static inline int test_root(ext4_group_t a, int b)
} }
} }
static int ext4_group_sparse(ext4_group_t group)
{
if (group <= 1)
return 1;
if (!(group & 1))
return 0;
return (test_root(group, 7) || test_root(group, 5) ||
test_root(group, 3));
}
/** /**
* ext4_bg_has_super - number of blocks used by the superblock in group * ext4_bg_has_super - number of blocks used by the superblock in group
* @sb: superblock for filesystem * @sb: superblock for filesystem
@ -728,11 +721,26 @@ static int ext4_group_sparse(ext4_group_t group)
*/ */
int ext4_bg_has_super(struct super_block *sb, ext4_group_t group) int ext4_bg_has_super(struct super_block *sb, ext4_group_t group)
{ {
if (EXT4_HAS_RO_COMPAT_FEATURE(sb, struct ext4_super_block *es = EXT4_SB(sb)->s_es;
EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER) &&
!ext4_group_sparse(group)) if (group == 0)
return 0;
return 1; return 1;
if (EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_SPARSE_SUPER2)) {
if (group == le32_to_cpu(es->s_backup_bgs[0]) ||
group == le32_to_cpu(es->s_backup_bgs[1]))
return 1;
return 0;
}
if ((group <= 1) || !EXT4_HAS_RO_COMPAT_FEATURE(sb,
EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER))
return 1;
if (!(group & 1))
return 0;
if (test_root(group, 3) || (test_root(group, 5)) ||
test_root(group, 7))
return 1;
return 0;
} }
static unsigned long ext4_bg_num_gdb_meta(struct super_block *sb, static unsigned long ext4_bg_num_gdb_meta(struct super_block *sb,

View file

@ -105,7 +105,7 @@ int __ext4_check_dir_entry(const char *function, unsigned int line,
static int ext4_readdir(struct file *file, struct dir_context *ctx) static int ext4_readdir(struct file *file, struct dir_context *ctx)
{ {
unsigned int offset; unsigned int offset;
int i, stored; int i;
struct ext4_dir_entry_2 *de; struct ext4_dir_entry_2 *de;
int err; int err;
struct inode *inode = file_inode(file); struct inode *inode = file_inode(file);
@ -133,7 +133,6 @@ static int ext4_readdir(struct file *file, struct dir_context *ctx)
return ret; return ret;
} }
stored = 0;
offset = ctx->pos & (sb->s_blocksize - 1); offset = ctx->pos & (sb->s_blocksize - 1);
while (ctx->pos < inode->i_size) { while (ctx->pos < inode->i_size) {

View file

@ -158,7 +158,6 @@ struct ext4_allocation_request {
#define EXT4_MAP_MAPPED (1 << BH_Mapped) #define EXT4_MAP_MAPPED (1 << BH_Mapped)
#define EXT4_MAP_UNWRITTEN (1 << BH_Unwritten) #define EXT4_MAP_UNWRITTEN (1 << BH_Unwritten)
#define EXT4_MAP_BOUNDARY (1 << BH_Boundary) #define EXT4_MAP_BOUNDARY (1 << BH_Boundary)
#define EXT4_MAP_UNINIT (1 << BH_Uninit)
/* Sometimes (in the bigalloc case, from ext4_da_get_block_prep) the caller of /* Sometimes (in the bigalloc case, from ext4_da_get_block_prep) the caller of
* ext4_map_blocks wants to know whether or not the underlying cluster has * ext4_map_blocks wants to know whether or not the underlying cluster has
* already been accounted for. EXT4_MAP_FROM_CLUSTER conveys to the caller that * already been accounted for. EXT4_MAP_FROM_CLUSTER conveys to the caller that
@ -169,7 +168,7 @@ struct ext4_allocation_request {
#define EXT4_MAP_FROM_CLUSTER (1 << BH_AllocFromCluster) #define EXT4_MAP_FROM_CLUSTER (1 << BH_AllocFromCluster)
#define EXT4_MAP_FLAGS (EXT4_MAP_NEW | EXT4_MAP_MAPPED |\ #define EXT4_MAP_FLAGS (EXT4_MAP_NEW | EXT4_MAP_MAPPED |\
EXT4_MAP_UNWRITTEN | EXT4_MAP_BOUNDARY |\ EXT4_MAP_UNWRITTEN | EXT4_MAP_BOUNDARY |\
EXT4_MAP_UNINIT | EXT4_MAP_FROM_CLUSTER) EXT4_MAP_FROM_CLUSTER)
struct ext4_map_blocks { struct ext4_map_blocks {
ext4_fsblk_t m_pblk; ext4_fsblk_t m_pblk;
@ -184,7 +183,7 @@ struct ext4_map_blocks {
#define EXT4_IO_END_UNWRITTEN 0x0001 #define EXT4_IO_END_UNWRITTEN 0x0001
/* /*
* For converting uninitialized extents on a work queue. 'handle' is used for * For converting unwritten extents on a work queue. 'handle' is used for
* buffered writeback. * buffered writeback.
*/ */
typedef struct ext4_io_end { typedef struct ext4_io_end {
@ -537,26 +536,26 @@ enum {
/* /*
* Flags used by ext4_map_blocks() * Flags used by ext4_map_blocks()
*/ */
/* Allocate any needed blocks and/or convert an unitialized /* Allocate any needed blocks and/or convert an unwritten
extent to be an initialized ext4 */ extent to be an initialized ext4 */
#define EXT4_GET_BLOCKS_CREATE 0x0001 #define EXT4_GET_BLOCKS_CREATE 0x0001
/* Request the creation of an unitialized extent */ /* Request the creation of an unwritten extent */
#define EXT4_GET_BLOCKS_UNINIT_EXT 0x0002 #define EXT4_GET_BLOCKS_UNWRIT_EXT 0x0002
#define EXT4_GET_BLOCKS_CREATE_UNINIT_EXT (EXT4_GET_BLOCKS_UNINIT_EXT|\ #define EXT4_GET_BLOCKS_CREATE_UNWRIT_EXT (EXT4_GET_BLOCKS_UNWRIT_EXT|\
EXT4_GET_BLOCKS_CREATE) EXT4_GET_BLOCKS_CREATE)
/* Caller is from the delayed allocation writeout path /* Caller is from the delayed allocation writeout path
* finally doing the actual allocation of delayed blocks */ * finally doing the actual allocation of delayed blocks */
#define EXT4_GET_BLOCKS_DELALLOC_RESERVE 0x0004 #define EXT4_GET_BLOCKS_DELALLOC_RESERVE 0x0004
/* caller is from the direct IO path, request to creation of an /* caller is from the direct IO path, request to creation of an
unitialized extents if not allocated, split the uninitialized unwritten extents if not allocated, split the unwritten
extent if blocks has been preallocated already*/ extent if blocks has been preallocated already*/
#define EXT4_GET_BLOCKS_PRE_IO 0x0008 #define EXT4_GET_BLOCKS_PRE_IO 0x0008
#define EXT4_GET_BLOCKS_CONVERT 0x0010 #define EXT4_GET_BLOCKS_CONVERT 0x0010
#define EXT4_GET_BLOCKS_IO_CREATE_EXT (EXT4_GET_BLOCKS_PRE_IO|\ #define EXT4_GET_BLOCKS_IO_CREATE_EXT (EXT4_GET_BLOCKS_PRE_IO|\
EXT4_GET_BLOCKS_CREATE_UNINIT_EXT) EXT4_GET_BLOCKS_CREATE_UNWRIT_EXT)
/* Convert extent to initialized after IO complete */ /* Convert extent to initialized after IO complete */
#define EXT4_GET_BLOCKS_IO_CONVERT_EXT (EXT4_GET_BLOCKS_CONVERT|\ #define EXT4_GET_BLOCKS_IO_CONVERT_EXT (EXT4_GET_BLOCKS_CONVERT|\
EXT4_GET_BLOCKS_CREATE_UNINIT_EXT) EXT4_GET_BLOCKS_CREATE_UNWRIT_EXT)
/* Eventual metadata allocation (due to growing extent tree) /* Eventual metadata allocation (due to growing extent tree)
* should not fail, so try to use reserved blocks for that.*/ * should not fail, so try to use reserved blocks for that.*/
#define EXT4_GET_BLOCKS_METADATA_NOFAIL 0x0020 #define EXT4_GET_BLOCKS_METADATA_NOFAIL 0x0020
@ -876,6 +875,8 @@ struct ext4_inode_info {
struct inode vfs_inode; struct inode vfs_inode;
struct jbd2_inode *jinode; struct jbd2_inode *jinode;
spinlock_t i_raw_lock; /* protects updates to the raw inode */
/* /*
* File creation time. Its function is same as that of * File creation time. Its function is same as that of
* struct timespec i_{a,c,m}time in the generic inode. * struct timespec i_{a,c,m}time in the generic inode.
@ -1159,7 +1160,8 @@ struct ext4_super_block {
__le32 s_usr_quota_inum; /* inode for tracking user quota */ __le32 s_usr_quota_inum; /* inode for tracking user quota */
__le32 s_grp_quota_inum; /* inode for tracking group quota */ __le32 s_grp_quota_inum; /* inode for tracking group quota */
__le32 s_overhead_clusters; /* overhead blocks/clusters in fs */ __le32 s_overhead_clusters; /* overhead blocks/clusters in fs */
__le32 s_reserved[108]; /* Padding to the end of the block */ __le32 s_backup_bgs[2]; /* groups with sparse_super2 SBs */
__le32 s_reserved[106]; /* Padding to the end of the block */
__le32 s_checksum; /* crc32c(superblock) */ __le32 s_checksum; /* crc32c(superblock) */
}; };
@ -1505,6 +1507,7 @@ static inline void ext4_clear_state_flags(struct ext4_inode_info *ei)
#define EXT4_FEATURE_COMPAT_EXT_ATTR 0x0008 #define EXT4_FEATURE_COMPAT_EXT_ATTR 0x0008
#define EXT4_FEATURE_COMPAT_RESIZE_INODE 0x0010 #define EXT4_FEATURE_COMPAT_RESIZE_INODE 0x0010
#define EXT4_FEATURE_COMPAT_DIR_INDEX 0x0020 #define EXT4_FEATURE_COMPAT_DIR_INDEX 0x0020
#define EXT4_FEATURE_COMPAT_SPARSE_SUPER2 0x0200
#define EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001 #define EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001
#define EXT4_FEATURE_RO_COMPAT_LARGE_FILE 0x0002 #define EXT4_FEATURE_RO_COMPAT_LARGE_FILE 0x0002
@ -1953,10 +1956,6 @@ extern void ext4_get_group_no_and_offset(struct super_block *sb,
extern ext4_group_t ext4_get_group_number(struct super_block *sb, extern ext4_group_t ext4_get_group_number(struct super_block *sb,
ext4_fsblk_t block); ext4_fsblk_t block);
extern void ext4_validate_block_bitmap(struct super_block *sb,
struct ext4_group_desc *desc,
ext4_group_t block_group,
struct buffer_head *bh);
extern unsigned int ext4_block_group(struct super_block *sb, extern unsigned int ext4_block_group(struct super_block *sb,
ext4_fsblk_t blocknr); ext4_fsblk_t blocknr);
extern ext4_grpblk_t ext4_block_group_offset(struct super_block *sb, extern ext4_grpblk_t ext4_block_group_offset(struct super_block *sb,
@ -1985,16 +1984,9 @@ extern int ext4_wait_block_bitmap(struct super_block *sb,
struct buffer_head *bh); struct buffer_head *bh);
extern struct buffer_head *ext4_read_block_bitmap(struct super_block *sb, extern struct buffer_head *ext4_read_block_bitmap(struct super_block *sb,
ext4_group_t block_group); ext4_group_t block_group);
extern void ext4_init_block_bitmap(struct super_block *sb,
struct buffer_head *bh,
ext4_group_t group,
struct ext4_group_desc *desc);
extern unsigned ext4_free_clusters_after_init(struct super_block *sb, extern unsigned ext4_free_clusters_after_init(struct super_block *sb,
ext4_group_t block_group, ext4_group_t block_group,
struct ext4_group_desc *gdp); struct ext4_group_desc *gdp);
extern unsigned ext4_num_overhead_clusters(struct super_block *sb,
ext4_group_t block_group,
struct ext4_group_desc *gdp);
ext4_fsblk_t ext4_inode_to_goal_block(struct inode *); ext4_fsblk_t ext4_inode_to_goal_block(struct inode *);
/* dir.c */ /* dir.c */
@ -2137,8 +2129,6 @@ extern int ext4_alloc_da_blocks(struct inode *inode);
extern void ext4_set_aops(struct inode *inode); extern void ext4_set_aops(struct inode *inode);
extern int ext4_writepage_trans_blocks(struct inode *); extern int ext4_writepage_trans_blocks(struct inode *);
extern int ext4_chunk_trans_blocks(struct inode *, int nrblocks); extern int ext4_chunk_trans_blocks(struct inode *, int nrblocks);
extern int ext4_block_truncate_page(handle_t *handle,
struct address_space *mapping, loff_t from);
extern int ext4_zero_partial_blocks(handle_t *handle, struct inode *inode, extern int ext4_zero_partial_blocks(handle_t *handle, struct inode *inode,
loff_t lstart, loff_t lend); loff_t lstart, loff_t lend);
extern int ext4_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf); extern int ext4_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf);
@ -2198,8 +2188,6 @@ extern int ext4_resize_fs(struct super_block *sb, ext4_fsblk_t n_blocks_count);
/* super.c */ /* super.c */
extern int ext4_calculate_overhead(struct super_block *sb); extern int ext4_calculate_overhead(struct super_block *sb);
extern int ext4_superblock_csum_verify(struct super_block *sb,
struct ext4_super_block *es);
extern void ext4_superblock_csum_set(struct super_block *sb); extern void ext4_superblock_csum_set(struct super_block *sb);
extern void *ext4_kvmalloc(size_t size, gfp_t flags); extern void *ext4_kvmalloc(size_t size, gfp_t flags);
extern void *ext4_kvzalloc(size_t size, gfp_t flags); extern void *ext4_kvzalloc(size_t size, gfp_t flags);
@ -2571,19 +2559,11 @@ extern const struct file_operations ext4_dir_operations;
extern const struct inode_operations ext4_file_inode_operations; extern const struct inode_operations ext4_file_inode_operations;
extern const struct file_operations ext4_file_operations; extern const struct file_operations ext4_file_operations;
extern loff_t ext4_llseek(struct file *file, loff_t offset, int origin); extern loff_t ext4_llseek(struct file *file, loff_t offset, int origin);
extern void ext4_unwritten_wait(struct inode *inode);
/* inline.c */ /* inline.c */
extern int ext4_has_inline_data(struct inode *inode); extern int ext4_has_inline_data(struct inode *inode);
extern int ext4_get_inline_size(struct inode *inode);
extern int ext4_get_max_inline_size(struct inode *inode); extern int ext4_get_max_inline_size(struct inode *inode);
extern int ext4_find_inline_data_nolock(struct inode *inode); extern int ext4_find_inline_data_nolock(struct inode *inode);
extern void ext4_write_inline_data(struct inode *inode,
struct ext4_iloc *iloc,
void *buffer, loff_t pos,
unsigned int len);
extern int ext4_prepare_inline_data(handle_t *handle, struct inode *inode,
unsigned int len);
extern int ext4_init_inline_data(handle_t *handle, struct inode *inode, extern int ext4_init_inline_data(handle_t *handle, struct inode *inode,
unsigned int len); unsigned int len);
extern int ext4_destroy_inline_data(handle_t *handle, struct inode *inode); extern int ext4_destroy_inline_data(handle_t *handle, struct inode *inode);
@ -2771,23 +2751,20 @@ extern void ext4_io_submit(struct ext4_io_submit *io);
extern int ext4_bio_write_page(struct ext4_io_submit *io, extern int ext4_bio_write_page(struct ext4_io_submit *io,
struct page *page, struct page *page,
int len, int len,
struct writeback_control *wbc); struct writeback_control *wbc,
bool keep_towrite);
/* mmp.c */ /* mmp.c */
extern int ext4_multi_mount_protect(struct super_block *, ext4_fsblk_t); extern int ext4_multi_mount_protect(struct super_block *, ext4_fsblk_t);
extern void ext4_mmp_csum_set(struct super_block *sb, struct mmp_struct *mmp);
extern int ext4_mmp_csum_verify(struct super_block *sb,
struct mmp_struct *mmp);
/* /*
* Note that these flags will never ever appear in a buffer_head's state flag. * Note that these flags will never ever appear in a buffer_head's state flag.
* See EXT4_MAP_... to see where this is used. * See EXT4_MAP_... to see where this is used.
*/ */
enum ext4_state_bits { enum ext4_state_bits {
BH_Uninit /* blocks are allocated but uninitialized on disk */ BH_AllocFromCluster /* allocated blocks were part of already
= BH_JBDPrivateStart,
BH_AllocFromCluster, /* allocated blocks were part of already
* allocated cluster. */ * allocated cluster. */
= BH_JBDPrivateStart
}; };
/* /*

View file

@ -137,21 +137,21 @@ struct ext4_ext_path {
* EXT_INIT_MAX_LEN is the maximum number of blocks we can have in an * EXT_INIT_MAX_LEN is the maximum number of blocks we can have in an
* initialized extent. This is 2^15 and not (2^16 - 1), since we use the * initialized extent. This is 2^15 and not (2^16 - 1), since we use the
* MSB of ee_len field in the extent datastructure to signify if this * MSB of ee_len field in the extent datastructure to signify if this
* particular extent is an initialized extent or an uninitialized (i.e. * particular extent is an initialized extent or an unwritten (i.e.
* preallocated). * preallocated).
* EXT_UNINIT_MAX_LEN is the maximum number of blocks we can have in an * EXT_UNWRITTEN_MAX_LEN is the maximum number of blocks we can have in an
* uninitialized extent. * unwritten extent.
* If ee_len is <= 0x8000, it is an initialized extent. Otherwise, it is an * If ee_len is <= 0x8000, it is an initialized extent. Otherwise, it is an
* uninitialized one. In other words, if MSB of ee_len is set, it is an * unwritten one. In other words, if MSB of ee_len is set, it is an
* uninitialized extent with only one special scenario when ee_len = 0x8000. * unwritten extent with only one special scenario when ee_len = 0x8000.
* In this case we can not have an uninitialized extent of zero length and * In this case we can not have an unwritten extent of zero length and
* thus we make it as a special case of initialized extent with 0x8000 length. * thus we make it as a special case of initialized extent with 0x8000 length.
* This way we get better extent-to-group alignment for initialized extents. * This way we get better extent-to-group alignment for initialized extents.
* Hence, the maximum number of blocks we can have in an *initialized* * Hence, the maximum number of blocks we can have in an *initialized*
* extent is 2^15 (32768) and in an *uninitialized* extent is 2^15-1 (32767). * extent is 2^15 (32768) and in an *unwritten* extent is 2^15-1 (32767).
*/ */
#define EXT_INIT_MAX_LEN (1UL << 15) #define EXT_INIT_MAX_LEN (1UL << 15)
#define EXT_UNINIT_MAX_LEN (EXT_INIT_MAX_LEN - 1) #define EXT_UNWRITTEN_MAX_LEN (EXT_INIT_MAX_LEN - 1)
#define EXT_FIRST_EXTENT(__hdr__) \ #define EXT_FIRST_EXTENT(__hdr__) \
@ -187,14 +187,14 @@ static inline unsigned short ext_depth(struct inode *inode)
return le16_to_cpu(ext_inode_hdr(inode)->eh_depth); return le16_to_cpu(ext_inode_hdr(inode)->eh_depth);
} }
static inline void ext4_ext_mark_uninitialized(struct ext4_extent *ext) static inline void ext4_ext_mark_unwritten(struct ext4_extent *ext)
{ {
/* We can not have an uninitialized extent of zero length! */ /* We can not have an unwritten extent of zero length! */
BUG_ON((le16_to_cpu(ext->ee_len) & ~EXT_INIT_MAX_LEN) == 0); BUG_ON((le16_to_cpu(ext->ee_len) & ~EXT_INIT_MAX_LEN) == 0);
ext->ee_len |= cpu_to_le16(EXT_INIT_MAX_LEN); ext->ee_len |= cpu_to_le16(EXT_INIT_MAX_LEN);
} }
static inline int ext4_ext_is_uninitialized(struct ext4_extent *ext) static inline int ext4_ext_is_unwritten(struct ext4_extent *ext)
{ {
/* Extent with ee_len of 0x8000 is treated as an initialized extent */ /* Extent with ee_len of 0x8000 is treated as an initialized extent */
return (le16_to_cpu(ext->ee_len) > EXT_INIT_MAX_LEN); return (le16_to_cpu(ext->ee_len) > EXT_INIT_MAX_LEN);

View file

@ -122,8 +122,9 @@ handle_t *__ext4_journal_start_reserved(handle_t *handle, unsigned int line,
return handle; return handle;
} }
void ext4_journal_abort_handle(const char *caller, unsigned int line, static void ext4_journal_abort_handle(const char *caller, unsigned int line,
const char *err_fn, struct buffer_head *bh, const char *err_fn,
struct buffer_head *bh,
handle_t *handle, int err) handle_t *handle, int err)
{ {
char nbuf[16]; char nbuf[16];

View file

@ -231,10 +231,6 @@ int ext4_mark_inode_dirty(handle_t *handle, struct inode *inode);
/* /*
* Wrapper functions with which ext4 calls into JBD. * Wrapper functions with which ext4 calls into JBD.
*/ */
void ext4_journal_abort_handle(const char *caller, unsigned int line,
const char *err_fn,
struct buffer_head *bh, handle_t *handle, int err);
int __ext4_journal_get_write_access(const char *where, unsigned int line, int __ext4_journal_get_write_access(const char *where, unsigned int line,
handle_t *handle, struct buffer_head *bh); handle_t *handle, struct buffer_head *bh);

View file

@ -50,8 +50,8 @@
*/ */
#define EXT4_EXT_MAY_ZEROOUT 0x1 /* safe to zeroout if split fails \ #define EXT4_EXT_MAY_ZEROOUT 0x1 /* safe to zeroout if split fails \
due to ENOSPC */ due to ENOSPC */
#define EXT4_EXT_MARK_UNINIT1 0x2 /* mark first half uninitialized */ #define EXT4_EXT_MARK_UNWRIT1 0x2 /* mark first half unwritten */
#define EXT4_EXT_MARK_UNINIT2 0x4 /* mark second half uninitialized */ #define EXT4_EXT_MARK_UNWRIT2 0x4 /* mark second half unwritten */
#define EXT4_EXT_DATA_VALID1 0x8 /* first half contains valid data */ #define EXT4_EXT_DATA_VALID1 0x8 /* first half contains valid data */
#define EXT4_EXT_DATA_VALID2 0x10 /* second half contains valid data */ #define EXT4_EXT_DATA_VALID2 0x10 /* second half contains valid data */
@ -143,6 +143,7 @@ static int ext4_ext_get_access(handle_t *handle, struct inode *inode,
{ {
if (path->p_bh) { if (path->p_bh) {
/* path points to block */ /* path points to block */
BUFFER_TRACE(path->p_bh, "get_write_access");
return ext4_journal_get_write_access(handle, path->p_bh); return ext4_journal_get_write_access(handle, path->p_bh);
} }
/* path points to leaf/index in inode body */ /* path points to leaf/index in inode body */
@ -524,7 +525,7 @@ __read_extent_tree_block(const char *function, unsigned int line,
lblk - prev, ~0, lblk - prev, ~0,
EXTENT_STATUS_HOLE); EXTENT_STATUS_HOLE);
if (ext4_ext_is_uninitialized(ex)) if (ext4_ext_is_unwritten(ex))
status = EXTENT_STATUS_UNWRITTEN; status = EXTENT_STATUS_UNWRITTEN;
ext4_es_cache_extent(inode, lblk, len, ext4_es_cache_extent(inode, lblk, len,
ext4_ext_pblock(ex), status); ext4_ext_pblock(ex), status);
@ -620,7 +621,7 @@ static void ext4_ext_show_path(struct inode *inode, struct ext4_ext_path *path)
} else if (path->p_ext) { } else if (path->p_ext) {
ext_debug(" %d:[%d]%d:%llu ", ext_debug(" %d:[%d]%d:%llu ",
le32_to_cpu(path->p_ext->ee_block), le32_to_cpu(path->p_ext->ee_block),
ext4_ext_is_uninitialized(path->p_ext), ext4_ext_is_unwritten(path->p_ext),
ext4_ext_get_actual_len(path->p_ext), ext4_ext_get_actual_len(path->p_ext),
ext4_ext_pblock(path->p_ext)); ext4_ext_pblock(path->p_ext));
} else } else
@ -646,7 +647,7 @@ static void ext4_ext_show_leaf(struct inode *inode, struct ext4_ext_path *path)
for (i = 0; i < le16_to_cpu(eh->eh_entries); i++, ex++) { for (i = 0; i < le16_to_cpu(eh->eh_entries); i++, ex++) {
ext_debug("%d:[%d]%d:%llu ", le32_to_cpu(ex->ee_block), ext_debug("%d:[%d]%d:%llu ", le32_to_cpu(ex->ee_block),
ext4_ext_is_uninitialized(ex), ext4_ext_is_unwritten(ex),
ext4_ext_get_actual_len(ex), ext4_ext_pblock(ex)); ext4_ext_get_actual_len(ex), ext4_ext_pblock(ex));
} }
ext_debug("\n"); ext_debug("\n");
@ -677,7 +678,7 @@ static void ext4_ext_show_move(struct inode *inode, struct ext4_ext_path *path,
ext_debug("move %d:%llu:[%d]%d in new leaf %llu\n", ext_debug("move %d:%llu:[%d]%d in new leaf %llu\n",
le32_to_cpu(ex->ee_block), le32_to_cpu(ex->ee_block),
ext4_ext_pblock(ex), ext4_ext_pblock(ex),
ext4_ext_is_uninitialized(ex), ext4_ext_is_unwritten(ex),
ext4_ext_get_actual_len(ex), ext4_ext_get_actual_len(ex),
newblock); newblock);
ex++; ex++;
@ -802,7 +803,7 @@ ext4_ext_binsearch(struct inode *inode,
ext_debug(" -> %d:%llu:[%d]%d ", ext_debug(" -> %d:%llu:[%d]%d ",
le32_to_cpu(path->p_ext->ee_block), le32_to_cpu(path->p_ext->ee_block),
ext4_ext_pblock(path->p_ext), ext4_ext_pblock(path->p_ext),
ext4_ext_is_uninitialized(path->p_ext), ext4_ext_is_unwritten(path->p_ext),
ext4_ext_get_actual_len(path->p_ext)); ext4_ext_get_actual_len(path->p_ext));
#ifdef CHECK_BINSEARCH #ifdef CHECK_BINSEARCH
@ -1686,11 +1687,11 @@ ext4_can_extents_be_merged(struct inode *inode, struct ext4_extent *ex1,
/* /*
* Make sure that both extents are initialized. We don't merge * Make sure that both extents are initialized. We don't merge
* uninitialized extents so that we can be sure that end_io code has * unwritten extents so that we can be sure that end_io code has
* the extent that was written properly split out and conversion to * the extent that was written properly split out and conversion to
* initialized is trivial. * initialized is trivial.
*/ */
if (ext4_ext_is_uninitialized(ex1) != ext4_ext_is_uninitialized(ex2)) if (ext4_ext_is_unwritten(ex1) != ext4_ext_is_unwritten(ex2))
return 0; return 0;
ext1_ee_len = ext4_ext_get_actual_len(ex1); ext1_ee_len = ext4_ext_get_actual_len(ex1);
@ -1707,10 +1708,10 @@ ext4_can_extents_be_merged(struct inode *inode, struct ext4_extent *ex1,
*/ */
if (ext1_ee_len + ext2_ee_len > EXT_INIT_MAX_LEN) if (ext1_ee_len + ext2_ee_len > EXT_INIT_MAX_LEN)
return 0; return 0;
if (ext4_ext_is_uninitialized(ex1) && if (ext4_ext_is_unwritten(ex1) &&
(ext4_test_inode_state(inode, EXT4_STATE_DIO_UNWRITTEN) || (ext4_test_inode_state(inode, EXT4_STATE_DIO_UNWRITTEN) ||
atomic_read(&EXT4_I(inode)->i_unwritten) || atomic_read(&EXT4_I(inode)->i_unwritten) ||
(ext1_ee_len + ext2_ee_len > EXT_UNINIT_MAX_LEN))) (ext1_ee_len + ext2_ee_len > EXT_UNWRITTEN_MAX_LEN)))
return 0; return 0;
#ifdef AGGRESSIVE_TEST #ifdef AGGRESSIVE_TEST
if (ext1_ee_len >= 4) if (ext1_ee_len >= 4)
@ -1735,7 +1736,7 @@ static int ext4_ext_try_to_merge_right(struct inode *inode,
{ {
struct ext4_extent_header *eh; struct ext4_extent_header *eh;
unsigned int depth, len; unsigned int depth, len;
int merge_done = 0, uninit; int merge_done = 0, unwritten;
depth = ext_depth(inode); depth = ext_depth(inode);
BUG_ON(path[depth].p_hdr == NULL); BUG_ON(path[depth].p_hdr == NULL);
@ -1745,11 +1746,11 @@ static int ext4_ext_try_to_merge_right(struct inode *inode,
if (!ext4_can_extents_be_merged(inode, ex, ex + 1)) if (!ext4_can_extents_be_merged(inode, ex, ex + 1))
break; break;
/* merge with next extent! */ /* merge with next extent! */
uninit = ext4_ext_is_uninitialized(ex); unwritten = ext4_ext_is_unwritten(ex);
ex->ee_len = cpu_to_le16(ext4_ext_get_actual_len(ex) ex->ee_len = cpu_to_le16(ext4_ext_get_actual_len(ex)
+ ext4_ext_get_actual_len(ex + 1)); + ext4_ext_get_actual_len(ex + 1));
if (uninit) if (unwritten)
ext4_ext_mark_uninitialized(ex); ext4_ext_mark_unwritten(ex);
if (ex + 1 < EXT_LAST_EXTENT(eh)) { if (ex + 1 < EXT_LAST_EXTENT(eh)) {
len = (EXT_LAST_EXTENT(eh) - ex - 1) len = (EXT_LAST_EXTENT(eh) - ex - 1)
@ -1903,7 +1904,7 @@ int ext4_ext_insert_extent(handle_t *handle, struct inode *inode,
struct ext4_ext_path *npath = NULL; struct ext4_ext_path *npath = NULL;
int depth, len, err; int depth, len, err;
ext4_lblk_t next; ext4_lblk_t next;
int mb_flags = 0, uninit; int mb_flags = 0, unwritten;
if (unlikely(ext4_ext_get_actual_len(newext) == 0)) { if (unlikely(ext4_ext_get_actual_len(newext) == 0)) {
EXT4_ERROR_INODE(inode, "ext4_ext_get_actual_len(newext) == 0"); EXT4_ERROR_INODE(inode, "ext4_ext_get_actual_len(newext) == 0");
@ -1943,21 +1944,21 @@ int ext4_ext_insert_extent(handle_t *handle, struct inode *inode,
if (ext4_can_extents_be_merged(inode, ex, newext)) { if (ext4_can_extents_be_merged(inode, ex, newext)) {
ext_debug("append [%d]%d block to %u:[%d]%d" ext_debug("append [%d]%d block to %u:[%d]%d"
"(from %llu)\n", "(from %llu)\n",
ext4_ext_is_uninitialized(newext), ext4_ext_is_unwritten(newext),
ext4_ext_get_actual_len(newext), ext4_ext_get_actual_len(newext),
le32_to_cpu(ex->ee_block), le32_to_cpu(ex->ee_block),
ext4_ext_is_uninitialized(ex), ext4_ext_is_unwritten(ex),
ext4_ext_get_actual_len(ex), ext4_ext_get_actual_len(ex),
ext4_ext_pblock(ex)); ext4_ext_pblock(ex));
err = ext4_ext_get_access(handle, inode, err = ext4_ext_get_access(handle, inode,
path + depth); path + depth);
if (err) if (err)
return err; return err;
uninit = ext4_ext_is_uninitialized(ex); unwritten = ext4_ext_is_unwritten(ex);
ex->ee_len = cpu_to_le16(ext4_ext_get_actual_len(ex) ex->ee_len = cpu_to_le16(ext4_ext_get_actual_len(ex)
+ ext4_ext_get_actual_len(newext)); + ext4_ext_get_actual_len(newext));
if (uninit) if (unwritten)
ext4_ext_mark_uninitialized(ex); ext4_ext_mark_unwritten(ex);
eh = path[depth].p_hdr; eh = path[depth].p_hdr;
nearex = ex; nearex = ex;
goto merge; goto merge;
@ -1969,10 +1970,10 @@ prepend:
ext_debug("prepend %u[%d]%d block to %u:[%d]%d" ext_debug("prepend %u[%d]%d block to %u:[%d]%d"
"(from %llu)\n", "(from %llu)\n",
le32_to_cpu(newext->ee_block), le32_to_cpu(newext->ee_block),
ext4_ext_is_uninitialized(newext), ext4_ext_is_unwritten(newext),
ext4_ext_get_actual_len(newext), ext4_ext_get_actual_len(newext),
le32_to_cpu(ex->ee_block), le32_to_cpu(ex->ee_block),
ext4_ext_is_uninitialized(ex), ext4_ext_is_unwritten(ex),
ext4_ext_get_actual_len(ex), ext4_ext_get_actual_len(ex),
ext4_ext_pblock(ex)); ext4_ext_pblock(ex));
err = ext4_ext_get_access(handle, inode, err = ext4_ext_get_access(handle, inode,
@ -1980,13 +1981,13 @@ prepend:
if (err) if (err)
return err; return err;
uninit = ext4_ext_is_uninitialized(ex); unwritten = ext4_ext_is_unwritten(ex);
ex->ee_block = newext->ee_block; ex->ee_block = newext->ee_block;
ext4_ext_store_pblock(ex, ext4_ext_pblock(newext)); ext4_ext_store_pblock(ex, ext4_ext_pblock(newext));
ex->ee_len = cpu_to_le16(ext4_ext_get_actual_len(ex) ex->ee_len = cpu_to_le16(ext4_ext_get_actual_len(ex)
+ ext4_ext_get_actual_len(newext)); + ext4_ext_get_actual_len(newext));
if (uninit) if (unwritten)
ext4_ext_mark_uninitialized(ex); ext4_ext_mark_unwritten(ex);
eh = path[depth].p_hdr; eh = path[depth].p_hdr;
nearex = ex; nearex = ex;
goto merge; goto merge;
@ -2046,7 +2047,7 @@ has_space:
ext_debug("first extent in the leaf: %u:%llu:[%d]%d\n", ext_debug("first extent in the leaf: %u:%llu:[%d]%d\n",
le32_to_cpu(newext->ee_block), le32_to_cpu(newext->ee_block),
ext4_ext_pblock(newext), ext4_ext_pblock(newext),
ext4_ext_is_uninitialized(newext), ext4_ext_is_unwritten(newext),
ext4_ext_get_actual_len(newext)); ext4_ext_get_actual_len(newext));
nearex = EXT_FIRST_EXTENT(eh); nearex = EXT_FIRST_EXTENT(eh);
} else { } else {
@ -2057,7 +2058,7 @@ has_space:
"nearest %p\n", "nearest %p\n",
le32_to_cpu(newext->ee_block), le32_to_cpu(newext->ee_block),
ext4_ext_pblock(newext), ext4_ext_pblock(newext),
ext4_ext_is_uninitialized(newext), ext4_ext_is_unwritten(newext),
ext4_ext_get_actual_len(newext), ext4_ext_get_actual_len(newext),
nearex); nearex);
nearex++; nearex++;
@ -2068,7 +2069,7 @@ has_space:
"nearest %p\n", "nearest %p\n",
le32_to_cpu(newext->ee_block), le32_to_cpu(newext->ee_block),
ext4_ext_pblock(newext), ext4_ext_pblock(newext),
ext4_ext_is_uninitialized(newext), ext4_ext_is_unwritten(newext),
ext4_ext_get_actual_len(newext), ext4_ext_get_actual_len(newext),
nearex); nearex);
} }
@ -2078,7 +2079,7 @@ has_space:
"move %d extents from 0x%p to 0x%p\n", "move %d extents from 0x%p to 0x%p\n",
le32_to_cpu(newext->ee_block), le32_to_cpu(newext->ee_block),
ext4_ext_pblock(newext), ext4_ext_pblock(newext),
ext4_ext_is_uninitialized(newext), ext4_ext_is_unwritten(newext),
ext4_ext_get_actual_len(newext), ext4_ext_get_actual_len(newext),
len, nearex, nearex + 1); len, nearex, nearex + 1);
memmove(nearex + 1, nearex, memmove(nearex + 1, nearex,
@ -2200,7 +2201,7 @@ static int ext4_fill_fiemap_extents(struct inode *inode,
es.es_lblk = le32_to_cpu(ex->ee_block); es.es_lblk = le32_to_cpu(ex->ee_block);
es.es_len = ext4_ext_get_actual_len(ex); es.es_len = ext4_ext_get_actual_len(ex);
es.es_pblk = ext4_ext_pblock(ex); es.es_pblk = ext4_ext_pblock(ex);
if (ext4_ext_is_uninitialized(ex)) if (ext4_ext_is_unwritten(ex))
flags |= FIEMAP_EXTENT_UNWRITTEN; flags |= FIEMAP_EXTENT_UNWRITTEN;
} }
@ -2576,7 +2577,7 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode,
unsigned num; unsigned num;
ext4_lblk_t ex_ee_block; ext4_lblk_t ex_ee_block;
unsigned short ex_ee_len; unsigned short ex_ee_len;
unsigned uninitialized = 0; unsigned unwritten = 0;
struct ext4_extent *ex; struct ext4_extent *ex;
ext4_fsblk_t pblk; ext4_fsblk_t pblk;
@ -2623,13 +2624,13 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode,
while (ex >= EXT_FIRST_EXTENT(eh) && while (ex >= EXT_FIRST_EXTENT(eh) &&
ex_ee_block + ex_ee_len > start) { ex_ee_block + ex_ee_len > start) {
if (ext4_ext_is_uninitialized(ex)) if (ext4_ext_is_unwritten(ex))
uninitialized = 1; unwritten = 1;
else else
uninitialized = 0; unwritten = 0;
ext_debug("remove ext %u:[%d]%d\n", ex_ee_block, ext_debug("remove ext %u:[%d]%d\n", ex_ee_block,
uninitialized, ex_ee_len); unwritten, ex_ee_len);
path[depth].p_ext = ex; path[depth].p_ext = ex;
a = ex_ee_block > start ? ex_ee_block : start; a = ex_ee_block > start ? ex_ee_block : start;
@ -2701,11 +2702,11 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode,
ex->ee_len = cpu_to_le16(num); ex->ee_len = cpu_to_le16(num);
/* /*
* Do not mark uninitialized if all the blocks in the * Do not mark unwritten if all the blocks in the
* extent have been removed. * extent have been removed.
*/ */
if (uninitialized && num) if (unwritten && num)
ext4_ext_mark_uninitialized(ex); ext4_ext_mark_unwritten(ex);
/* /*
* If the extent was completely released, * If the extent was completely released,
* we need to remove it from the leaf * we need to remove it from the leaf
@ -2854,9 +2855,9 @@ again:
end < ee_block + ext4_ext_get_actual_len(ex) - 1) { end < ee_block + ext4_ext_get_actual_len(ex) - 1) {
int split_flag = 0; int split_flag = 0;
if (ext4_ext_is_uninitialized(ex)) if (ext4_ext_is_unwritten(ex))
split_flag = EXT4_EXT_MARK_UNINIT1 | split_flag = EXT4_EXT_MARK_UNWRIT1 |
EXT4_EXT_MARK_UNINIT2; EXT4_EXT_MARK_UNWRIT2;
/* /*
* Split the extent in two so that 'end' is the last * Split the extent in two so that 'end' is the last
@ -3113,7 +3114,7 @@ static int ext4_ext_zeroout(struct inode *inode, struct ext4_extent *ex)
* @path: the path to the extent * @path: the path to the extent
* @split: the logical block where the extent is splitted. * @split: the logical block where the extent is splitted.
* @split_flags: indicates if the extent could be zeroout if split fails, and * @split_flags: indicates if the extent could be zeroout if split fails, and
* the states(init or uninit) of new extents. * the states(init or unwritten) of new extents.
* @flags: flags used to insert new extent to extent tree. * @flags: flags used to insert new extent to extent tree.
* *
* *
@ -3155,10 +3156,10 @@ static int ext4_split_extent_at(handle_t *handle,
newblock = split - ee_block + ext4_ext_pblock(ex); newblock = split - ee_block + ext4_ext_pblock(ex);
BUG_ON(split < ee_block || split >= (ee_block + ee_len)); BUG_ON(split < ee_block || split >= (ee_block + ee_len));
BUG_ON(!ext4_ext_is_uninitialized(ex) && BUG_ON(!ext4_ext_is_unwritten(ex) &&
split_flag & (EXT4_EXT_MAY_ZEROOUT | split_flag & (EXT4_EXT_MAY_ZEROOUT |
EXT4_EXT_MARK_UNINIT1 | EXT4_EXT_MARK_UNWRIT1 |
EXT4_EXT_MARK_UNINIT2)); EXT4_EXT_MARK_UNWRIT2));
err = ext4_ext_get_access(handle, inode, path + depth); err = ext4_ext_get_access(handle, inode, path + depth);
if (err) if (err)
@ -3170,8 +3171,8 @@ static int ext4_split_extent_at(handle_t *handle,
* then we just change the state of the extent, and splitting * then we just change the state of the extent, and splitting
* is not needed. * is not needed.
*/ */
if (split_flag & EXT4_EXT_MARK_UNINIT2) if (split_flag & EXT4_EXT_MARK_UNWRIT2)
ext4_ext_mark_uninitialized(ex); ext4_ext_mark_unwritten(ex);
else else
ext4_ext_mark_initialized(ex); ext4_ext_mark_initialized(ex);
@ -3185,8 +3186,8 @@ static int ext4_split_extent_at(handle_t *handle,
/* case a */ /* case a */
memcpy(&orig_ex, ex, sizeof(orig_ex)); memcpy(&orig_ex, ex, sizeof(orig_ex));
ex->ee_len = cpu_to_le16(split - ee_block); ex->ee_len = cpu_to_le16(split - ee_block);
if (split_flag & EXT4_EXT_MARK_UNINIT1) if (split_flag & EXT4_EXT_MARK_UNWRIT1)
ext4_ext_mark_uninitialized(ex); ext4_ext_mark_unwritten(ex);
/* /*
* path may lead to new leaf, not to original leaf any more * path may lead to new leaf, not to original leaf any more
@ -3200,8 +3201,8 @@ static int ext4_split_extent_at(handle_t *handle,
ex2->ee_block = cpu_to_le32(split); ex2->ee_block = cpu_to_le32(split);
ex2->ee_len = cpu_to_le16(ee_len - (split - ee_block)); ex2->ee_len = cpu_to_le16(ee_len - (split - ee_block));
ext4_ext_store_pblock(ex2, newblock); ext4_ext_store_pblock(ex2, newblock);
if (split_flag & EXT4_EXT_MARK_UNINIT2) if (split_flag & EXT4_EXT_MARK_UNWRIT2)
ext4_ext_mark_uninitialized(ex2); ext4_ext_mark_unwritten(ex2);
err = ext4_ext_insert_extent(handle, inode, path, &newex, flags); err = ext4_ext_insert_extent(handle, inode, path, &newex, flags);
if (err == -ENOSPC && (EXT4_EXT_MAY_ZEROOUT & split_flag)) { if (err == -ENOSPC && (EXT4_EXT_MAY_ZEROOUT & split_flag)) {
@ -3278,7 +3279,7 @@ static int ext4_split_extent(handle_t *handle,
struct ext4_extent *ex; struct ext4_extent *ex;
unsigned int ee_len, depth; unsigned int ee_len, depth;
int err = 0; int err = 0;
int uninitialized; int unwritten;
int split_flag1, flags1; int split_flag1, flags1;
int allocated = map->m_len; int allocated = map->m_len;
@ -3286,14 +3287,14 @@ static int ext4_split_extent(handle_t *handle,
ex = path[depth].p_ext; ex = path[depth].p_ext;
ee_block = le32_to_cpu(ex->ee_block); ee_block = le32_to_cpu(ex->ee_block);
ee_len = ext4_ext_get_actual_len(ex); ee_len = ext4_ext_get_actual_len(ex);
uninitialized = ext4_ext_is_uninitialized(ex); unwritten = ext4_ext_is_unwritten(ex);
if (map->m_lblk + map->m_len < ee_block + ee_len) { if (map->m_lblk + map->m_len < ee_block + ee_len) {
split_flag1 = split_flag & EXT4_EXT_MAY_ZEROOUT; split_flag1 = split_flag & EXT4_EXT_MAY_ZEROOUT;
flags1 = flags | EXT4_GET_BLOCKS_PRE_IO; flags1 = flags | EXT4_GET_BLOCKS_PRE_IO;
if (uninitialized) if (unwritten)
split_flag1 |= EXT4_EXT_MARK_UNINIT1 | split_flag1 |= EXT4_EXT_MARK_UNWRIT1 |
EXT4_EXT_MARK_UNINIT2; EXT4_EXT_MARK_UNWRIT2;
if (split_flag & EXT4_EXT_DATA_VALID2) if (split_flag & EXT4_EXT_DATA_VALID2)
split_flag1 |= EXT4_EXT_DATA_VALID1; split_flag1 |= EXT4_EXT_DATA_VALID1;
err = ext4_split_extent_at(handle, inode, path, err = ext4_split_extent_at(handle, inode, path,
@ -3318,15 +3319,15 @@ static int ext4_split_extent(handle_t *handle,
(unsigned long) map->m_lblk); (unsigned long) map->m_lblk);
return -EIO; return -EIO;
} }
uninitialized = ext4_ext_is_uninitialized(ex); unwritten = ext4_ext_is_unwritten(ex);
split_flag1 = 0; split_flag1 = 0;
if (map->m_lblk >= ee_block) { if (map->m_lblk >= ee_block) {
split_flag1 = split_flag & EXT4_EXT_DATA_VALID2; split_flag1 = split_flag & EXT4_EXT_DATA_VALID2;
if (uninitialized) { if (unwritten) {
split_flag1 |= EXT4_EXT_MARK_UNINIT1; split_flag1 |= EXT4_EXT_MARK_UNWRIT1;
split_flag1 |= split_flag & (EXT4_EXT_MAY_ZEROOUT | split_flag1 |= split_flag & (EXT4_EXT_MAY_ZEROOUT |
EXT4_EXT_MARK_UNINIT2); EXT4_EXT_MARK_UNWRIT2);
} }
err = ext4_split_extent_at(handle, inode, path, err = ext4_split_extent_at(handle, inode, path,
map->m_lblk, split_flag1, flags); map->m_lblk, split_flag1, flags);
@ -3341,16 +3342,16 @@ out:
/* /*
* This function is called by ext4_ext_map_blocks() if someone tries to write * This function is called by ext4_ext_map_blocks() if someone tries to write
* to an uninitialized extent. It may result in splitting the uninitialized * to an unwritten extent. It may result in splitting the unwritten
* extent into multiple extents (up to three - one initialized and two * extent into multiple extents (up to three - one initialized and two
* uninitialized). * unwritten).
* There are three possibilities: * There are three possibilities:
* a> There is no split required: Entire extent should be initialized * 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 * 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 * c> Splits in three extents: Somone is writing in middle of the extent
* *
* Pre-conditions: * Pre-conditions:
* - The extent pointed to by 'path' is uninitialized. * - The extent pointed to by 'path' is unwritten.
* - The extent pointed to by 'path' contains a superset * - The extent pointed to by 'path' contains a superset
* of the logical span [map->m_lblk, map->m_lblk + map->m_len). * of the logical span [map->m_lblk, map->m_lblk + map->m_len).
* *
@ -3396,12 +3397,12 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
trace_ext4_ext_convert_to_initialized_enter(inode, map, ex); trace_ext4_ext_convert_to_initialized_enter(inode, map, ex);
/* Pre-conditions */ /* Pre-conditions */
BUG_ON(!ext4_ext_is_uninitialized(ex)); BUG_ON(!ext4_ext_is_unwritten(ex));
BUG_ON(!in_range(map->m_lblk, ee_block, ee_len)); BUG_ON(!in_range(map->m_lblk, ee_block, ee_len));
/* /*
* Attempt to transfer newly initialized blocks from the currently * Attempt to transfer newly initialized blocks from the currently
* uninitialized extent to its neighbor. This is much cheaper * unwritten extent to its neighbor. This is much cheaper
* than an insertion followed by a merge as those involve costly * than an insertion followed by a merge as those involve costly
* memmove() calls. Transferring to the left is the common case in * memmove() calls. Transferring to the left is the common case in
* steady state for workloads doing fallocate(FALLOC_FL_KEEP_SIZE) * steady state for workloads doing fallocate(FALLOC_FL_KEEP_SIZE)
@ -3437,7 +3438,7 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
* - C4: abut_ex can receive the additional blocks without * - C4: abut_ex can receive the additional blocks without
* overflowing the (initialized) length limit. * overflowing the (initialized) length limit.
*/ */
if ((!ext4_ext_is_uninitialized(abut_ex)) && /*C1*/ if ((!ext4_ext_is_unwritten(abut_ex)) && /*C1*/
((prev_lblk + prev_len) == ee_block) && /*C2*/ ((prev_lblk + prev_len) == ee_block) && /*C2*/
((prev_pblk + prev_len) == ee_pblk) && /*C3*/ ((prev_pblk + prev_len) == ee_pblk) && /*C3*/
(prev_len < (EXT_INIT_MAX_LEN - map_len))) { /*C4*/ (prev_len < (EXT_INIT_MAX_LEN - map_len))) { /*C4*/
@ -3452,7 +3453,7 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
ex->ee_block = cpu_to_le32(ee_block + map_len); ex->ee_block = cpu_to_le32(ee_block + map_len);
ext4_ext_store_pblock(ex, ee_pblk + map_len); ext4_ext_store_pblock(ex, ee_pblk + map_len);
ex->ee_len = cpu_to_le16(ee_len - map_len); ex->ee_len = cpu_to_le16(ee_len - map_len);
ext4_ext_mark_uninitialized(ex); /* Restore the flag */ ext4_ext_mark_unwritten(ex); /* Restore the flag */
/* Extend abut_ex by 'map_len' blocks */ /* Extend abut_ex by 'map_len' blocks */
abut_ex->ee_len = cpu_to_le16(prev_len + map_len); abut_ex->ee_len = cpu_to_le16(prev_len + map_len);
@ -3483,7 +3484,7 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
* - C4: abut_ex can receive the additional blocks without * - C4: abut_ex can receive the additional blocks without
* overflowing the (initialized) length limit. * overflowing the (initialized) length limit.
*/ */
if ((!ext4_ext_is_uninitialized(abut_ex)) && /*C1*/ if ((!ext4_ext_is_unwritten(abut_ex)) && /*C1*/
((map->m_lblk + map_len) == next_lblk) && /*C2*/ ((map->m_lblk + map_len) == next_lblk) && /*C2*/
((ee_pblk + ee_len) == next_pblk) && /*C3*/ ((ee_pblk + ee_len) == next_pblk) && /*C3*/
(next_len < (EXT_INIT_MAX_LEN - map_len))) { /*C4*/ (next_len < (EXT_INIT_MAX_LEN - map_len))) { /*C4*/
@ -3498,7 +3499,7 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
abut_ex->ee_block = cpu_to_le32(next_lblk - map_len); abut_ex->ee_block = cpu_to_le32(next_lblk - map_len);
ext4_ext_store_pblock(abut_ex, next_pblk - map_len); ext4_ext_store_pblock(abut_ex, next_pblk - map_len);
ex->ee_len = cpu_to_le16(ee_len - map_len); ex->ee_len = cpu_to_le16(ee_len - map_len);
ext4_ext_mark_uninitialized(ex); /* Restore the flag */ ext4_ext_mark_unwritten(ex); /* Restore the flag */
/* Extend abut_ex by 'map_len' blocks */ /* Extend abut_ex by 'map_len' blocks */
abut_ex->ee_len = cpu_to_le16(next_len + map_len); abut_ex->ee_len = cpu_to_le16(next_len + map_len);
@ -3603,26 +3604,26 @@ out:
/* /*
* This function is called by ext4_ext_map_blocks() from * This function is called by ext4_ext_map_blocks() from
* ext4_get_blocks_dio_write() when DIO to write * ext4_get_blocks_dio_write() when DIO to write
* to an uninitialized extent. * to an unwritten extent.
* *
* Writing to an uninitialized extent may result in splitting the uninitialized * Writing to an unwritten extent may result in splitting the unwritten
* extent into multiple initialized/uninitialized extents (up to three) * extent into multiple initialized/unwritten extents (up to three)
* There are three possibilities: * There are three possibilities:
* a> There is no split required: Entire extent should be uninitialized * a> There is no split required: Entire extent should be unwritten
* b> Splits in two extents: Write is happening at either end of the extent * 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 * c> Splits in three extents: Somone is writing in middle of the extent
* *
* This works the same way in the case of initialized -> unwritten conversion. * This works the same way in the case of initialized -> unwritten conversion.
* *
* One of more index blocks maybe needed if the extent tree grow after * One of more index blocks maybe needed if the extent tree grow after
* the uninitialized extent split. To prevent ENOSPC occur at the IO * the unwritten extent split. To prevent ENOSPC occur at the IO
* complete, we need to split the uninitialized extent before DIO submit * complete, we need to split the unwritten extent before DIO submit
* the IO. The uninitialized extent called at this time will be split * the IO. The unwritten extent called at this time will be split
* into three uninitialized extent(at most). After IO complete, the part * into three unwritten extent(at most). After IO complete, the part
* being filled will be convert to initialized by the end_io callback function * being filled will be convert to initialized by the end_io callback function
* via ext4_convert_unwritten_extents(). * via ext4_convert_unwritten_extents().
* *
* Returns the size of uninitialized extent to be written on success. * Returns the size of unwritten extent to be written on success.
*/ */
static int ext4_split_convert_extents(handle_t *handle, static int ext4_split_convert_extents(handle_t *handle,
struct inode *inode, struct inode *inode,
@ -3660,7 +3661,7 @@ static int ext4_split_convert_extents(handle_t *handle,
} else if (flags & EXT4_GET_BLOCKS_CONVERT) { } else if (flags & EXT4_GET_BLOCKS_CONVERT) {
split_flag |= ee_block + ee_len <= eof_block ? split_flag |= ee_block + ee_len <= eof_block ?
EXT4_EXT_MAY_ZEROOUT : 0; EXT4_EXT_MAY_ZEROOUT : 0;
split_flag |= (EXT4_EXT_MARK_UNINIT2 | EXT4_EXT_DATA_VALID2); split_flag |= (EXT4_EXT_MARK_UNWRIT2 | EXT4_EXT_DATA_VALID2);
} }
flags |= EXT4_GET_BLOCKS_PRE_IO; flags |= EXT4_GET_BLOCKS_PRE_IO;
return ext4_split_extent(handle, inode, path, map, split_flag, flags); return ext4_split_extent(handle, inode, path, map, split_flag, flags);
@ -3710,8 +3711,8 @@ static int ext4_convert_initialized_extents(handle_t *handle,
err = ext4_ext_get_access(handle, inode, path + depth); err = ext4_ext_get_access(handle, inode, path + depth);
if (err) if (err)
goto out; goto out;
/* first mark the extent as uninitialized */ /* first mark the extent as unwritten */
ext4_ext_mark_uninitialized(ex); ext4_ext_mark_unwritten(ex);
/* note: ext4_ext_correct_indexes() isn't needed here because /* note: ext4_ext_correct_indexes() isn't needed here because
* borders are not changed * borders are not changed
@ -3971,10 +3972,10 @@ ext4_ext_convert_initialized_extent(handle_t *handle, struct inode *inode,
/* /*
* Make sure that the extent is no bigger than we support with * Make sure that the extent is no bigger than we support with
* uninitialized extent * unwritten extent
*/ */
if (map->m_len > EXT_UNINIT_MAX_LEN) if (map->m_len > EXT_UNWRITTEN_MAX_LEN)
map->m_len = EXT_UNINIT_MAX_LEN / 2; map->m_len = EXT_UNWRITTEN_MAX_LEN / 2;
ret = ext4_convert_initialized_extents(handle, inode, map, ret = ext4_convert_initialized_extents(handle, inode, map,
path); path);
@ -3993,7 +3994,7 @@ ext4_ext_convert_initialized_extent(handle_t *handle, struct inode *inode,
} }
static int static int
ext4_ext_handle_uninitialized_extents(handle_t *handle, struct inode *inode, ext4_ext_handle_unwritten_extents(handle_t *handle, struct inode *inode,
struct ext4_map_blocks *map, struct ext4_map_blocks *map,
struct ext4_ext_path *path, int flags, struct ext4_ext_path *path, int flags,
unsigned int allocated, ext4_fsblk_t newblock) unsigned int allocated, ext4_fsblk_t newblock)
@ -4002,23 +4003,23 @@ ext4_ext_handle_uninitialized_extents(handle_t *handle, struct inode *inode,
int err = 0; int err = 0;
ext4_io_end_t *io = ext4_inode_aio(inode); ext4_io_end_t *io = ext4_inode_aio(inode);
ext_debug("ext4_ext_handle_uninitialized_extents: inode %lu, logical " ext_debug("ext4_ext_handle_unwritten_extents: inode %lu, logical "
"block %llu, max_blocks %u, flags %x, allocated %u\n", "block %llu, max_blocks %u, flags %x, allocated %u\n",
inode->i_ino, (unsigned long long)map->m_lblk, map->m_len, inode->i_ino, (unsigned long long)map->m_lblk, map->m_len,
flags, allocated); flags, allocated);
ext4_ext_show_leaf(inode, path); ext4_ext_show_leaf(inode, path);
/* /*
* When writing into uninitialized space, we should not fail to * When writing into unwritten space, we should not fail to
* allocate metadata blocks for the new extent block if needed. * allocate metadata blocks for the new extent block if needed.
*/ */
flags |= EXT4_GET_BLOCKS_METADATA_NOFAIL; flags |= EXT4_GET_BLOCKS_METADATA_NOFAIL;
trace_ext4_ext_handle_uninitialized_extents(inode, map, flags, trace_ext4_ext_handle_unwritten_extents(inode, map, flags,
allocated, newblock); allocated, newblock);
/* get_block() before submit the IO, split the extent */ /* get_block() before submit the IO, split the extent */
if ((flags & EXT4_GET_BLOCKS_PRE_IO)) { if (flags & EXT4_GET_BLOCKS_PRE_IO) {
ret = ext4_split_convert_extents(handle, inode, map, ret = ext4_split_convert_extents(handle, inode, map,
path, flags | EXT4_GET_BLOCKS_CONVERT); path, flags | EXT4_GET_BLOCKS_CONVERT);
if (ret <= 0) if (ret <= 0)
@ -4033,12 +4034,10 @@ ext4_ext_handle_uninitialized_extents(handle_t *handle, struct inode *inode,
else else
ext4_set_inode_state(inode, EXT4_STATE_DIO_UNWRITTEN); ext4_set_inode_state(inode, EXT4_STATE_DIO_UNWRITTEN);
map->m_flags |= EXT4_MAP_UNWRITTEN; map->m_flags |= EXT4_MAP_UNWRITTEN;
if (ext4_should_dioread_nolock(inode))
map->m_flags |= EXT4_MAP_UNINIT;
goto out; goto out;
} }
/* IO end_io complete, convert the filled extent to written */ /* IO end_io complete, convert the filled extent to written */
if ((flags & EXT4_GET_BLOCKS_CONVERT)) { if (flags & EXT4_GET_BLOCKS_CONVERT) {
ret = ext4_convert_unwritten_extents_endio(handle, inode, map, ret = ext4_convert_unwritten_extents_endio(handle, inode, map,
path); path);
if (ret >= 0) { if (ret >= 0) {
@ -4059,7 +4058,7 @@ ext4_ext_handle_uninitialized_extents(handle_t *handle, struct inode *inode,
* repeat fallocate creation request * repeat fallocate creation request
* we already have an unwritten extent * we already have an unwritten extent
*/ */
if (flags & EXT4_GET_BLOCKS_UNINIT_EXT) { if (flags & EXT4_GET_BLOCKS_UNWRIT_EXT) {
map->m_flags |= EXT4_MAP_UNWRITTEN; map->m_flags |= EXT4_MAP_UNWRITTEN;
goto map_out; goto map_out;
} }
@ -4310,7 +4309,7 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
/* /*
* Uninitialized extents are treated as holes, except that * unwritten extents are treated as holes, except that
* we split out initialized portions during a write. * we split out initialized portions during a write.
*/ */
ee_len = ext4_ext_get_actual_len(ex); ee_len = ext4_ext_get_actual_len(ex);
@ -4329,16 +4328,16 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
* If the extent is initialized check whether the * If the extent is initialized check whether the
* caller wants to convert it to unwritten. * caller wants to convert it to unwritten.
*/ */
if ((!ext4_ext_is_uninitialized(ex)) && if ((!ext4_ext_is_unwritten(ex)) &&
(flags & EXT4_GET_BLOCKS_CONVERT_UNWRITTEN)) { (flags & EXT4_GET_BLOCKS_CONVERT_UNWRITTEN)) {
allocated = ext4_ext_convert_initialized_extent( allocated = ext4_ext_convert_initialized_extent(
handle, inode, map, path, flags, handle, inode, map, path, flags,
allocated, newblock); allocated, newblock);
goto out2; goto out2;
} else if (!ext4_ext_is_uninitialized(ex)) } else if (!ext4_ext_is_unwritten(ex))
goto out; goto out;
ret = ext4_ext_handle_uninitialized_extents( ret = ext4_ext_handle_unwritten_extents(
handle, inode, map, path, flags, handle, inode, map, path, flags,
allocated, newblock); allocated, newblock);
if (ret < 0) if (ret < 0)
@ -4410,15 +4409,15 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
/* /*
* See if request is beyond maximum number of blocks we can have in * See if request is beyond maximum number of blocks we can have in
* a single extent. For an initialized extent this limit is * a single extent. For an initialized extent this limit is
* EXT_INIT_MAX_LEN and for an uninitialized extent this limit is * EXT_INIT_MAX_LEN and for an unwritten extent this limit is
* EXT_UNINIT_MAX_LEN. * EXT_UNWRITTEN_MAX_LEN.
*/ */
if (map->m_len > EXT_INIT_MAX_LEN && if (map->m_len > EXT_INIT_MAX_LEN &&
!(flags & EXT4_GET_BLOCKS_UNINIT_EXT)) !(flags & EXT4_GET_BLOCKS_UNWRIT_EXT))
map->m_len = EXT_INIT_MAX_LEN; map->m_len = EXT_INIT_MAX_LEN;
else if (map->m_len > EXT_UNINIT_MAX_LEN && else if (map->m_len > EXT_UNWRITTEN_MAX_LEN &&
(flags & EXT4_GET_BLOCKS_UNINIT_EXT)) (flags & EXT4_GET_BLOCKS_UNWRIT_EXT))
map->m_len = EXT_UNINIT_MAX_LEN; map->m_len = EXT_UNWRITTEN_MAX_LEN;
/* Check if we can really insert (m_lblk)::(m_lblk + m_len) extent */ /* Check if we can really insert (m_lblk)::(m_lblk + m_len) extent */
newex.ee_len = cpu_to_le16(map->m_len); newex.ee_len = cpu_to_le16(map->m_len);
@ -4466,21 +4465,19 @@ got_allocated_blocks:
/* try to insert new extent into found leaf and return */ /* try to insert new extent into found leaf and return */
ext4_ext_store_pblock(&newex, newblock + offset); ext4_ext_store_pblock(&newex, newblock + offset);
newex.ee_len = cpu_to_le16(ar.len); newex.ee_len = cpu_to_le16(ar.len);
/* Mark uninitialized */ /* Mark unwritten */
if (flags & EXT4_GET_BLOCKS_UNINIT_EXT){ if (flags & EXT4_GET_BLOCKS_UNWRIT_EXT){
ext4_ext_mark_uninitialized(&newex); ext4_ext_mark_unwritten(&newex);
map->m_flags |= EXT4_MAP_UNWRITTEN; map->m_flags |= EXT4_MAP_UNWRITTEN;
/* /*
* io_end structure was created for every IO write to an * io_end structure was created for every IO write to an
* uninitialized extent. To avoid unnecessary conversion, * unwritten extent. To avoid unnecessary conversion,
* here we flag the IO that really needs the conversion. * here we flag the IO that really needs the conversion.
* For non asycn direct IO case, flag the inode state * For non asycn direct IO case, flag the inode state
* that we need to perform conversion when IO is done. * that we need to perform conversion when IO is done.
*/ */
if ((flags & EXT4_GET_BLOCKS_PRE_IO)) if (flags & EXT4_GET_BLOCKS_PRE_IO)
set_unwritten = 1; set_unwritten = 1;
if (ext4_should_dioread_nolock(inode))
map->m_flags |= EXT4_MAP_UNINIT;
} }
err = 0; err = 0;
@ -4607,9 +4604,9 @@ got_allocated_blocks:
/* /*
* Cache the extent and update transaction to commit on fdatasync only * Cache the extent and update transaction to commit on fdatasync only
* when it is _not_ an uninitialized extent. * when it is _not_ an unwritten extent.
*/ */
if ((flags & EXT4_GET_BLOCKS_UNINIT_EXT) == 0) if ((flags & EXT4_GET_BLOCKS_UNWRIT_EXT) == 0)
ext4_update_inode_fsync_trans(handle, inode, 1); ext4_update_inode_fsync_trans(handle, inode, 1);
else else
ext4_update_inode_fsync_trans(handle, inode, 0); ext4_update_inode_fsync_trans(handle, inode, 0);
@ -4683,7 +4680,7 @@ static int ext4_alloc_file_blocks(struct file *file, ext4_lblk_t offset,
* that it doesn't get unnecessarily split into multiple * that it doesn't get unnecessarily split into multiple
* extents. * extents.
*/ */
if (len <= EXT_UNINIT_MAX_LEN) if (len <= EXT_UNWRITTEN_MAX_LEN)
flags |= EXT4_GET_BLOCKS_NO_NORMALIZE; flags |= EXT4_GET_BLOCKS_NO_NORMALIZE;
/* /*
@ -4744,6 +4741,13 @@ static long ext4_zero_range(struct file *file, loff_t offset,
if (!S_ISREG(inode->i_mode)) if (!S_ISREG(inode->i_mode))
return -EINVAL; return -EINVAL;
/* 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;
}
/* /*
* Write out all dirty pages to avoid race conditions * Write out all dirty pages to avoid race conditions
* Then release them. * Then release them.
@ -4775,7 +4779,7 @@ static long ext4_zero_range(struct file *file, loff_t offset,
else else
max_blocks -= lblk; max_blocks -= lblk;
flags = EXT4_GET_BLOCKS_CREATE_UNINIT_EXT | flags = EXT4_GET_BLOCKS_CREATE_UNWRIT_EXT |
EXT4_GET_BLOCKS_CONVERT_UNWRITTEN; EXT4_GET_BLOCKS_CONVERT_UNWRITTEN;
if (mode & FALLOC_FL_KEEP_SIZE) if (mode & FALLOC_FL_KEEP_SIZE)
flags |= EXT4_GET_BLOCKS_KEEP_SIZE; flags |= EXT4_GET_BLOCKS_KEEP_SIZE;
@ -4918,7 +4922,7 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
max_blocks = (EXT4_BLOCK_ALIGN(len + offset, blkbits) >> blkbits) max_blocks = (EXT4_BLOCK_ALIGN(len + offset, blkbits) >> blkbits)
- lblk; - lblk;
flags = EXT4_GET_BLOCKS_CREATE_UNINIT_EXT; flags = EXT4_GET_BLOCKS_CREATE_UNWRIT_EXT;
if (mode & FALLOC_FL_KEEP_SIZE) if (mode & FALLOC_FL_KEEP_SIZE)
flags |= EXT4_GET_BLOCKS_KEEP_SIZE; flags |= EXT4_GET_BLOCKS_KEEP_SIZE;

View file

@ -344,8 +344,14 @@ static int ext4_es_can_be_merged(struct extent_status *es1,
if (ext4_es_status(es1) != ext4_es_status(es2)) if (ext4_es_status(es1) != ext4_es_status(es2))
return 0; return 0;
if (((__u64) es1->es_len) + es2->es_len > 0xFFFFFFFFULL) if (((__u64) es1->es_len) + es2->es_len > EXT_MAX_BLOCKS) {
pr_warn("ES assertion failed when merging extents. "
"The sum of lengths of es1 (%d) and es2 (%d) "
"is bigger than allowed file size (%d)\n",
es1->es_len, es2->es_len, EXT_MAX_BLOCKS);
WARN_ON(1);
return 0; return 0;
}
if (((__u64) es1->es_lblk) + es1->es_len != es2->es_lblk) if (((__u64) es1->es_lblk) + es1->es_len != es2->es_lblk)
return 0; return 0;
@ -433,7 +439,7 @@ static void ext4_es_insert_extent_ext_check(struct inode *inode,
ee_start = ext4_ext_pblock(ex); ee_start = ext4_ext_pblock(ex);
ee_len = ext4_ext_get_actual_len(ex); ee_len = ext4_ext_get_actual_len(ex);
ee_status = ext4_ext_is_uninitialized(ex) ? 1 : 0; ee_status = ext4_ext_is_unwritten(ex) ? 1 : 0;
es_status = ext4_es_is_unwritten(es) ? 1 : 0; es_status = ext4_es_is_unwritten(es) ? 1 : 0;
/* /*

View file

@ -57,7 +57,7 @@ static int ext4_release_file(struct inode *inode, struct file *filp)
return 0; return 0;
} }
void ext4_unwritten_wait(struct inode *inode) static void ext4_unwritten_wait(struct inode *inode)
{ {
wait_queue_head_t *wq = ext4_ioend_wq(inode); wait_queue_head_t *wq = ext4_ioend_wq(inode);
@ -92,36 +92,65 @@ ext4_unaligned_aio(struct inode *inode, const struct iovec *iov,
} }
static ssize_t static ssize_t
ext4_file_dio_write(struct kiocb *iocb, const struct iovec *iov, ext4_file_write(struct kiocb *iocb, const struct iovec *iov,
unsigned long nr_segs, loff_t pos) unsigned long nr_segs, loff_t pos)
{ {
struct file *file = iocb->ki_filp; struct file *file = iocb->ki_filp;
struct inode *inode = file->f_mapping->host; struct inode *inode = file_inode(iocb->ki_filp);
struct mutex *aio_mutex = NULL;
struct blk_plug plug; struct blk_plug plug;
int unaligned_aio = 0; int o_direct = file->f_flags & O_DIRECT;
ssize_t ret;
int overwrite = 0; int overwrite = 0;
size_t length = iov_length(iov, nr_segs); size_t length = iov_length(iov, nr_segs);
ssize_t ret;
if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS) &&
!is_sync_kiocb(iocb))
unaligned_aio = ext4_unaligned_aio(inode, iov, nr_segs, pos);
/* Unaligned direct AIO must be serialized; see comment above */
if (unaligned_aio) {
mutex_lock(ext4_aio_mutex(inode));
ext4_unwritten_wait(inode);
}
BUG_ON(iocb->ki_pos != pos); BUG_ON(iocb->ki_pos != pos);
/*
* Unaligned direct AIO must be serialized; see comment above
* In the case of O_APPEND, assume that we must always serialize
*/
if (o_direct &&
ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS) &&
!is_sync_kiocb(iocb) &&
(file->f_flags & O_APPEND ||
ext4_unaligned_aio(inode, iov, nr_segs, pos))) {
aio_mutex = ext4_aio_mutex(inode);
mutex_lock(aio_mutex);
ext4_unwritten_wait(inode);
}
mutex_lock(&inode->i_mutex); mutex_lock(&inode->i_mutex);
if (file->f_flags & O_APPEND)
iocb->ki_pos = pos = i_size_read(inode);
/*
* If we have encountered a bitmap-format file, the size limit
* is smaller than s_maxbytes, which is for extent-mapped files.
*/
if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))) {
struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
if ((pos > sbi->s_bitmap_maxbytes) ||
(pos == sbi->s_bitmap_maxbytes && length > 0)) {
mutex_unlock(&inode->i_mutex);
ret = -EFBIG;
goto errout;
}
if (pos + length > sbi->s_bitmap_maxbytes) {
nr_segs = iov_shorten((struct iovec *)iov, nr_segs,
sbi->s_bitmap_maxbytes - pos);
}
}
if (o_direct) {
blk_start_plug(&plug); blk_start_plug(&plug);
iocb->private = &overwrite; iocb->private = &overwrite;
/* check whether we do a DIO overwrite or not */ /* check whether we do a DIO overwrite or not */
if (ext4_should_dioread_nolock(inode) && !unaligned_aio && if (ext4_should_dioread_nolock(inode) && !aio_mutex &&
!file->f_mapping->nrpages && pos + length <= i_size_read(inode)) { !file->f_mapping->nrpages && pos + length <= i_size_read(inode)) {
struct ext4_map_blocks map; struct ext4_map_blocks map;
unsigned int blkbits = inode->i_blkbits; unsigned int blkbits = inode->i_blkbits;
@ -134,17 +163,21 @@ ext4_file_dio_write(struct kiocb *iocb, const struct iovec *iov,
err = ext4_map_blocks(NULL, inode, &map, 0); err = ext4_map_blocks(NULL, inode, &map, 0);
/* /*
* 'err==len' means that all of blocks has been preallocated no * 'err==len' means that all of blocks has
* matter they are initialized or not. For excluding * been preallocated no matter they are
* uninitialized extents, we need to check m_flags. There are * initialized or not. For excluding
* two conditions that indicate for initialized extents. * unwritten extents, we need to check
* 1) If we hit extent cache, EXT4_MAP_MAPPED flag is returned; * m_flags. There are two conditions that
* 2) If we do a real lookup, non-flags are returned. * indicate for initialized extents. 1) If we
* So we should check these two conditions. * hit extent cache, EXT4_MAP_MAPPED flag is
* returned; 2) If we do a real lookup,
* non-flags are returned. So we should check
* these two conditions.
*/ */
if (err == len && (map.m_flags & EXT4_MAP_MAPPED)) if (err == len && (map.m_flags & EXT4_MAP_MAPPED))
overwrite = 1; overwrite = 1;
} }
}
ret = __generic_file_aio_write(iocb, iov, nr_segs); ret = __generic_file_aio_write(iocb, iov, nr_segs);
mutex_unlock(&inode->i_mutex); mutex_unlock(&inode->i_mutex);
@ -156,45 +189,12 @@ ext4_file_dio_write(struct kiocb *iocb, const struct iovec *iov,
if (err < 0) if (err < 0)
ret = err; ret = err;
} }
if (o_direct)
blk_finish_plug(&plug); blk_finish_plug(&plug);
if (unaligned_aio) errout:
mutex_unlock(ext4_aio_mutex(inode)); if (aio_mutex)
mutex_unlock(aio_mutex);
return ret;
}
static ssize_t
ext4_file_write(struct kiocb *iocb, const struct iovec *iov,
unsigned long nr_segs, loff_t pos)
{
struct inode *inode = file_inode(iocb->ki_filp);
ssize_t ret;
/*
* If we have encountered a bitmap-format file, the size limit
* is smaller than s_maxbytes, which is for extent-mapped files.
*/
if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))) {
struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
size_t length = iov_length(iov, nr_segs);
if ((pos > sbi->s_bitmap_maxbytes ||
(pos == sbi->s_bitmap_maxbytes && length > 0)))
return -EFBIG;
if (pos + length > sbi->s_bitmap_maxbytes) {
nr_segs = iov_shorten((struct iovec *)iov, nr_segs,
sbi->s_bitmap_maxbytes - pos);
}
}
if (unlikely(iocb->ki_filp->f_flags & O_DIRECT))
ret = ext4_file_dio_write(iocb, iov, nr_segs, pos);
else
ret = generic_file_aio_write(iocb, iov, nr_segs, pos);
return ret; return ret;
} }
@ -244,6 +244,7 @@ static int ext4_file_open(struct inode * inode, struct file * filp)
handle = ext4_journal_start_sb(sb, EXT4_HT_MISC, 1); handle = ext4_journal_start_sb(sb, EXT4_HT_MISC, 1);
if (IS_ERR(handle)) if (IS_ERR(handle))
return PTR_ERR(handle); return PTR_ERR(handle);
BUFFER_TRACE(sbi->s_sbh, "get_write_access");
err = ext4_journal_get_write_access(handle, sbi->s_sbh); err = ext4_journal_get_write_access(handle, sbi->s_sbh);
if (err) { if (err) {
ext4_journal_stop(handle); ext4_journal_stop(handle);

View file

@ -22,7 +22,7 @@
#define EXT4_INLINE_DOTDOT_OFFSET 2 #define EXT4_INLINE_DOTDOT_OFFSET 2
#define EXT4_INLINE_DOTDOT_SIZE 4 #define EXT4_INLINE_DOTDOT_SIZE 4
int ext4_get_inline_size(struct inode *inode) static int ext4_get_inline_size(struct inode *inode)
{ {
if (EXT4_I(inode)->i_inline_off) if (EXT4_I(inode)->i_inline_off)
return EXT4_I(inode)->i_inline_size; return EXT4_I(inode)->i_inline_size;
@ -211,7 +211,7 @@ out:
* value since it is already handled by ext4_xattr_ibody_inline_set. * value since it is already handled by ext4_xattr_ibody_inline_set.
* That saves us one memcpy. * That saves us one memcpy.
*/ */
void ext4_write_inline_data(struct inode *inode, struct ext4_iloc *iloc, static void ext4_write_inline_data(struct inode *inode, struct ext4_iloc *iloc,
void *buffer, loff_t pos, unsigned int len) void *buffer, loff_t pos, unsigned int len)
{ {
struct ext4_xattr_entry *entry; struct ext4_xattr_entry *entry;
@ -264,6 +264,7 @@ static int ext4_create_inline_data(handle_t *handle,
if (error) if (error)
return error; return error;
BUFFER_TRACE(is.iloc.bh, "get_write_access");
error = ext4_journal_get_write_access(handle, is.iloc.bh); error = ext4_journal_get_write_access(handle, is.iloc.bh);
if (error) if (error)
goto out; goto out;
@ -347,6 +348,7 @@ static int ext4_update_inline_data(handle_t *handle, struct inode *inode,
if (error == -ENODATA) if (error == -ENODATA)
goto out; goto out;
BUFFER_TRACE(is.iloc.bh, "get_write_access");
error = ext4_journal_get_write_access(handle, is.iloc.bh); error = ext4_journal_get_write_access(handle, is.iloc.bh);
if (error) if (error)
goto out; goto out;
@ -373,7 +375,7 @@ out:
return error; return error;
} }
int ext4_prepare_inline_data(handle_t *handle, struct inode *inode, static int ext4_prepare_inline_data(handle_t *handle, struct inode *inode,
unsigned int len) unsigned int len)
{ {
int ret, size; int ret, size;
@ -424,6 +426,7 @@ static int ext4_destroy_inline_data_nolock(handle_t *handle,
if (error) if (error)
goto out; goto out;
BUFFER_TRACE(is.iloc.bh, "get_write_access");
error = ext4_journal_get_write_access(handle, is.iloc.bh); error = ext4_journal_get_write_access(handle, is.iloc.bh);
if (error) if (error)
goto out; goto out;
@ -1007,6 +1010,7 @@ static int ext4_add_dirent_to_inline(handle_t *handle,
if (err) if (err)
return err; return err;
BUFFER_TRACE(iloc->bh, "get_write_access");
err = ext4_journal_get_write_access(handle, iloc->bh); err = ext4_journal_get_write_access(handle, iloc->bh);
if (err) if (err)
return err; return err;
@ -1669,6 +1673,7 @@ int ext4_delete_inline_entry(handle_t *handle,
EXT4_MIN_INLINE_DATA_SIZE; EXT4_MIN_INLINE_DATA_SIZE;
} }
BUFFER_TRACE(bh, "get_write_access");
err = ext4_journal_get_write_access(handle, bh); err = ext4_journal_get_write_access(handle, bh);
if (err) if (err)
goto out; goto out;

View file

@ -148,6 +148,9 @@ static int ext4_inode_is_fast_symlink(struct inode *inode)
int ea_blocks = EXT4_I(inode)->i_file_acl ? int ea_blocks = EXT4_I(inode)->i_file_acl ?
EXT4_CLUSTER_SIZE(inode->i_sb) >> 9 : 0; EXT4_CLUSTER_SIZE(inode->i_sb) >> 9 : 0;
if (ext4_has_inline_data(inode))
return 0;
return (S_ISLNK(inode->i_mode) && inode->i_blocks - ea_blocks == 0); return (S_ISLNK(inode->i_mode) && inode->i_blocks - ea_blocks == 0);
} }
@ -443,7 +446,7 @@ static void ext4_map_blocks_es_recheck(handle_t *handle,
* could be converted. * could be converted.
*/ */
if (!(flags & EXT4_GET_BLOCKS_NO_LOCK)) if (!(flags & EXT4_GET_BLOCKS_NO_LOCK))
down_read((&EXT4_I(inode)->i_data_sem)); down_read(&EXT4_I(inode)->i_data_sem);
if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) { if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) {
retval = ext4_ext_map_blocks(handle, inode, map, flags & retval = ext4_ext_map_blocks(handle, inode, map, flags &
EXT4_GET_BLOCKS_KEEP_SIZE); EXT4_GET_BLOCKS_KEEP_SIZE);
@ -489,8 +492,8 @@ static void ext4_map_blocks_es_recheck(handle_t *handle,
* Otherwise, call with ext4_ind_map_blocks() to handle indirect mapping * Otherwise, call with ext4_ind_map_blocks() to handle indirect mapping
* based files * based files
* *
* On success, it returns the number of blocks being mapped or allocate. * On success, it returns the number of blocks being mapped or allocated.
* if create==0 and the blocks are pre-allocated and uninitialized block, * if create==0 and the blocks are pre-allocated and unwritten block,
* the result buffer head is unmapped. If the create ==1, it will make sure * the result buffer head is unmapped. If the create ==1, it will make sure
* the buffer head is mapped. * the buffer head is mapped.
* *
@ -555,7 +558,7 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode,
* file system block. * file system block.
*/ */
if (!(flags & EXT4_GET_BLOCKS_NO_LOCK)) if (!(flags & EXT4_GET_BLOCKS_NO_LOCK))
down_read((&EXT4_I(inode)->i_data_sem)); down_read(&EXT4_I(inode)->i_data_sem);
if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) { if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) {
retval = ext4_ext_map_blocks(handle, inode, map, flags & retval = ext4_ext_map_blocks(handle, inode, map, flags &
EXT4_GET_BLOCKS_KEEP_SIZE); EXT4_GET_BLOCKS_KEEP_SIZE);
@ -622,12 +625,12 @@ found:
map->m_flags &= ~EXT4_MAP_FLAGS; map->m_flags &= ~EXT4_MAP_FLAGS;
/* /*
* New blocks allocate and/or writing to uninitialized extent * New blocks allocate and/or writing to unwritten extent
* will possibly result in updating i_data, so we take * will possibly result in updating i_data, so we take
* the write lock of i_data_sem, and call get_blocks() * the write lock of i_data_sem, and call get_blocks()
* with create == 1 flag. * with create == 1 flag.
*/ */
down_write((&EXT4_I(inode)->i_data_sem)); down_write(&EXT4_I(inode)->i_data_sem);
/* /*
* if the caller is from delayed allocation writeout path * if the caller is from delayed allocation writeout path
@ -922,6 +925,7 @@ int do_journal_get_write_access(handle_t *handle,
*/ */
if (dirty) if (dirty)
clear_buffer_dirty(bh); clear_buffer_dirty(bh);
BUFFER_TRACE(bh, "get write access");
ret = ext4_journal_get_write_access(handle, bh); ret = ext4_journal_get_write_access(handle, bh);
if (!ret && dirty) if (!ret && dirty)
ret = ext4_handle_dirty_metadata(handle, NULL, bh); ret = ext4_handle_dirty_metadata(handle, NULL, bh);
@ -1540,7 +1544,7 @@ static int ext4_da_map_blocks(struct inode *inode, sector_t iblock,
ext4_es_lru_add(inode); ext4_es_lru_add(inode);
if (ext4_es_is_hole(&es)) { if (ext4_es_is_hole(&es)) {
retval = 0; retval = 0;
down_read((&EXT4_I(inode)->i_data_sem)); down_read(&EXT4_I(inode)->i_data_sem);
goto add_delayed; goto add_delayed;
} }
@ -1577,7 +1581,7 @@ static int ext4_da_map_blocks(struct inode *inode, sector_t iblock,
* Try to see if we can get the block without requesting a new * Try to see if we can get the block without requesting a new
* file system block. * file system block.
*/ */
down_read((&EXT4_I(inode)->i_data_sem)); down_read(&EXT4_I(inode)->i_data_sem);
if (ext4_has_inline_data(inode)) { if (ext4_has_inline_data(inode)) {
/* /*
* We will soon create blocks for this page, and let * We will soon create blocks for this page, and let
@ -1769,6 +1773,7 @@ static int __ext4_journalled_writepage(struct page *page,
BUG_ON(!ext4_handle_valid(handle)); BUG_ON(!ext4_handle_valid(handle));
if (inline_data) { if (inline_data) {
BUFFER_TRACE(inode_bh, "get write access");
ret = ext4_journal_get_write_access(handle, inode_bh); ret = ext4_journal_get_write_access(handle, inode_bh);
err = ext4_handle_dirty_metadata(handle, inode, inode_bh); err = ext4_handle_dirty_metadata(handle, inode, inode_bh);
@ -1846,6 +1851,7 @@ static int ext4_writepage(struct page *page,
struct buffer_head *page_bufs = NULL; struct buffer_head *page_bufs = NULL;
struct inode *inode = page->mapping->host; struct inode *inode = page->mapping->host;
struct ext4_io_submit io_submit; struct ext4_io_submit io_submit;
bool keep_towrite = false;
trace_ext4_writepage(page); trace_ext4_writepage(page);
size = i_size_read(inode); size = i_size_read(inode);
@ -1876,6 +1882,7 @@ static int ext4_writepage(struct page *page,
unlock_page(page); unlock_page(page);
return 0; return 0;
} }
keep_towrite = true;
} }
if (PageChecked(page) && ext4_should_journal_data(inode)) if (PageChecked(page) && ext4_should_journal_data(inode))
@ -1892,7 +1899,7 @@ static int ext4_writepage(struct page *page,
unlock_page(page); unlock_page(page);
return -ENOMEM; return -ENOMEM;
} }
ret = ext4_bio_write_page(&io_submit, page, len, wbc); ret = ext4_bio_write_page(&io_submit, page, len, wbc, keep_towrite);
ext4_io_submit(&io_submit); ext4_io_submit(&io_submit);
/* Drop io_end reference we got from init */ /* Drop io_end reference we got from init */
ext4_put_io_end_defer(io_submit.io_end); ext4_put_io_end_defer(io_submit.io_end);
@ -1911,7 +1918,7 @@ static int mpage_submit_page(struct mpage_da_data *mpd, struct page *page)
else else
len = PAGE_CACHE_SIZE; len = PAGE_CACHE_SIZE;
clear_page_dirty_for_io(page); clear_page_dirty_for_io(page);
err = ext4_bio_write_page(&mpd->io_submit, page, len, mpd->wbc); err = ext4_bio_write_page(&mpd->io_submit, page, len, mpd->wbc, false);
if (!err) if (!err)
mpd->wbc->nr_to_write--; mpd->wbc->nr_to_write--;
mpd->first_page++; mpd->first_page++;
@ -2032,7 +2039,7 @@ static int mpage_process_page_bufs(struct mpage_da_data *mpd,
* Scan buffers corresponding to changed extent (we expect corresponding pages * Scan buffers corresponding to changed extent (we expect corresponding pages
* to be already locked) and update buffer state according to new extent state. * to be already locked) and update buffer state according to new extent state.
* We map delalloc buffers to their physical location, clear unwritten bits, * We map delalloc buffers to their physical location, clear unwritten bits,
* and mark buffers as uninit when we perform writes to uninitialized extents * and mark buffers as uninit when we perform writes to unwritten extents
* and do extent conversion after IO is finished. If the last page is not fully * and do extent conversion after IO is finished. If the last page is not fully
* mapped, we update @map to the next extent in the last page that needs * mapped, we update @map to the next extent in the last page that needs
* mapping. Otherwise we submit the page for IO. * mapping. Otherwise we submit the page for IO.
@ -2126,12 +2133,12 @@ static int mpage_map_one_extent(handle_t *handle, struct mpage_da_data *mpd)
struct inode *inode = mpd->inode; struct inode *inode = mpd->inode;
struct ext4_map_blocks *map = &mpd->map; struct ext4_map_blocks *map = &mpd->map;
int get_blocks_flags; int get_blocks_flags;
int err; int err, dioread_nolock;
trace_ext4_da_write_pages_extent(inode, map); trace_ext4_da_write_pages_extent(inode, map);
/* /*
* Call ext4_map_blocks() to allocate any delayed allocation blocks, or * Call ext4_map_blocks() to allocate any delayed allocation blocks, or
* to convert an uninitialized extent to be initialized (in the case * to convert an unwritten extent to be initialized (in the case
* where we have written into one or more preallocated blocks). It is * where we have written into one or more preallocated blocks). It is
* possible that we're going to need more metadata blocks than * possible that we're going to need more metadata blocks than
* previously reserved. However we must not fail because we're in * previously reserved. However we must not fail because we're in
@ -2148,7 +2155,8 @@ static int mpage_map_one_extent(handle_t *handle, struct mpage_da_data *mpd)
*/ */
get_blocks_flags = EXT4_GET_BLOCKS_CREATE | get_blocks_flags = EXT4_GET_BLOCKS_CREATE |
EXT4_GET_BLOCKS_METADATA_NOFAIL; EXT4_GET_BLOCKS_METADATA_NOFAIL;
if (ext4_should_dioread_nolock(inode)) dioread_nolock = ext4_should_dioread_nolock(inode);
if (dioread_nolock)
get_blocks_flags |= EXT4_GET_BLOCKS_IO_CREATE_EXT; get_blocks_flags |= EXT4_GET_BLOCKS_IO_CREATE_EXT;
if (map->m_flags & (1 << BH_Delay)) if (map->m_flags & (1 << BH_Delay))
get_blocks_flags |= EXT4_GET_BLOCKS_DELALLOC_RESERVE; get_blocks_flags |= EXT4_GET_BLOCKS_DELALLOC_RESERVE;
@ -2156,7 +2164,7 @@ static int mpage_map_one_extent(handle_t *handle, struct mpage_da_data *mpd)
err = ext4_map_blocks(handle, inode, map, get_blocks_flags); err = ext4_map_blocks(handle, inode, map, get_blocks_flags);
if (err < 0) if (err < 0)
return err; return err;
if (map->m_flags & EXT4_MAP_UNINIT) { if (dioread_nolock && (map->m_flags & EXT4_MAP_UNWRITTEN)) {
if (!mpd->io_submit.io_end->handle && if (!mpd->io_submit.io_end->handle &&
ext4_handle_valid(handle)) { ext4_handle_valid(handle)) {
mpd->io_submit.io_end->handle = handle->h_rsv_handle; mpd->io_submit.io_end->handle = handle->h_rsv_handle;
@ -3070,9 +3078,9 @@ static void ext4_end_io_dio(struct kiocb *iocb, loff_t offset,
* preallocated extents, and those write extend the file, no need to * preallocated extents, and those write extend the file, no need to
* fall back to buffered IO. * fall back to buffered IO.
* *
* For holes, we fallocate those blocks, mark them as uninitialized * For holes, we fallocate those blocks, mark them as unwritten
* If those blocks were preallocated, we mark sure they are split, but * If those blocks were preallocated, we mark sure they are split, but
* still keep the range to write as uninitialized. * still keep the range to write as unwritten.
* *
* The unwritten extents will be converted to written when DIO is completed. * The unwritten extents will be converted to written when DIO is completed.
* For async direct IO, since the IO may still pending when return, we * For async direct IO, since the IO may still pending when return, we
@ -3124,12 +3132,12 @@ static ssize_t ext4_ext_direct_IO(int rw, struct kiocb *iocb,
* We could direct write to holes and fallocate. * We could direct write to holes and fallocate.
* *
* Allocated blocks to fill the hole are marked as * Allocated blocks to fill the hole are marked as
* uninitialized to prevent parallel buffered read to expose * unwritten to prevent parallel buffered read to expose
* the stale data before DIO complete the data IO. * the stale data before DIO complete the data IO.
* *
* As to previously fallocated extents, ext4 get_block will * As to previously fallocated extents, ext4 get_block will
* just simply mark the buffer mapped but still keep the * just simply mark the buffer mapped but still keep the
* extents uninitialized. * extents unwritten.
* *
* For non AIO case, we will convert those unwritten extents * For non AIO case, we will convert those unwritten extents
* to written after return back from blockdev_direct_IO. * to written after return back from blockdev_direct_IO.
@ -3440,7 +3448,7 @@ unlock:
* This required during truncate. We need to physically zero the tail end * This required during truncate. We need to physically zero the tail end
* of that block so it doesn't yield old data if the file is later grown. * of that block so it doesn't yield old data if the file is later grown.
*/ */
int ext4_block_truncate_page(handle_t *handle, static int ext4_block_truncate_page(handle_t *handle,
struct address_space *mapping, loff_t from) struct address_space *mapping, loff_t from)
{ {
unsigned offset = from & (PAGE_CACHE_SIZE-1); unsigned offset = from & (PAGE_CACHE_SIZE-1);
@ -4304,12 +4312,15 @@ static int ext4_do_update_inode(handle_t *handle,
struct ext4_inode *raw_inode = ext4_raw_inode(iloc); struct ext4_inode *raw_inode = ext4_raw_inode(iloc);
struct ext4_inode_info *ei = EXT4_I(inode); struct ext4_inode_info *ei = EXT4_I(inode);
struct buffer_head *bh = iloc->bh; struct buffer_head *bh = iloc->bh;
struct super_block *sb = inode->i_sb;
int err = 0, rc, block; int err = 0, rc, block;
int need_datasync = 0; int need_datasync = 0, set_large_file = 0;
uid_t i_uid; uid_t i_uid;
gid_t i_gid; gid_t i_gid;
/* For fields not not tracking in the in-memory inode, spin_lock(&ei->i_raw_lock);
/* For fields not tracked in the in-memory inode,
* initialise them to zero for new inodes. */ * initialise them to zero for new inodes. */
if (ext4_test_inode_state(inode, EXT4_STATE_NEW)) if (ext4_test_inode_state(inode, EXT4_STATE_NEW))
memset(raw_inode, 0, EXT4_SB(inode->i_sb)->s_inode_size); memset(raw_inode, 0, EXT4_SB(inode->i_sb)->s_inode_size);
@ -4347,8 +4358,10 @@ static int ext4_do_update_inode(handle_t *handle,
EXT4_INODE_SET_XTIME(i_atime, inode, raw_inode); EXT4_INODE_SET_XTIME(i_atime, inode, raw_inode);
EXT4_EINODE_SET_XTIME(i_crtime, ei, raw_inode); EXT4_EINODE_SET_XTIME(i_crtime, ei, raw_inode);
if (ext4_inode_blocks_set(handle, raw_inode, ei)) if (ext4_inode_blocks_set(handle, raw_inode, ei)) {
spin_unlock(&ei->i_raw_lock);
goto out_brelse; goto out_brelse;
}
raw_inode->i_dtime = cpu_to_le32(ei->i_dtime); raw_inode->i_dtime = cpu_to_le32(ei->i_dtime);
raw_inode->i_flags = cpu_to_le32(ei->i_flags & 0xFFFFFFFF); raw_inode->i_flags = cpu_to_le32(ei->i_flags & 0xFFFFFFFF);
if (likely(!test_opt2(inode->i_sb, HURD_COMPAT))) if (likely(!test_opt2(inode->i_sb, HURD_COMPAT)))
@ -4360,24 +4373,11 @@ static int ext4_do_update_inode(handle_t *handle,
need_datasync = 1; need_datasync = 1;
} }
if (ei->i_disksize > 0x7fffffffULL) { if (ei->i_disksize > 0x7fffffffULL) {
struct super_block *sb = inode->i_sb;
if (!EXT4_HAS_RO_COMPAT_FEATURE(sb, if (!EXT4_HAS_RO_COMPAT_FEATURE(sb,
EXT4_FEATURE_RO_COMPAT_LARGE_FILE) || EXT4_FEATURE_RO_COMPAT_LARGE_FILE) ||
EXT4_SB(sb)->s_es->s_rev_level == EXT4_SB(sb)->s_es->s_rev_level ==
cpu_to_le32(EXT4_GOOD_OLD_REV)) { cpu_to_le32(EXT4_GOOD_OLD_REV))
/* If this is the first large file set_large_file = 1;
* created, add a flag to the superblock.
*/
err = ext4_journal_get_write_access(handle,
EXT4_SB(sb)->s_sbh);
if (err)
goto out_brelse;
ext4_update_dynamic_rev(sb);
EXT4_SET_RO_COMPAT_FEATURE(sb,
EXT4_FEATURE_RO_COMPAT_LARGE_FILE);
ext4_handle_sync(handle);
err = ext4_handle_dirty_super(handle, sb);
}
} }
raw_inode->i_generation = cpu_to_le32(inode->i_generation); raw_inode->i_generation = cpu_to_le32(inode->i_generation);
if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) { if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) {
@ -4409,12 +4409,24 @@ static int ext4_do_update_inode(handle_t *handle,
ext4_inode_csum_set(inode, raw_inode, ei); ext4_inode_csum_set(inode, raw_inode, ei);
spin_unlock(&ei->i_raw_lock);
BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata"); BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata");
rc = ext4_handle_dirty_metadata(handle, NULL, bh); rc = ext4_handle_dirty_metadata(handle, NULL, bh);
if (!err) if (!err)
err = rc; err = rc;
ext4_clear_inode_state(inode, EXT4_STATE_NEW); ext4_clear_inode_state(inode, EXT4_STATE_NEW);
if (set_large_file) {
BUFFER_TRACE(EXT4_SB(sb)->s_sbh, "get write access");
err = ext4_journal_get_write_access(handle, EXT4_SB(sb)->s_sbh);
if (err)
goto out_brelse;
ext4_update_dynamic_rev(sb);
EXT4_SET_RO_COMPAT_FEATURE(sb,
EXT4_FEATURE_RO_COMPAT_LARGE_FILE);
ext4_handle_sync(handle);
err = ext4_handle_dirty_super(handle, sb);
}
ext4_update_inode_fsync_trans(handle, inode, need_datasync); ext4_update_inode_fsync_trans(handle, inode, need_datasync);
out_brelse: out_brelse:
brelse(bh); brelse(bh);

View file

@ -2619,7 +2619,7 @@ int ext4_mb_init(struct super_block *sb)
sbi->s_locality_groups = alloc_percpu(struct ext4_locality_group); sbi->s_locality_groups = alloc_percpu(struct ext4_locality_group);
if (sbi->s_locality_groups == NULL) { if (sbi->s_locality_groups == NULL) {
ret = -ENOMEM; ret = -ENOMEM;
goto out_free_groupinfo_slab; goto out;
} }
for_each_possible_cpu(i) { for_each_possible_cpu(i) {
struct ext4_locality_group *lg; struct ext4_locality_group *lg;
@ -2644,8 +2644,6 @@ int ext4_mb_init(struct super_block *sb)
out_free_locality_groups: out_free_locality_groups:
free_percpu(sbi->s_locality_groups); free_percpu(sbi->s_locality_groups);
sbi->s_locality_groups = NULL; sbi->s_locality_groups = NULL;
out_free_groupinfo_slab:
ext4_groupinfo_destroy_slabs();
out: out:
kfree(sbi->s_mb_offsets); kfree(sbi->s_mb_offsets);
sbi->s_mb_offsets = NULL; sbi->s_mb_offsets = NULL;
@ -2878,6 +2876,7 @@ ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac,
if (!bitmap_bh) if (!bitmap_bh)
goto out_err; goto out_err;
BUFFER_TRACE(bitmap_bh, "getting write access");
err = ext4_journal_get_write_access(handle, bitmap_bh); err = ext4_journal_get_write_access(handle, bitmap_bh);
if (err) if (err)
goto out_err; goto out_err;
@ -2890,6 +2889,7 @@ ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac,
ext4_debug("using block group %u(%d)\n", ac->ac_b_ex.fe_group, ext4_debug("using block group %u(%d)\n", ac->ac_b_ex.fe_group,
ext4_free_group_clusters(sb, gdp)); ext4_free_group_clusters(sb, gdp));
BUFFER_TRACE(gdp_bh, "get_write_access");
err = ext4_journal_get_write_access(handle, gdp_bh); err = ext4_journal_get_write_access(handle, gdp_bh);
if (err) if (err)
goto out_err; goto out_err;
@ -3147,7 +3147,7 @@ ext4_mb_normalize_request(struct ext4_allocation_context *ac,
} }
BUG_ON(start + size <= ac->ac_o_ex.fe_logical && BUG_ON(start + size <= ac->ac_o_ex.fe_logical &&
start > ac->ac_o_ex.fe_logical); start > ac->ac_o_ex.fe_logical);
BUG_ON(size <= 0 || size > EXT4_CLUSTERS_PER_GROUP(ac->ac_sb)); BUG_ON(size <= 0 || size > EXT4_BLOCKS_PER_GROUP(ac->ac_sb));
/* now prepare goal request */ /* now prepare goal request */

View file

@ -505,7 +505,7 @@ int ext4_ext_migrate(struct inode *inode)
* with i_data_sem held to prevent racing with block * with i_data_sem held to prevent racing with block
* allocation. * allocation.
*/ */
down_read((&EXT4_I(inode)->i_data_sem)); down_read(&EXT4_I(inode)->i_data_sem);
ext4_set_inode_state(inode, EXT4_STATE_EXT_MIGRATE); ext4_set_inode_state(inode, EXT4_STATE_EXT_MIGRATE);
up_read((&EXT4_I(inode)->i_data_sem)); up_read((&EXT4_I(inode)->i_data_sem));

View file

@ -18,7 +18,7 @@ static __le32 ext4_mmp_csum(struct super_block *sb, struct mmp_struct *mmp)
return cpu_to_le32(csum); return cpu_to_le32(csum);
} }
int ext4_mmp_csum_verify(struct super_block *sb, struct mmp_struct *mmp) static int ext4_mmp_csum_verify(struct super_block *sb, struct mmp_struct *mmp)
{ {
if (!EXT4_HAS_RO_COMPAT_FEATURE(sb, if (!EXT4_HAS_RO_COMPAT_FEATURE(sb,
EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
@ -27,7 +27,7 @@ int ext4_mmp_csum_verify(struct super_block *sb, struct mmp_struct *mmp)
return mmp->mmp_checksum == ext4_mmp_csum(sb, mmp); return mmp->mmp_checksum == ext4_mmp_csum(sb, mmp);
} }
void ext4_mmp_csum_set(struct super_block *sb, struct mmp_struct *mmp) static void ext4_mmp_csum_set(struct super_block *sb, struct mmp_struct *mmp)
{ {
if (!EXT4_HAS_RO_COMPAT_FEATURE(sb, if (!EXT4_HAS_RO_COMPAT_FEATURE(sb,
EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))

View file

@ -57,8 +57,8 @@ get_ext_path(struct inode *inode, ext4_lblk_t lblock,
static void static void
copy_extent_status(struct ext4_extent *src, struct ext4_extent *dest) copy_extent_status(struct ext4_extent *src, struct ext4_extent *dest)
{ {
if (ext4_ext_is_uninitialized(src)) if (ext4_ext_is_unwritten(src))
ext4_ext_mark_uninitialized(dest); ext4_ext_mark_unwritten(dest);
else else
dest->ee_len = cpu_to_le16(ext4_ext_get_actual_len(dest)); dest->ee_len = cpu_to_le16(ext4_ext_get_actual_len(dest));
} }
@ -391,6 +391,7 @@ mext_insert_extents(handle_t *handle, struct inode *orig_inode,
if (depth) { if (depth) {
/* Register to journal */ /* Register to journal */
BUFFER_TRACE(orig_path->p_bh, "get_write_access");
ret = ext4_journal_get_write_access(handle, orig_path->p_bh); ret = ext4_journal_get_write_access(handle, orig_path->p_bh);
if (ret) if (ret)
return ret; return ret;
@ -593,14 +594,14 @@ mext_calc_swap_extents(struct ext4_extent *tmp_dext,
* @inode: inode in question * @inode: inode in question
* @from: block offset of inode * @from: block offset of inode
* @count: block count to be checked * @count: block count to be checked
* @uninit: extents expected to be uninitialized * @unwritten: extents expected to be unwritten
* @err: pointer to save error value * @err: pointer to save error value
* *
* Return 1 if all extents in range has expected type, and zero otherwise. * Return 1 if all extents in range has expected type, and zero otherwise.
*/ */
static int static int
mext_check_coverage(struct inode *inode, ext4_lblk_t from, ext4_lblk_t count, mext_check_coverage(struct inode *inode, ext4_lblk_t from, ext4_lblk_t count,
int uninit, int *err) int unwritten, int *err)
{ {
struct ext4_ext_path *path = NULL; struct ext4_ext_path *path = NULL;
struct ext4_extent *ext; struct ext4_extent *ext;
@ -611,7 +612,7 @@ mext_check_coverage(struct inode *inode, ext4_lblk_t from, ext4_lblk_t count,
if (*err) if (*err)
goto out; goto out;
ext = path[ext_depth(inode)].p_ext; ext = path[ext_depth(inode)].p_ext;
if (uninit != ext4_ext_is_uninitialized(ext)) if (unwritten != ext4_ext_is_unwritten(ext))
goto out; goto out;
from += ext4_ext_get_actual_len(ext); from += ext4_ext_get_actual_len(ext);
ext4_ext_drop_refs(path); ext4_ext_drop_refs(path);
@ -894,7 +895,7 @@ out:
* @orig_page_offset: page index on original file * @orig_page_offset: page index on original file
* @data_offset_in_page: block index where data swapping starts * @data_offset_in_page: block index where data swapping starts
* @block_len_in_page: the number of blocks to be swapped * @block_len_in_page: the number of blocks to be swapped
* @uninit: orig extent is uninitialized or not * @unwritten: orig extent is unwritten or not
* @err: pointer to save return value * @err: pointer to save return value
* *
* Save the data in original inode blocks and replace original inode extents * Save the data in original inode blocks and replace original inode extents
@ -905,7 +906,7 @@ out:
static int static int
move_extent_per_page(struct file *o_filp, struct inode *donor_inode, move_extent_per_page(struct file *o_filp, struct inode *donor_inode,
pgoff_t orig_page_offset, int data_offset_in_page, pgoff_t orig_page_offset, int data_offset_in_page,
int block_len_in_page, int uninit, int *err) int block_len_in_page, int unwritten, int *err)
{ {
struct inode *orig_inode = file_inode(o_filp); struct inode *orig_inode = file_inode(o_filp);
struct page *pagep[2] = {NULL, NULL}; struct page *pagep[2] = {NULL, NULL};
@ -962,27 +963,27 @@ again:
if (unlikely(*err < 0)) if (unlikely(*err < 0))
goto stop_journal; goto stop_journal;
/* /*
* If orig extent was uninitialized it can become initialized * If orig extent was unwritten it can become initialized
* at any time after i_data_sem was dropped, in order to * at any time after i_data_sem was dropped, in order to
* serialize with delalloc we have recheck extent while we * serialize with delalloc we have recheck extent while we
* hold page's lock, if it is still the case data copy is not * hold page's lock, if it is still the case data copy is not
* necessary, just swap data blocks between orig and donor. * necessary, just swap data blocks between orig and donor.
*/ */
if (uninit) { if (unwritten) {
ext4_double_down_write_data_sem(orig_inode, donor_inode); ext4_double_down_write_data_sem(orig_inode, donor_inode);
/* If any of extents in range became initialized we have to /* If any of extents in range became initialized we have to
* fallback to data copying */ * fallback to data copying */
uninit = mext_check_coverage(orig_inode, orig_blk_offset, unwritten = mext_check_coverage(orig_inode, orig_blk_offset,
block_len_in_page, 1, err); block_len_in_page, 1, err);
if (*err) if (*err)
goto drop_data_sem; goto drop_data_sem;
uninit &= mext_check_coverage(donor_inode, orig_blk_offset, unwritten &= mext_check_coverage(donor_inode, orig_blk_offset,
block_len_in_page, 1, err); block_len_in_page, 1, err);
if (*err) if (*err)
goto drop_data_sem; goto drop_data_sem;
if (!uninit) { if (!unwritten) {
ext4_double_up_write_data_sem(orig_inode, donor_inode); ext4_double_up_write_data_sem(orig_inode, donor_inode);
goto data_copy; goto data_copy;
} }
@ -1259,7 +1260,7 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp,
int blocks_per_page = PAGE_CACHE_SIZE >> orig_inode->i_blkbits; int blocks_per_page = PAGE_CACHE_SIZE >> orig_inode->i_blkbits;
int data_offset_in_page; int data_offset_in_page;
int block_len_in_page; int block_len_in_page;
int uninit; int unwritten;
if (orig_inode->i_sb != donor_inode->i_sb) { if (orig_inode->i_sb != donor_inode->i_sb) {
ext4_debug("ext4 move extent: The argument files " ext4_debug("ext4 move extent: The argument files "
@ -1391,8 +1392,8 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp,
!last_extent) !last_extent)
continue; continue;
/* Is original extent is uninitialized */ /* Is original extent is unwritten */
uninit = ext4_ext_is_uninitialized(ext_prev); unwritten = ext4_ext_is_unwritten(ext_prev);
data_offset_in_page = seq_start % blocks_per_page; data_offset_in_page = seq_start % blocks_per_page;
@ -1432,8 +1433,8 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp,
o_filp, donor_inode, o_filp, donor_inode,
orig_page_offset, orig_page_offset,
data_offset_in_page, data_offset_in_page,
block_len_in_page, uninit, block_len_in_page,
&ret); unwritten, &ret);
/* Count how many blocks we have exchanged */ /* Count how many blocks we have exchanged */
*moved_len += block_len_in_page; *moved_len += block_len_in_page;

View file

@ -67,6 +67,7 @@ static struct buffer_head *ext4_append(handle_t *handle,
return ERR_PTR(err); return ERR_PTR(err);
inode->i_size += inode->i_sb->s_blocksize; inode->i_size += inode->i_sb->s_blocksize;
EXT4_I(inode)->i_disksize = inode->i_size; EXT4_I(inode)->i_disksize = inode->i_size;
BUFFER_TRACE(bh, "get_write_access");
err = ext4_journal_get_write_access(handle, bh); err = ext4_journal_get_write_access(handle, bh);
if (err) { if (err) {
brelse(bh); brelse(bh);
@ -1778,6 +1779,7 @@ static int make_indexed_dir(handle_t *handle, struct dentry *dentry,
blocksize = dir->i_sb->s_blocksize; blocksize = dir->i_sb->s_blocksize;
dxtrace(printk(KERN_DEBUG "Creating index: inode %lu\n", dir->i_ino)); dxtrace(printk(KERN_DEBUG "Creating index: inode %lu\n", dir->i_ino));
BUFFER_TRACE(bh, "get_write_access");
retval = ext4_journal_get_write_access(handle, bh); retval = ext4_journal_get_write_access(handle, bh);
if (retval) { if (retval) {
ext4_std_error(dir->i_sb, retval); ext4_std_error(dir->i_sb, retval);
@ -2510,8 +2512,7 @@ static int empty_dir(struct inode *inode)
ext4_rec_len_from_disk(de1->rec_len, sb->s_blocksize); ext4_rec_len_from_disk(de1->rec_len, sb->s_blocksize);
de = ext4_next_entry(de1, sb->s_blocksize); de = ext4_next_entry(de1, sb->s_blocksize);
while (offset < inode->i_size) { while (offset < inode->i_size) {
if (!bh || if ((void *) de >= (void *) (bh->b_data+sb->s_blocksize)) {
(void *) de >= (void *) (bh->b_data+sb->s_blocksize)) {
unsigned int lblock; unsigned int lblock;
err = 0; err = 0;
brelse(bh); brelse(bh);
@ -2539,26 +2540,37 @@ static int empty_dir(struct inode *inode)
return 1; return 1;
} }
/* ext4_orphan_add() links an unlinked or truncated inode into a list of /*
* ext4_orphan_add() links an unlinked or truncated inode into a list of
* such inodes, starting at the superblock, in case we crash before the * such inodes, starting at the superblock, in case we crash before the
* file is closed/deleted, or in case the inode truncate spans multiple * file is closed/deleted, or in case the inode truncate spans multiple
* transactions and the last transaction is not recovered after a crash. * transactions and the last transaction is not recovered after a crash.
* *
* At filesystem recovery time, we walk this list deleting unlinked * At filesystem recovery time, we walk this list deleting unlinked
* inodes and truncating linked inodes in ext4_orphan_cleanup(). * inodes and truncating linked inodes in ext4_orphan_cleanup().
*
* Orphan list manipulation functions must be called under i_mutex unless
* we are just creating the inode or deleting it.
*/ */
int ext4_orphan_add(handle_t *handle, struct inode *inode) int ext4_orphan_add(handle_t *handle, struct inode *inode)
{ {
struct super_block *sb = inode->i_sb; struct super_block *sb = inode->i_sb;
struct ext4_sb_info *sbi = EXT4_SB(sb);
struct ext4_iloc iloc; struct ext4_iloc iloc;
int err = 0, rc; int err = 0, rc;
bool dirty = false;
if (!EXT4_SB(sb)->s_journal) if (!sbi->s_journal)
return 0; return 0;
mutex_lock(&EXT4_SB(sb)->s_orphan_lock); WARN_ON_ONCE(!(inode->i_state & (I_NEW | I_FREEING)) &&
!mutex_is_locked(&inode->i_mutex));
/*
* Exit early if inode already is on orphan list. This is a big speedup
* since we don't have to contend on the global s_orphan_lock.
*/
if (!list_empty(&EXT4_I(inode)->i_orphan)) if (!list_empty(&EXT4_I(inode)->i_orphan))
goto out_unlock; return 0;
/* /*
* Orphan handling is only valid for files with data blocks * Orphan handling is only valid for files with data blocks
@ -2569,48 +2581,51 @@ int ext4_orphan_add(handle_t *handle, struct inode *inode)
J_ASSERT((S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || J_ASSERT((S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
S_ISLNK(inode->i_mode)) || inode->i_nlink == 0); S_ISLNK(inode->i_mode)) || inode->i_nlink == 0);
BUFFER_TRACE(EXT4_SB(sb)->s_sbh, "get_write_access"); BUFFER_TRACE(sbi->s_sbh, "get_write_access");
err = ext4_journal_get_write_access(handle, EXT4_SB(sb)->s_sbh); err = ext4_journal_get_write_access(handle, sbi->s_sbh);
if (err) if (err)
goto out_unlock; goto out;
err = ext4_reserve_inode_write(handle, inode, &iloc); err = ext4_reserve_inode_write(handle, inode, &iloc);
if (err) if (err)
goto out_unlock; goto out;
mutex_lock(&sbi->s_orphan_lock);
/* /*
* Due to previous errors inode may be already a part of on-disk * Due to previous errors inode may be already a part of on-disk
* orphan list. If so skip on-disk list modification. * orphan list. If so skip on-disk list modification.
*/ */
if (NEXT_ORPHAN(inode) && NEXT_ORPHAN(inode) <= if (!NEXT_ORPHAN(inode) || NEXT_ORPHAN(inode) >
(le32_to_cpu(EXT4_SB(sb)->s_es->s_inodes_count))) (le32_to_cpu(sbi->s_es->s_inodes_count))) {
goto mem_insert; /* Insert this inode at the head of the on-disk orphan list */
NEXT_ORPHAN(inode) = le32_to_cpu(sbi->s_es->s_last_orphan);
sbi->s_es->s_last_orphan = cpu_to_le32(inode->i_ino);
dirty = true;
}
list_add(&EXT4_I(inode)->i_orphan, &sbi->s_orphan);
mutex_unlock(&sbi->s_orphan_lock);
/* Insert this inode at the head of the on-disk orphan list... */ if (dirty) {
NEXT_ORPHAN(inode) = le32_to_cpu(EXT4_SB(sb)->s_es->s_last_orphan);
EXT4_SB(sb)->s_es->s_last_orphan = cpu_to_le32(inode->i_ino);
err = ext4_handle_dirty_super(handle, sb); err = ext4_handle_dirty_super(handle, sb);
rc = ext4_mark_iloc_dirty(handle, inode, &iloc); rc = ext4_mark_iloc_dirty(handle, inode, &iloc);
if (!err) if (!err)
err = rc; err = rc;
if (err) {
/* Only add to the head of the in-memory list if all the /*
* previous operations succeeded. If the orphan_add is going to * We have to remove inode from in-memory list if
* fail (possibly taking the journal offline), we can't risk * addition to on disk orphan list failed. Stray orphan
* leaving the inode on the orphan list: stray orphan-list * list entries can cause panics at unmount time.
* entries can cause panics at unmount time. */
* mutex_lock(&sbi->s_orphan_lock);
* This is safe: on error we're going to ignore the orphan list list_del(&EXT4_I(inode)->i_orphan);
* anyway on the next recovery. */ mutex_unlock(&sbi->s_orphan_lock);
mem_insert: }
if (!err) }
list_add(&EXT4_I(inode)->i_orphan, &EXT4_SB(sb)->s_orphan);
jbd_debug(4, "superblock will point to %lu\n", inode->i_ino); jbd_debug(4, "superblock will point to %lu\n", inode->i_ino);
jbd_debug(4, "orphan inode %lu will point to %d\n", jbd_debug(4, "orphan inode %lu will point to %d\n",
inode->i_ino, NEXT_ORPHAN(inode)); inode->i_ino, NEXT_ORPHAN(inode));
out_unlock: out:
mutex_unlock(&EXT4_SB(sb)->s_orphan_lock); ext4_std_error(sb, err);
ext4_std_error(inode->i_sb, err);
return err; return err;
} }
@ -2622,45 +2637,51 @@ int ext4_orphan_del(handle_t *handle, struct inode *inode)
{ {
struct list_head *prev; struct list_head *prev;
struct ext4_inode_info *ei = EXT4_I(inode); struct ext4_inode_info *ei = EXT4_I(inode);
struct ext4_sb_info *sbi; struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
__u32 ino_next; __u32 ino_next;
struct ext4_iloc iloc; struct ext4_iloc iloc;
int err = 0; int err = 0;
if ((!EXT4_SB(inode->i_sb)->s_journal) && if (!sbi->s_journal && !(sbi->s_mount_state & EXT4_ORPHAN_FS))
!(EXT4_SB(inode->i_sb)->s_mount_state & EXT4_ORPHAN_FS))
return 0; return 0;
mutex_lock(&EXT4_SB(inode->i_sb)->s_orphan_lock); WARN_ON_ONCE(!(inode->i_state & (I_NEW | I_FREEING)) &&
!mutex_is_locked(&inode->i_mutex));
/* Do this quick check before taking global s_orphan_lock. */
if (list_empty(&ei->i_orphan)) if (list_empty(&ei->i_orphan))
goto out; return 0;
ino_next = NEXT_ORPHAN(inode); if (handle) {
prev = ei->i_orphan.prev; /* Grab inode buffer early before taking global s_orphan_lock */
sbi = EXT4_SB(inode->i_sb); err = ext4_reserve_inode_write(handle, inode, &iloc);
}
mutex_lock(&sbi->s_orphan_lock);
jbd_debug(4, "remove inode %lu from orphan list\n", inode->i_ino); jbd_debug(4, "remove inode %lu from orphan list\n", inode->i_ino);
prev = ei->i_orphan.prev;
list_del_init(&ei->i_orphan); list_del_init(&ei->i_orphan);
/* If we're on an error path, we may not have a valid /* If we're on an error path, we may not have a valid
* transaction handle with which to update the orphan list on * transaction handle with which to update the orphan list on
* disk, but we still need to remove the inode from the linked * disk, but we still need to remove the inode from the linked
* list in memory. */ * list in memory. */
if (!handle) if (!handle || err) {
goto out; mutex_unlock(&sbi->s_orphan_lock);
err = ext4_reserve_inode_write(handle, inode, &iloc);
if (err)
goto out_err; goto out_err;
}
ino_next = NEXT_ORPHAN(inode);
if (prev == &sbi->s_orphan) { if (prev == &sbi->s_orphan) {
jbd_debug(4, "superblock will point to %u\n", ino_next); jbd_debug(4, "superblock will point to %u\n", ino_next);
BUFFER_TRACE(sbi->s_sbh, "get_write_access"); BUFFER_TRACE(sbi->s_sbh, "get_write_access");
err = ext4_journal_get_write_access(handle, sbi->s_sbh); err = ext4_journal_get_write_access(handle, sbi->s_sbh);
if (err) if (err) {
mutex_unlock(&sbi->s_orphan_lock);
goto out_brelse; goto out_brelse;
}
sbi->s_es->s_last_orphan = cpu_to_le32(ino_next); sbi->s_es->s_last_orphan = cpu_to_le32(ino_next);
mutex_unlock(&sbi->s_orphan_lock);
err = ext4_handle_dirty_super(handle, inode->i_sb); err = ext4_handle_dirty_super(handle, inode->i_sb);
} else { } else {
struct ext4_iloc iloc2; struct ext4_iloc iloc2;
@ -2670,20 +2691,20 @@ int ext4_orphan_del(handle_t *handle, struct inode *inode)
jbd_debug(4, "orphan inode %lu will point to %u\n", jbd_debug(4, "orphan inode %lu will point to %u\n",
i_prev->i_ino, ino_next); i_prev->i_ino, ino_next);
err = ext4_reserve_inode_write(handle, i_prev, &iloc2); err = ext4_reserve_inode_write(handle, i_prev, &iloc2);
if (err) if (err) {
mutex_unlock(&sbi->s_orphan_lock);
goto out_brelse; goto out_brelse;
}
NEXT_ORPHAN(i_prev) = ino_next; NEXT_ORPHAN(i_prev) = ino_next;
err = ext4_mark_iloc_dirty(handle, i_prev, &iloc2); err = ext4_mark_iloc_dirty(handle, i_prev, &iloc2);
mutex_unlock(&sbi->s_orphan_lock);
} }
if (err) if (err)
goto out_brelse; goto out_brelse;
NEXT_ORPHAN(inode) = 0; NEXT_ORPHAN(inode) = 0;
err = ext4_mark_iloc_dirty(handle, inode, &iloc); err = ext4_mark_iloc_dirty(handle, inode, &iloc);
out_err: out_err:
ext4_std_error(inode->i_sb, err); ext4_std_error(inode->i_sb, err);
out:
mutex_unlock(&EXT4_SB(inode->i_sb)->s_orphan_lock);
return err; return err;
out_brelse: out_brelse:

View file

@ -401,7 +401,8 @@ submit_and_retry:
int ext4_bio_write_page(struct ext4_io_submit *io, int ext4_bio_write_page(struct ext4_io_submit *io,
struct page *page, struct page *page,
int len, int len,
struct writeback_control *wbc) struct writeback_control *wbc,
bool keep_towrite)
{ {
struct inode *inode = page->mapping->host; struct inode *inode = page->mapping->host;
unsigned block_start, blocksize; unsigned block_start, blocksize;
@ -414,9 +415,23 @@ int ext4_bio_write_page(struct ext4_io_submit *io,
BUG_ON(!PageLocked(page)); BUG_ON(!PageLocked(page));
BUG_ON(PageWriteback(page)); BUG_ON(PageWriteback(page));
if (keep_towrite)
set_page_writeback_keepwrite(page);
else
set_page_writeback(page); set_page_writeback(page);
ClearPageError(page); ClearPageError(page);
/*
* Comments copied from block_write_full_page:
*
* The page straddles i_size. It must be zeroed out on each and every
* writepage invocation because it may be mmapped. "A file is mapped
* in multiples of the page size. For a file that is not a multiple of
* the page size, the remaining memory is zeroed when mapped, and
* writes to that region are not written out to the file."
*/
if (len < PAGE_CACHE_SIZE)
zero_user_segment(page, len, PAGE_CACHE_SIZE);
/* /*
* In the first loop we prepare and mark buffers to submit. We have to * In the first loop we prepare and mark buffers to submit. We have to
* mark all buffers in the page before submitting so that * mark all buffers in the page before submitting so that
@ -428,19 +443,6 @@ int ext4_bio_write_page(struct ext4_io_submit *io,
do { do {
block_start = bh_offset(bh); block_start = bh_offset(bh);
if (block_start >= len) { if (block_start >= len) {
/*
* Comments copied from block_write_full_page:
*
* The page straddles i_size. It must be zeroed out on
* each and every writepage invocation because it may
* be mmapped. "A file is mapped in multiples of the
* page size. For a file that is not a multiple of
* the page size, the remaining memory is zeroed when
* mapped, and writes to that region are not written
* out to the file."
*/
zero_user_segment(page, block_start,
block_start + blocksize);
clear_buffer_dirty(bh); clear_buffer_dirty(bh);
set_buffer_uptodate(bh); set_buffer_uptodate(bh);
continue; continue;

View file

@ -348,6 +348,7 @@ static struct buffer_head *bclean(handle_t *handle, struct super_block *sb,
bh = sb_getblk(sb, blk); bh = sb_getblk(sb, blk);
if (unlikely(!bh)) if (unlikely(!bh))
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
BUFFER_TRACE(bh, "get_write_access");
if ((err = ext4_journal_get_write_access(handle, bh))) { if ((err = ext4_journal_get_write_access(handle, bh))) {
brelse(bh); brelse(bh);
bh = ERR_PTR(err); bh = ERR_PTR(err);
@ -426,6 +427,7 @@ static int set_flexbg_block_bitmap(struct super_block *sb, handle_t *handle,
if (unlikely(!bh)) if (unlikely(!bh))
return -ENOMEM; return -ENOMEM;
BUFFER_TRACE(bh, "get_write_access");
err = ext4_journal_get_write_access(handle, bh); err = ext4_journal_get_write_access(handle, bh);
if (err) if (err)
return err; return err;
@ -518,6 +520,7 @@ static int setup_new_flex_group_blocks(struct super_block *sb,
goto out; goto out;
} }
BUFFER_TRACE(gdb, "get_write_access");
err = ext4_journal_get_write_access(handle, gdb); err = ext4_journal_get_write_access(handle, gdb);
if (err) { if (err) {
brelse(gdb); brelse(gdb);
@ -790,14 +793,17 @@ static int add_new_gdb(handle_t *handle, struct inode *inode,
goto exit_dind; goto exit_dind;
} }
BUFFER_TRACE(EXT4_SB(sb)->s_sbh, "get_write_access");
err = ext4_journal_get_write_access(handle, EXT4_SB(sb)->s_sbh); err = ext4_journal_get_write_access(handle, EXT4_SB(sb)->s_sbh);
if (unlikely(err)) if (unlikely(err))
goto exit_dind; goto exit_dind;
BUFFER_TRACE(gdb_bh, "get_write_access");
err = ext4_journal_get_write_access(handle, gdb_bh); err = ext4_journal_get_write_access(handle, gdb_bh);
if (unlikely(err)) if (unlikely(err))
goto exit_dind; goto exit_dind;
BUFFER_TRACE(dind, "get_write_access");
err = ext4_journal_get_write_access(handle, dind); err = ext4_journal_get_write_access(handle, dind);
if (unlikely(err)) if (unlikely(err))
ext4_std_error(sb, err); ext4_std_error(sb, err);
@ -902,6 +908,7 @@ static int add_new_gdb_meta_bg(struct super_block *sb,
EXT4_SB(sb)->s_group_desc = n_group_desc; EXT4_SB(sb)->s_group_desc = n_group_desc;
EXT4_SB(sb)->s_gdb_count++; EXT4_SB(sb)->s_gdb_count++;
ext4_kvfree(o_group_desc); ext4_kvfree(o_group_desc);
BUFFER_TRACE(gdb_bh, "get_write_access");
err = ext4_journal_get_write_access(handle, gdb_bh); err = ext4_journal_get_write_access(handle, gdb_bh);
if (unlikely(err)) if (unlikely(err))
brelse(gdb_bh); brelse(gdb_bh);
@ -977,6 +984,7 @@ static int reserve_backup_gdb(handle_t *handle, struct inode *inode,
} }
for (i = 0; i < reserved_gdb; i++) { for (i = 0; i < reserved_gdb; i++) {
BUFFER_TRACE(primary[i], "get_write_access");
if ((err = ext4_journal_get_write_access(handle, primary[i]))) if ((err = ext4_journal_get_write_access(handle, primary[i])))
goto exit_bh; goto exit_bh;
} }
@ -1084,6 +1092,7 @@ static void update_backups(struct super_block *sb, int blk_off, char *data,
ext4_debug("update metadata backup %llu(+%llu)\n", ext4_debug("update metadata backup %llu(+%llu)\n",
backup_block, backup_block - backup_block, backup_block -
ext4_group_first_block_no(sb, group)); ext4_group_first_block_no(sb, group));
BUFFER_TRACE(bh, "get_write_access");
if ((err = ext4_journal_get_write_access(handle, bh))) if ((err = ext4_journal_get_write_access(handle, bh)))
break; break;
lock_buffer(bh); lock_buffer(bh);
@ -1163,6 +1172,7 @@ static int ext4_add_new_descs(handle_t *handle, struct super_block *sb,
*/ */
if (gdb_off) { if (gdb_off) {
gdb_bh = sbi->s_group_desc[gdb_num]; gdb_bh = sbi->s_group_desc[gdb_num];
BUFFER_TRACE(gdb_bh, "get_write_access");
err = ext4_journal_get_write_access(handle, gdb_bh); err = ext4_journal_get_write_access(handle, gdb_bh);
if (!err && reserved_gdb && ext4_bg_num_gdb(sb, group)) if (!err && reserved_gdb && ext4_bg_num_gdb(sb, group))
@ -1433,6 +1443,7 @@ static int ext4_flex_group_add(struct super_block *sb,
goto exit; goto exit;
} }
BUFFER_TRACE(sbi->s_sbh, "get_write_access");
err = ext4_journal_get_write_access(handle, sbi->s_sbh); err = ext4_journal_get_write_access(handle, sbi->s_sbh);
if (err) if (err)
goto exit_journal; goto exit_journal;
@ -1645,6 +1656,7 @@ static int ext4_group_extend_no_check(struct super_block *sb,
return err; return err;
} }
BUFFER_TRACE(EXT4_SB(sb)->s_sbh, "get_write_access");
err = ext4_journal_get_write_access(handle, EXT4_SB(sb)->s_sbh); err = ext4_journal_get_write_access(handle, EXT4_SB(sb)->s_sbh);
if (err) { if (err) {
ext4_warning(sb, "error %d on journal write access", err); ext4_warning(sb, "error %d on journal write access", err);
@ -1804,6 +1816,7 @@ static int ext4_convert_meta_bg(struct super_block *sb, struct inode *inode)
if (IS_ERR(handle)) if (IS_ERR(handle))
return PTR_ERR(handle); return PTR_ERR(handle);
BUFFER_TRACE(sbi->s_sbh, "get_write_access");
err = ext4_journal_get_write_access(handle, sbi->s_sbh); err = ext4_journal_get_write_access(handle, sbi->s_sbh);
if (err) if (err)
goto errout; goto errout;

View file

@ -138,7 +138,7 @@ static __le32 ext4_superblock_csum(struct super_block *sb,
return cpu_to_le32(csum); return cpu_to_le32(csum);
} }
int ext4_superblock_csum_verify(struct super_block *sb, static int ext4_superblock_csum_verify(struct super_block *sb,
struct ext4_super_block *es) struct ext4_super_block *es)
{ {
if (!EXT4_HAS_RO_COMPAT_FEATURE(sb, if (!EXT4_HAS_RO_COMPAT_FEATURE(sb,
@ -879,6 +879,7 @@ static struct inode *ext4_alloc_inode(struct super_block *sb)
return NULL; return NULL;
ei->vfs_inode.i_version = 1; ei->vfs_inode.i_version = 1;
spin_lock_init(&ei->i_raw_lock);
INIT_LIST_HEAD(&ei->i_prealloc_list); INIT_LIST_HEAD(&ei->i_prealloc_list);
spin_lock_init(&ei->i_prealloc_lock); spin_lock_init(&ei->i_prealloc_lock);
ext4_es_init_tree(&ei->i_es_tree); ext4_es_init_tree(&ei->i_es_tree);
@ -1903,7 +1904,7 @@ static int ext4_setup_super(struct super_block *sb, struct ext4_super_block *es,
if (!(sbi->s_mount_state & EXT4_VALID_FS)) if (!(sbi->s_mount_state & EXT4_VALID_FS))
ext4_msg(sb, KERN_WARNING, "warning: mounting unchecked fs, " ext4_msg(sb, KERN_WARNING, "warning: mounting unchecked fs, "
"running e2fsck is recommended"); "running e2fsck is recommended");
else if ((sbi->s_mount_state & EXT4_ERROR_FS)) else if (sbi->s_mount_state & EXT4_ERROR_FS)
ext4_msg(sb, KERN_WARNING, ext4_msg(sb, KERN_WARNING,
"warning: mounting fs with errors, " "warning: mounting fs with errors, "
"running e2fsck is recommended"); "running e2fsck is recommended");
@ -2404,6 +2405,16 @@ static ext4_fsblk_t descriptor_loc(struct super_block *sb,
if (ext4_bg_has_super(sb, bg)) if (ext4_bg_has_super(sb, bg))
has_super = 1; has_super = 1;
/*
* If we have a meta_bg fs with 1k blocks, group 0's GDT is at
* block 2, not 1. If s_first_data_block == 0 (bigalloc is enabled
* on modern mke2fs or blksize > 1k on older mke2fs) then we must
* compensate.
*/
if (sb->s_blocksize == 1024 && nr == 0 &&
le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block) == 0)
has_super++;
return (has_super + ext4_group_first_block_no(sb, bg)); return (has_super + ext4_group_first_block_no(sb, bg));
} }
@ -3337,7 +3348,7 @@ static ext4_fsblk_t ext4_calculate_resv_clusters(struct super_block *sb)
* By default we reserve 2% or 4096 clusters, whichever is smaller. * By default we reserve 2% or 4096 clusters, whichever is smaller.
* This should cover the situations where we can not afford to run * This should cover the situations where we can not afford to run
* out of space like for example punch hole, or converting * out of space like for example punch hole, or converting
* uninitialized extents in delalloc path. In most cases such * unwritten extents in delalloc path. In most cases such
* allocation would require 1, or 2 blocks, higher numbers are * allocation would require 1, or 2 blocks, higher numbers are
* very rare. * very rare.
*/ */
@ -5370,6 +5381,7 @@ static ssize_t ext4_quota_write(struct super_block *sb, int type,
bh = ext4_bread(handle, inode, blk, 1, &err); bh = ext4_bread(handle, inode, blk, 1, &err);
if (!bh) if (!bh)
goto out; goto out;
BUFFER_TRACE(bh, "get write access");
err = ext4_journal_get_write_access(handle, bh); err = ext4_journal_get_write_access(handle, bh);
if (err) { if (err) {
brelse(bh); brelse(bh);

View file

@ -369,6 +369,9 @@ ext4_xattr_get(struct inode *inode, int name_index, const char *name,
{ {
int error; int error;
if (strlen(name) > 255)
return -ERANGE;
down_read(&EXT4_I(inode)->xattr_sem); down_read(&EXT4_I(inode)->xattr_sem);
error = ext4_xattr_ibody_get(inode, name_index, name, buffer, error = ext4_xattr_ibody_get(inode, name_index, name, buffer,
buffer_size); buffer_size);
@ -513,6 +516,7 @@ static void ext4_xattr_update_super_block(handle_t *handle,
if (EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_EXT_ATTR)) if (EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_EXT_ATTR))
return; return;
BUFFER_TRACE(EXT4_SB(sb)->s_sbh, "get_write_access");
if (ext4_journal_get_write_access(handle, EXT4_SB(sb)->s_sbh) == 0) { if (ext4_journal_get_write_access(handle, EXT4_SB(sb)->s_sbh) == 0) {
EXT4_SET_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_EXT_ATTR); EXT4_SET_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_EXT_ATTR);
ext4_handle_dirty_super(handle, sb); ext4_handle_dirty_super(handle, sb);
@ -532,6 +536,7 @@ ext4_xattr_release_block(handle_t *handle, struct inode *inode,
struct mb_cache *ext4_mb_cache = EXT4_GET_MB_CACHE(inode); struct mb_cache *ext4_mb_cache = EXT4_GET_MB_CACHE(inode);
ce = mb_cache_entry_get(ext4_mb_cache, bh->b_bdev, bh->b_blocknr); ce = mb_cache_entry_get(ext4_mb_cache, bh->b_bdev, bh->b_blocknr);
BUFFER_TRACE(bh, "get_write_access");
error = ext4_journal_get_write_access(handle, bh); error = ext4_journal_get_write_access(handle, bh);
if (error) if (error)
goto out; goto out;
@ -774,6 +779,7 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode,
if (s->base) { if (s->base) {
ce = mb_cache_entry_get(ext4_mb_cache, bs->bh->b_bdev, ce = mb_cache_entry_get(ext4_mb_cache, bs->bh->b_bdev,
bs->bh->b_blocknr); bs->bh->b_blocknr);
BUFFER_TRACE(bs->bh, "get_write_access");
error = ext4_journal_get_write_access(handle, bs->bh); error = ext4_journal_get_write_access(handle, bs->bh);
if (error) if (error)
goto cleanup; goto cleanup;
@ -859,6 +865,7 @@ inserted:
EXT4_C2B(EXT4_SB(sb), 1)); EXT4_C2B(EXT4_SB(sb), 1));
if (error) if (error)
goto cleanup; goto cleanup;
BUFFER_TRACE(new_bh, "get_write_access");
error = ext4_journal_get_write_access(handle, error = ext4_journal_get_write_access(handle,
new_bh); new_bh);
if (error) if (error)
@ -896,7 +903,7 @@ inserted:
* take i_data_sem because we will test * take i_data_sem because we will test
* i_delalloc_reserved_flag in ext4_mb_new_blocks * i_delalloc_reserved_flag in ext4_mb_new_blocks
*/ */
down_read((&EXT4_I(inode)->i_data_sem)); down_read(&EXT4_I(inode)->i_data_sem);
block = ext4_new_meta_blocks(handle, inode, goal, 0, block = ext4_new_meta_blocks(handle, inode, goal, 0,
NULL, &error); NULL, &error);
up_read((&EXT4_I(inode)->i_data_sem)); up_read((&EXT4_I(inode)->i_data_sem));

View file

@ -319,13 +319,23 @@ CLEARPAGEFLAG(Uptodate, uptodate)
extern void cancel_dirty_page(struct page *page, unsigned int account_size); extern void cancel_dirty_page(struct page *page, unsigned int account_size);
int test_clear_page_writeback(struct page *page); int test_clear_page_writeback(struct page *page);
int test_set_page_writeback(struct page *page); int __test_set_page_writeback(struct page *page, bool keep_write);
#define test_set_page_writeback(page) \
__test_set_page_writeback(page, false)
#define test_set_page_writeback_keepwrite(page) \
__test_set_page_writeback(page, true)
static inline void set_page_writeback(struct page *page) static inline void set_page_writeback(struct page *page)
{ {
test_set_page_writeback(page); test_set_page_writeback(page);
} }
static inline void set_page_writeback_keepwrite(struct page *page)
{
test_set_page_writeback_keepwrite(page);
}
#ifdef CONFIG_PAGEFLAGS_EXTENDED #ifdef CONFIG_PAGEFLAGS_EXTENDED
/* /*
* System with lots of page flags available. This allows separate * System with lots of page flags available. This allows separate

View file

@ -36,7 +36,7 @@ struct extent_status;
#define show_map_flags(flags) __print_flags(flags, "|", \ #define show_map_flags(flags) __print_flags(flags, "|", \
{ EXT4_GET_BLOCKS_CREATE, "CREATE" }, \ { EXT4_GET_BLOCKS_CREATE, "CREATE" }, \
{ EXT4_GET_BLOCKS_UNINIT_EXT, "UNINIT" }, \ { EXT4_GET_BLOCKS_UNWRIT_EXT, "UNWRIT" }, \
{ EXT4_GET_BLOCKS_DELALLOC_RESERVE, "DELALLOC" }, \ { EXT4_GET_BLOCKS_DELALLOC_RESERVE, "DELALLOC" }, \
{ EXT4_GET_BLOCKS_PRE_IO, "PRE_IO" }, \ { EXT4_GET_BLOCKS_PRE_IO, "PRE_IO" }, \
{ EXT4_GET_BLOCKS_CONVERT, "CONVERT" }, \ { EXT4_GET_BLOCKS_CONVERT, "CONVERT" }, \
@ -51,7 +51,6 @@ struct extent_status;
{ EXT4_MAP_MAPPED, "M" }, \ { EXT4_MAP_MAPPED, "M" }, \
{ EXT4_MAP_UNWRITTEN, "U" }, \ { EXT4_MAP_UNWRITTEN, "U" }, \
{ EXT4_MAP_BOUNDARY, "B" }, \ { EXT4_MAP_BOUNDARY, "B" }, \
{ EXT4_MAP_UNINIT, "u" }, \
{ EXT4_MAP_FROM_CLUSTER, "C" }) { EXT4_MAP_FROM_CLUSTER, "C" })
#define show_free_flags(flags) __print_flags(flags, "|", \ #define show_free_flags(flags) __print_flags(flags, "|", \
@ -1497,7 +1496,7 @@ DEFINE_EVENT(ext4__truncate, ext4_truncate_exit,
TP_ARGS(inode) TP_ARGS(inode)
); );
/* 'ux' is the uninitialized extent. */ /* 'ux' is the unwritten extent. */
TRACE_EVENT(ext4_ext_convert_to_initialized_enter, TRACE_EVENT(ext4_ext_convert_to_initialized_enter,
TP_PROTO(struct inode *inode, struct ext4_map_blocks *map, TP_PROTO(struct inode *inode, struct ext4_map_blocks *map,
struct ext4_extent *ux), struct ext4_extent *ux),
@ -1533,7 +1532,7 @@ TRACE_EVENT(ext4_ext_convert_to_initialized_enter,
); );
/* /*
* 'ux' is the uninitialized extent. * 'ux' is the unwritten extent.
* 'ix' is the initialized extent to which blocks are transferred. * 'ix' is the initialized extent to which blocks are transferred.
*/ */
TRACE_EVENT(ext4_ext_convert_to_initialized_fastpath, TRACE_EVENT(ext4_ext_convert_to_initialized_fastpath,
@ -1811,7 +1810,7 @@ DEFINE_EVENT(ext4__trim, ext4_trim_all_free,
TP_ARGS(sb, group, start, len) TP_ARGS(sb, group, start, len)
); );
TRACE_EVENT(ext4_ext_handle_uninitialized_extents, TRACE_EVENT(ext4_ext_handle_unwritten_extents,
TP_PROTO(struct inode *inode, struct ext4_map_blocks *map, int flags, TP_PROTO(struct inode *inode, struct ext4_map_blocks *map, int flags,
unsigned int allocated, ext4_fsblk_t newblock), unsigned int allocated, ext4_fsblk_t newblock),

View file

@ -2380,7 +2380,7 @@ int test_clear_page_writeback(struct page *page)
return ret; return ret;
} }
int test_set_page_writeback(struct page *page) int __test_set_page_writeback(struct page *page, bool keep_write)
{ {
struct address_space *mapping = page_mapping(page); struct address_space *mapping = page_mapping(page);
int ret; int ret;
@ -2405,6 +2405,7 @@ int test_set_page_writeback(struct page *page)
radix_tree_tag_clear(&mapping->page_tree, radix_tree_tag_clear(&mapping->page_tree,
page_index(page), page_index(page),
PAGECACHE_TAG_DIRTY); PAGECACHE_TAG_DIRTY);
if (!keep_write)
radix_tree_tag_clear(&mapping->page_tree, radix_tree_tag_clear(&mapping->page_tree,
page_index(page), page_index(page),
PAGECACHE_TAG_TOWRITE); PAGECACHE_TAG_TOWRITE);
@ -2418,7 +2419,7 @@ int test_set_page_writeback(struct page *page)
return ret; return ret;
} }
EXPORT_SYMBOL(test_set_page_writeback); EXPORT_SYMBOL(__test_set_page_writeback);
/* /*
* Return true if any of the pages in the mapping are marked with the * Return true if any of the pages in the mapping are marked with the