Commit 60ad4466 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4

* 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4: (60 commits)
  ext4: prevent memory leaks from ext4_mb_init_backend() on error path
  ext4: use EXT4_BAD_INO for buddy cache to avoid colliding with valid inode #
  ext4: use ext4_msg() instead of printk in mballoc
  ext4: use ext4_kvzalloc()/ext4_kvmalloc() for s_group_desc and s_group_info
  ext4: introduce ext4_kvmalloc(), ext4_kzalloc(), and ext4_kvfree()
  ext4: use the correct error exit path in ext4_init_inode_table()
  ext4: add missing kfree() on error return path in add_new_gdb()
  ext4: change umode_t in tracepoint headers to be an explicit __u16
  ext4: fix races in ext4_sync_parent()
  ext4: Fix overflow caused by missing cast in ext4_fallocate()
  ext4: add action of moving index in ext4_ext_rm_idx for Punch Hole
  ext4: simplify parameters of reserve_backup_gdb()
  ext4: simplify parameters of add_new_gdb()
  ext4: remove lock_buffer in bclean() and setup_new_group_blocks()
  ext4: simplify journal handling in setup_new_group_blocks()
  ext4: let setup_new_group_blocks() set multiple bits at a time
  ext4: fix a typo in ext4_group_extend()
  ext4: let ext4_group_add_blocks() handle 0 blocks quickly
  ext4: let ext4_group_add_blocks() return an error code
  ext4: rename ext4_add_groupblocks() to ext4_group_add_blocks()
  ...

Fix up conflict in fs/ext4/inode.c: commit aacfc19c ("fs: simplify
the blockdev_direct_IO prototype") had changed the ext4_ind_direct_IO()
function for the new simplified calling convention, while commit
dae1e52c ("ext4: move ext4_ind_* functions from inode.c to
indirect.c") moved the function to another file.
parents 1b8e9499 79a77c5a
...@@ -7,7 +7,7 @@ obj-$(CONFIG_EXT4_FS) += ext4.o ...@@ -7,7 +7,7 @@ obj-$(CONFIG_EXT4_FS) += ext4.o
ext4-y := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o page-io.o \ ext4-y := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o page-io.o \
ioctl.o namei.o super.o symlink.o hash.o resize.o extents.o \ ioctl.o namei.o super.o symlink.o hash.o resize.o extents.o \
ext4_jbd2.o migrate.o mballoc.o block_validity.o move_extent.o \ ext4_jbd2.o migrate.o mballoc.o block_validity.o move_extent.o \
mmp.o mmp.o indirect.o
ext4-$(CONFIG_EXT4_FS_XATTR) += xattr.o xattr_user.o xattr_trusted.o ext4-$(CONFIG_EXT4_FS_XATTR) += xattr.o xattr_user.o xattr_trusted.o
ext4-$(CONFIG_EXT4_FS_POSIX_ACL) += acl.o ext4-$(CONFIG_EXT4_FS_POSIX_ACL) += acl.o
......
...@@ -620,3 +620,51 @@ unsigned long ext4_bg_num_gdb(struct super_block *sb, ext4_group_t group) ...@@ -620,3 +620,51 @@ unsigned long ext4_bg_num_gdb(struct super_block *sb, ext4_group_t group)
} }
/**
* ext4_inode_to_goal_block - return a hint for block allocation
* @inode: inode for block allocation
*
* Return the ideal location to start allocating blocks for a
* newly created inode.
*/
ext4_fsblk_t ext4_inode_to_goal_block(struct inode *inode)
{
struct ext4_inode_info *ei = EXT4_I(inode);
ext4_group_t block_group;
ext4_grpblk_t colour;
int flex_size = ext4_flex_bg_size(EXT4_SB(inode->i_sb));
ext4_fsblk_t bg_start;
ext4_fsblk_t last_block;
block_group = ei->i_block_group;
if (flex_size >= EXT4_FLEX_SIZE_DIR_ALLOC_SCHEME) {
/*
* If there are at least EXT4_FLEX_SIZE_DIR_ALLOC_SCHEME
* block groups per flexgroup, reserve the first block
* group for directories and special files. Regular
* files will start at the second block group. This
* tends to speed up directory access and improves
* fsck times.
*/
block_group &= ~(flex_size-1);
if (S_ISREG(inode->i_mode))
block_group++;
}
bg_start = ext4_group_first_block_no(inode->i_sb, block_group);
last_block = ext4_blocks_count(EXT4_SB(inode->i_sb)->s_es) - 1;
/*
* If we are doing delayed allocation, we don't need take
* colour into account.
*/
if (test_opt(inode->i_sb, DELALLOC))
return bg_start;
if (bg_start + EXT4_BLOCKS_PER_GROUP(inode->i_sb) <= last_block)
colour = (current->pid % 16) *
(EXT4_BLOCKS_PER_GROUP(inode->i_sb) / 16);
else
colour = (current->pid % 16) * ((last_block - bg_start) / 16);
return bg_start + colour;
}
...@@ -246,3 +246,24 @@ int ext4_data_block_valid(struct ext4_sb_info *sbi, ext4_fsblk_t start_blk, ...@@ -246,3 +246,24 @@ int ext4_data_block_valid(struct ext4_sb_info *sbi, ext4_fsblk_t start_blk,
return 1; return 1;
} }
int ext4_check_blockref(const char *function, unsigned int line,
struct inode *inode, __le32 *p, unsigned int max)
{
struct ext4_super_block *es = EXT4_SB(inode->i_sb)->s_es;
__le32 *bref = p;
unsigned int blk;
while (bref < p+max) {
blk = le32_to_cpu(*bref++);
if (blk &&
unlikely(!ext4_data_block_valid(EXT4_SB(inode->i_sb),
blk, 1))) {
es->s_last_error_block = cpu_to_le64(blk);
ext4_error_inode(inode, function, line, blk,
"invalid block");
return -EIO;
}
}
return 0;
}
...@@ -526,6 +526,7 @@ struct ext4_new_group_data { ...@@ -526,6 +526,7 @@ struct ext4_new_group_data {
#define EXT4_FREE_BLOCKS_METADATA 0x0001 #define EXT4_FREE_BLOCKS_METADATA 0x0001
#define EXT4_FREE_BLOCKS_FORGET 0x0002 #define EXT4_FREE_BLOCKS_FORGET 0x0002
#define EXT4_FREE_BLOCKS_VALIDATED 0x0004 #define EXT4_FREE_BLOCKS_VALIDATED 0x0004
#define EXT4_FREE_BLOCKS_NO_QUOT_UPDATE 0x0008
/* /*
* ioctl commands * ioctl commands
...@@ -939,6 +940,8 @@ struct ext4_inode_info { ...@@ -939,6 +940,8 @@ struct ext4_inode_info {
#define ext4_find_next_zero_bit find_next_zero_bit_le #define ext4_find_next_zero_bit find_next_zero_bit_le
#define ext4_find_next_bit find_next_bit_le #define ext4_find_next_bit find_next_bit_le
extern void ext4_set_bits(void *bm, int cur, int len);
/* /*
* Maximal mount counts between two filesystem checks * Maximal mount counts between two filesystem checks
*/ */
...@@ -1126,7 +1129,8 @@ struct ext4_sb_info { ...@@ -1126,7 +1129,8 @@ struct ext4_sb_info {
struct journal_s *s_journal; struct journal_s *s_journal;
struct list_head s_orphan; struct list_head s_orphan;
struct mutex s_orphan_lock; struct mutex s_orphan_lock;
struct mutex s_resize_lock; unsigned long s_resize_flags; /* Flags indicating if there
is a resizer */
unsigned long s_commit_interval; unsigned long s_commit_interval;
u32 s_max_batch_time; u32 s_max_batch_time;
u32 s_min_batch_time; u32 s_min_batch_time;
...@@ -1214,6 +1218,9 @@ struct ext4_sb_info { ...@@ -1214,6 +1218,9 @@ struct ext4_sb_info {
/* Kernel thread for multiple mount protection */ /* Kernel thread for multiple mount protection */
struct task_struct *s_mmp_tsk; struct task_struct *s_mmp_tsk;
/* record the last minlen when FITRIM is called. */
atomic_t s_last_trim_minblks;
}; };
static inline struct ext4_sb_info *EXT4_SB(struct super_block *sb) static inline struct ext4_sb_info *EXT4_SB(struct super_block *sb)
...@@ -1743,6 +1750,7 @@ extern unsigned ext4_init_block_bitmap(struct super_block *sb, ...@@ -1743,6 +1750,7 @@ extern unsigned ext4_init_block_bitmap(struct super_block *sb,
struct ext4_group_desc *desc); struct ext4_group_desc *desc);
#define ext4_free_blocks_after_init(sb, group, desc) \ #define ext4_free_blocks_after_init(sb, group, desc) \
ext4_init_block_bitmap(sb, NULL, group, desc) ext4_init_block_bitmap(sb, NULL, group, desc)
ext4_fsblk_t ext4_inode_to_goal_block(struct inode *);
/* dir.c */ /* dir.c */
extern int __ext4_check_dir_entry(const char *, unsigned int, struct inode *, extern int __ext4_check_dir_entry(const char *, unsigned int, struct inode *,
...@@ -1793,7 +1801,7 @@ extern void ext4_free_blocks(handle_t *handle, struct inode *inode, ...@@ -1793,7 +1801,7 @@ extern void ext4_free_blocks(handle_t *handle, struct inode *inode,
unsigned long count, int flags); unsigned long count, int flags);
extern int ext4_mb_add_groupinfo(struct super_block *sb, extern int ext4_mb_add_groupinfo(struct super_block *sb,
ext4_group_t i, struct ext4_group_desc *desc); ext4_group_t i, struct ext4_group_desc *desc);
extern void ext4_add_groupblocks(handle_t *handle, struct super_block *sb, extern int ext4_group_add_blocks(handle_t *handle, struct super_block *sb,
ext4_fsblk_t block, unsigned long count); ext4_fsblk_t block, unsigned long count);
extern int ext4_trim_fs(struct super_block *, struct fstrim_range *); extern int ext4_trim_fs(struct super_block *, struct fstrim_range *);
...@@ -1834,6 +1842,17 @@ extern int ext4_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf); ...@@ -1834,6 +1842,17 @@ extern int ext4_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf);
extern qsize_t *ext4_get_reserved_space(struct inode *inode); extern qsize_t *ext4_get_reserved_space(struct inode *inode);
extern void ext4_da_update_reserve_space(struct inode *inode, extern void ext4_da_update_reserve_space(struct inode *inode,
int used, int quota_claim); int used, int quota_claim);
/* indirect.c */
extern int ext4_ind_map_blocks(handle_t *handle, struct inode *inode,
struct ext4_map_blocks *map, int flags);
extern ssize_t ext4_ind_direct_IO(int rw, struct kiocb *iocb,
const struct iovec *iov, loff_t offset,
unsigned long nr_segs);
extern int ext4_ind_calc_metadata_amount(struct inode *inode, sector_t lblock);
extern int ext4_ind_trans_blocks(struct inode *inode, int nrblocks, int chunk);
extern void ext4_ind_truncate(struct inode *inode);
/* ioctl.c */ /* ioctl.c */
extern long ext4_ioctl(struct file *, unsigned int, unsigned long); extern long ext4_ioctl(struct file *, unsigned int, unsigned long);
extern long ext4_compat_ioctl(struct file *, unsigned int, unsigned long); extern long ext4_compat_ioctl(struct file *, unsigned int, unsigned long);
...@@ -1855,6 +1874,9 @@ extern int ext4_group_extend(struct super_block *sb, ...@@ -1855,6 +1874,9 @@ extern int ext4_group_extend(struct super_block *sb,
ext4_fsblk_t n_blocks_count); ext4_fsblk_t n_blocks_count);
/* super.c */ /* super.c */
extern void *ext4_kvmalloc(size_t size, gfp_t flags);
extern void *ext4_kvzalloc(size_t size, gfp_t flags);
extern void ext4_kvfree(void *ptr);
extern void __ext4_error(struct super_block *, const char *, unsigned int, extern void __ext4_error(struct super_block *, const char *, unsigned int,
const char *, ...) const char *, ...)
__attribute__ ((format (printf, 4, 5))); __attribute__ ((format (printf, 4, 5)));
...@@ -2067,11 +2089,19 @@ struct ext4_group_info { ...@@ -2067,11 +2089,19 @@ struct ext4_group_info {
* 5 free 8-block regions. */ * 5 free 8-block regions. */
}; };
#define EXT4_GROUP_INFO_NEED_INIT_BIT 0 #define EXT4_GROUP_INFO_NEED_INIT_BIT 0
#define EXT4_GROUP_INFO_WAS_TRIMMED_BIT 1
#define EXT4_MB_GRP_NEED_INIT(grp) \ #define EXT4_MB_GRP_NEED_INIT(grp) \
(test_bit(EXT4_GROUP_INFO_NEED_INIT_BIT, &((grp)->bb_state))) (test_bit(EXT4_GROUP_INFO_NEED_INIT_BIT, &((grp)->bb_state)))
#define EXT4_MB_GRP_WAS_TRIMMED(grp) \
(test_bit(EXT4_GROUP_INFO_WAS_TRIMMED_BIT, &((grp)->bb_state)))
#define EXT4_MB_GRP_SET_TRIMMED(grp) \
(set_bit(EXT4_GROUP_INFO_WAS_TRIMMED_BIT, &((grp)->bb_state)))
#define EXT4_MB_GRP_CLEAR_TRIMMED(grp) \
(clear_bit(EXT4_GROUP_INFO_WAS_TRIMMED_BIT, &((grp)->bb_state)))
#define EXT4_MAX_CONTENTION 8 #define EXT4_MAX_CONTENTION 8
#define EXT4_CONTENTION_THRESHOLD 2 #define EXT4_CONTENTION_THRESHOLD 2
...@@ -2122,6 +2152,19 @@ static inline void ext4_mark_super_dirty(struct super_block *sb) ...@@ -2122,6 +2152,19 @@ static inline void ext4_mark_super_dirty(struct super_block *sb)
sb->s_dirt =1; sb->s_dirt =1;
} }
/*
* Block validity checking
*/
#define ext4_check_indirect_blockref(inode, bh) \
ext4_check_blockref(__func__, __LINE__, inode, \
(__le32 *)(bh)->b_data, \
EXT4_ADDR_PER_BLOCK((inode)->i_sb))
#define ext4_ind_check_inode(inode) \
ext4_check_blockref(__func__, __LINE__, inode, \
EXT4_I(inode)->i_data, \
EXT4_NDIR_BLOCKS)
/* /*
* Inodes and files operations * Inodes and files operations
*/ */
...@@ -2151,6 +2194,8 @@ extern void ext4_exit_system_zone(void); ...@@ -2151,6 +2194,8 @@ extern void ext4_exit_system_zone(void);
extern int ext4_data_block_valid(struct ext4_sb_info *sbi, extern int ext4_data_block_valid(struct ext4_sb_info *sbi,
ext4_fsblk_t start_blk, ext4_fsblk_t start_blk,
unsigned int count); unsigned int count);
extern int ext4_check_blockref(const char *, unsigned int,
struct inode *, __le32 *, unsigned int);
/* extents.c */ /* extents.c */
extern int ext4_ext_tree_init(handle_t *handle, struct inode *); extern int ext4_ext_tree_init(handle_t *handle, struct inode *);
...@@ -2230,6 +2275,10 @@ static inline void set_bitmap_uptodate(struct buffer_head *bh) ...@@ -2230,6 +2275,10 @@ static inline void set_bitmap_uptodate(struct buffer_head *bh)
extern wait_queue_head_t ext4__ioend_wq[EXT4_WQ_HASH_SZ]; extern wait_queue_head_t ext4__ioend_wq[EXT4_WQ_HASH_SZ];
extern struct mutex ext4__aio_mutex[EXT4_WQ_HASH_SZ]; extern struct mutex ext4__aio_mutex[EXT4_WQ_HASH_SZ];
#define EXT4_RESIZING 0
extern int ext4_resize_begin(struct super_block *sb);
extern void ext4_resize_end(struct super_block *sb);
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
#endif /* _EXT4_H */ #endif /* _EXT4_H */
...@@ -114,12 +114,6 @@ static ext4_fsblk_t ext4_ext_find_goal(struct inode *inode, ...@@ -114,12 +114,6 @@ static ext4_fsblk_t ext4_ext_find_goal(struct inode *inode,
struct ext4_ext_path *path, struct ext4_ext_path *path,
ext4_lblk_t block) ext4_lblk_t block)
{ {
struct ext4_inode_info *ei = EXT4_I(inode);
ext4_fsblk_t bg_start;
ext4_fsblk_t last_block;
ext4_grpblk_t colour;
ext4_group_t block_group;
int flex_size = ext4_flex_bg_size(EXT4_SB(inode->i_sb));
int depth; int depth;
if (path) { if (path) {
...@@ -161,36 +155,7 @@ static ext4_fsblk_t ext4_ext_find_goal(struct inode *inode, ...@@ -161,36 +155,7 @@ static ext4_fsblk_t ext4_ext_find_goal(struct inode *inode,
} }
/* OK. use inode's group */ /* OK. use inode's group */
block_group = ei->i_block_group; return ext4_inode_to_goal_block(inode);
if (flex_size >= EXT4_FLEX_SIZE_DIR_ALLOC_SCHEME) {
/*
* If there are at least EXT4_FLEX_SIZE_DIR_ALLOC_SCHEME
* block groups per flexgroup, reserve the first block
* group for directories and special files. Regular
* files will start at the second block group. This
* tends to speed up directory access and improves
* fsck times.
*/
block_group &= ~(flex_size-1);
if (S_ISREG(inode->i_mode))
block_group++;
}
bg_start = ext4_group_first_block_no(inode->i_sb, block_group);
last_block = ext4_blocks_count(EXT4_SB(inode->i_sb)->s_es) - 1;
/*
* If we are doing delayed allocation, we don't need take
* colour into account.
*/
if (test_opt(inode->i_sb, DELALLOC))
return bg_start;
if (bg_start + EXT4_BLOCKS_PER_GROUP(inode->i_sb) <= last_block)
colour = (current->pid % 16) *
(EXT4_BLOCKS_PER_GROUP(inode->i_sb) / 16);
else
colour = (current->pid % 16) * ((last_block - bg_start) / 16);
return bg_start + colour + block;
} }
/* /*
...@@ -776,6 +741,16 @@ static int ext4_ext_insert_index(handle_t *handle, struct inode *inode, ...@@ -776,6 +741,16 @@ static int ext4_ext_insert_index(handle_t *handle, struct inode *inode,
logical, le32_to_cpu(curp->p_idx->ei_block)); logical, le32_to_cpu(curp->p_idx->ei_block));
return -EIO; return -EIO;
} }
if (unlikely(le16_to_cpu(curp->p_hdr->eh_entries)
>= le16_to_cpu(curp->p_hdr->eh_max))) {
EXT4_ERROR_INODE(inode,
"eh_entries %d >= eh_max %d!",
le16_to_cpu(curp->p_hdr->eh_entries),
le16_to_cpu(curp->p_hdr->eh_max));
return -EIO;
}
len = EXT_MAX_INDEX(curp->p_hdr) - curp->p_idx; len = EXT_MAX_INDEX(curp->p_hdr) - curp->p_idx;
if (logical > le32_to_cpu(curp->p_idx->ei_block)) { if (logical > le32_to_cpu(curp->p_idx->ei_block)) {
/* insert after */ /* insert after */
...@@ -805,13 +780,6 @@ static int ext4_ext_insert_index(handle_t *handle, struct inode *inode, ...@@ -805,13 +780,6 @@ static int ext4_ext_insert_index(handle_t *handle, struct inode *inode,
ext4_idx_store_pblock(ix, ptr); ext4_idx_store_pblock(ix, ptr);
le16_add_cpu(&curp->p_hdr->eh_entries, 1); le16_add_cpu(&curp->p_hdr->eh_entries, 1);
if (unlikely(le16_to_cpu(curp->p_hdr->eh_entries)
> le16_to_cpu(curp->p_hdr->eh_max))) {
EXT4_ERROR_INODE(inode,
"logical %d == ei_block %d!",
logical, le32_to_cpu(curp->p_idx->ei_block));
return -EIO;
}
if (unlikely(ix > EXT_LAST_INDEX(curp->p_hdr))) { if (unlikely(ix > EXT_LAST_INDEX(curp->p_hdr))) {
EXT4_ERROR_INODE(inode, "ix > EXT_LAST_INDEX!"); EXT4_ERROR_INODE(inode, "ix > EXT_LAST_INDEX!");
return -EIO; return -EIO;
...@@ -1446,8 +1414,7 @@ ext4_ext_next_allocated_block(struct ext4_ext_path *path) ...@@ -1446,8 +1414,7 @@ ext4_ext_next_allocated_block(struct ext4_ext_path *path)
* ext4_ext_next_leaf_block: * ext4_ext_next_leaf_block:
* returns first allocated block from next leaf or EXT_MAX_BLOCKS * returns first allocated block from next leaf or EXT_MAX_BLOCKS
*/ */
static ext4_lblk_t ext4_ext_next_leaf_block(struct inode *inode, static ext4_lblk_t ext4_ext_next_leaf_block(struct ext4_ext_path *path)
struct ext4_ext_path *path)
{ {
int depth; int depth;
...@@ -1757,7 +1724,6 @@ int ext4_ext_insert_extent(handle_t *handle, struct inode *inode, ...@@ -1757,7 +1724,6 @@ int ext4_ext_insert_extent(handle_t *handle, struct inode *inode,
goto merge; goto merge;
} }
repeat:
depth = ext_depth(inode); depth = ext_depth(inode);
eh = path[depth].p_hdr; eh = path[depth].p_hdr;
if (le16_to_cpu(eh->eh_entries) < le16_to_cpu(eh->eh_max)) if (le16_to_cpu(eh->eh_entries) < le16_to_cpu(eh->eh_max))
...@@ -1765,9 +1731,10 @@ int ext4_ext_insert_extent(handle_t *handle, struct inode *inode, ...@@ -1765,9 +1731,10 @@ int ext4_ext_insert_extent(handle_t *handle, struct inode *inode,
/* probably next leaf has space for us? */ /* probably next leaf has space for us? */
fex = EXT_LAST_EXTENT(eh); fex = EXT_LAST_EXTENT(eh);
next = ext4_ext_next_leaf_block(inode, path); next = EXT_MAX_BLOCKS;
if (le32_to_cpu(newext->ee_block) > le32_to_cpu(fex->ee_block) if (le32_to_cpu(newext->ee_block) > le32_to_cpu(fex->ee_block))
&& next != EXT_MAX_BLOCKS) { next = ext4_ext_next_leaf_block(path);
if (next != EXT_MAX_BLOCKS) {
ext_debug("next leaf block - %d\n", next); ext_debug("next leaf block - %d\n", next);
BUG_ON(npath != NULL); BUG_ON(npath != NULL);
npath = ext4_ext_find_extent(inode, next, NULL); npath = ext4_ext_find_extent(inode, next, NULL);
...@@ -1779,7 +1746,7 @@ int ext4_ext_insert_extent(handle_t *handle, struct inode *inode, ...@@ -1779,7 +1746,7 @@ int ext4_ext_insert_extent(handle_t *handle, struct inode *inode,
ext_debug("next leaf isn't full(%d)\n", ext_debug("next leaf isn't full(%d)\n",
le16_to_cpu(eh->eh_entries)); le16_to_cpu(eh->eh_entries));
path = npath; path = npath;
goto repeat; goto has_space;
} }
ext_debug("next leaf has no free space(%d,%d)\n", ext_debug("next leaf has no free space(%d,%d)\n",
le16_to_cpu(eh->eh_entries), le16_to_cpu(eh->eh_max)); le16_to_cpu(eh->eh_entries), le16_to_cpu(eh->eh_max));
...@@ -1839,7 +1806,7 @@ int ext4_ext_insert_extent(handle_t *handle, struct inode *inode, ...@@ -1839,7 +1806,7 @@ int ext4_ext_insert_extent(handle_t *handle, struct inode *inode,
ext4_ext_pblock(newext), ext4_ext_pblock(newext),
ext4_ext_is_uninitialized(newext), ext4_ext_is_uninitialized(newext),
ext4_ext_get_actual_len(newext), ext4_ext_get_actual_len(newext),
nearex, len, nearex + 1, nearex + 2); nearex, len, nearex, nearex + 1);
memmove(nearex + 1, nearex, len); memmove(nearex + 1, nearex, len);
path[depth].p_ext = nearex; path[depth].p_ext = nearex;
} }
...@@ -2052,7 +2019,7 @@ ext4_ext_put_gap_in_cache(struct inode *inode, struct ext4_ext_path *path, ...@@ -2052,7 +2019,7 @@ ext4_ext_put_gap_in_cache(struct inode *inode, struct ext4_ext_path *path,
} }
/* /*
* ext4_ext_in_cache() * ext4_ext_check_cache()
* Checks to see if the given block is in the cache. * Checks to see if the given block is in the cache.
* If it is, the cached extent is stored in the given * If it is, the cached extent is stored in the given
* cache extent pointer. If the cached extent is a hole, * cache extent pointer. If the cached extent is a hole,
...@@ -2134,8 +2101,6 @@ ext4_ext_in_cache(struct inode *inode, ext4_lblk_t block, ...@@ -2134,8 +2101,6 @@ ext4_ext_in_cache(struct inode *inode, ext4_lblk_t block,
/* /*
* ext4_ext_rm_idx: * ext4_ext_rm_idx:
* removes index from the index block. * removes index from the index block.
* It's used in truncate case only, thus all requests are for
* last index in the block only.
*/ */
static int ext4_ext_rm_idx(handle_t *handle, struct inode *inode, static int ext4_ext_rm_idx(handle_t *handle, struct inode *inode,
struct ext4_ext_path *path) struct ext4_ext_path *path)
...@@ -2153,6 +2118,13 @@ static int ext4_ext_rm_idx(handle_t *handle, struct inode *inode, ...@@ -2153,6 +2118,13 @@ static int ext4_ext_rm_idx(handle_t *handle, struct inode *inode,
err = ext4_ext_get_access(handle, inode, path); err = ext4_ext_get_access(handle, inode, path);
if (err) if (err)
return err; return err;
if (path->p_idx != EXT_LAST_INDEX(path->p_hdr)) {
int len = EXT_LAST_INDEX(path->p_hdr) - path->p_idx;
len *= sizeof(struct ext4_extent_idx);
memmove(path->p_idx, path->p_idx + 1, len);
}
le16_add_cpu(&path->p_hdr->eh_entries, -1); le16_add_cpu(&path->p_hdr->eh_entries, -1);
err = ext4_ext_dirty(handle, inode, path); err = ext4_ext_dirty(handle, inode, path);
if (err) if (err)
...@@ -2534,8 +2506,7 @@ ext4_ext_more_to_rm(struct ext4_ext_path *path) ...@@ -2534,8 +2506,7 @@ ext4_ext_more_to_rm(struct ext4_ext_path *path)
return 1; return 1;
} }
static int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start, static int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start)
ext4_lblk_t end)
{ {
struct super_block *sb = inode->i_sb; struct super_block *sb = inode->i_sb;
int depth = ext_depth(inode); int depth = ext_depth(inode);
...@@ -2575,7 +2546,7 @@ static int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start, ...@@ -2575,7 +2546,7 @@ static int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start,
if (i == depth) { if (i == depth) {
/* this is leaf block */ /* this is leaf block */
err = ext4_ext_rm_leaf(handle, inode, path, err = ext4_ext_rm_leaf(handle, inode, path,
start, end); start, EXT_MAX_BLOCKS - 1);
/* root level has p_bh == NULL, brelse() eats this */ /* root level has p_bh == NULL, brelse() eats this */
brelse(path[i].p_bh); brelse(path[i].p_bh);
path[i].p_bh = NULL; path[i].p_bh = NULL;
...@@ -3107,12 +3078,10 @@ static int ext4_convert_unwritten_extents_endio(handle_t *handle, ...@@ -3107,12 +3078,10 @@ static int ext4_convert_unwritten_extents_endio(handle_t *handle,
struct ext4_ext_path *path) struct ext4_ext_path *path)
{ {
struct ext4_extent *ex; struct ext4_extent *ex;
struct ext4_extent_header *eh;
int depth; int depth;
int err = 0; int err = 0;
depth = ext_depth(inode); depth = ext_depth(inode);
eh = path[depth].p_hdr;
ex = path[depth].p_ext; ex = path[depth].p_ext;
ext_debug("ext4_convert_unwritten_extents_endio: inode %lu, logical" ext_debug("ext4_convert_unwritten_extents_endio: inode %lu, logical"
...@@ -3357,8 +3326,8 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode, ...@@ -3357,8 +3326,8 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
trace_ext4_ext_map_blocks_enter(inode, map->m_lblk, map->m_len, flags); trace_ext4_ext_map_blocks_enter(inode, map->m_lblk, map->m_len, flags);
/* check in cache */ /* check in cache */
if (ext4_ext_in_cache(inode, map->m_lblk, &newex) && if (!(flags & EXT4_GET_BLOCKS_PUNCH_OUT_EXT) &&
((flags & EXT4_GET_BLOCKS_PUNCH_OUT_EXT) == 0)) { ext4_ext_in_cache(inode, map->m_lblk, &newex)) {
if (!newex.ee_start_lo && !newex.ee_start_hi) { if (!newex.ee_start_lo && !newex.ee_start_hi) {
if ((flags & EXT4_GET_BLOCKS_CREATE) == 0) { if ((flags & EXT4_GET_BLOCKS_CREATE) == 0) {
/* /*
...@@ -3497,8 +3466,27 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode, ...@@ -3497,8 +3466,27 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
ext4_ext_mark_uninitialized(ex); ext4_ext_mark_uninitialized(ex);
err = ext4_ext_remove_space(inode, map->m_lblk, ext4_ext_invalidate_cache(inode);
map->m_lblk + punched_out);
err = ext4_ext_rm_leaf(handle, inode, path,
map->m_lblk, map->m_lblk + punched_out);
if (!err && path->p_hdr->eh_entries == 0) {
/*
* Punch hole freed all of this sub tree,
* so we need to correct eh_depth
*/
err = ext4_ext_get_access(handle, inode, path);
if (err == 0) {
ext_inode_hdr(inode)->eh_depth = 0;
ext_inode_hdr(inode)->eh_max =
cpu_to_le16(ext4_ext_space_root(
inode, 0));
err = ext4_ext_dirty(
handle, inode, path);
}
}
goto out2; goto out2;
} }
...@@ -3596,17 +3584,18 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode, ...@@ -3596,17 +3584,18 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
} }
err = check_eofblocks_fl(handle, inode, map->m_lblk, path, ar.len); err = check_eofblocks_fl(handle, inode, map->m_lblk, path, ar.len);
if (err) if (!err)
goto out2; err = ext4_ext_insert_extent(handle, inode, path,
&newex, flags);
err = ext4_ext_insert_extent(handle, inode, path, &newex, flags);
if (err) { if (err) {
int fb_flags = flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE ?
EXT4_FREE_BLOCKS_NO_QUOT_UPDATE : 0;
/* free data blocks we just allocated */ /* free data blocks we just allocated */
/* not a good idea to call discard here directly, /* not a good idea to call discard here directly,
* but otherwise we'd need to call it every free() */ * but otherwise we'd need to call it every free() */
ext4_discard_preallocations(inode); ext4_discard_preallocations(inode);
ext4_free_blocks(handle, inode, NULL, ext4_ext_pblock(&newex), ext4_free_blocks(handle, inode, NULL, ext4_ext_pblock(&newex),
ext4_ext_get_actual_len(&newex), 0); ext4_ext_get_actual_len(&newex), fb_flags);
goto out2; goto out2;
} }
...@@ -3699,7 +3688,7 @@ void ext4_ext_truncate(struct inode *inode) ...@@ -3699,7 +3688,7 @@ void ext4_ext_truncate(struct inode *inode)
last_block = (inode->i_size + sb->s_blocksize - 1) last_block = (inode->i_size + sb->s_blocksize - 1)
>> EXT4_BLOCK_SIZE_BITS(sb); >> EXT4_BLOCK_SIZE_BITS(sb);
err = ext4_ext_remove_space(inode, last_block, EXT_MAX_BLOCKS - 1); err = ext4_ext_remove_space(inode, last_block);
/* In a multi-transaction truncate, we only make the final /* In a multi-transaction truncate, we only make the final
* transaction synchronous. * transaction synchronous.
...@@ -3835,7 +3824,7 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len) ...@@ -3835,7 +3824,7 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
blkbits) >> blkbits)) blkbits) >> blkbits))
new_size = offset + len; new_size = offset + len;
else else
new_size = (map.m_lblk + ret) << blkbits; new_size = ((loff_t) map.m_lblk + ret) << blkbits;
ext4_falloc_update_inode(inode, mode, new_size, ext4_falloc_update_inode(inode, mode, new_size,
(map.m_flags & EXT4_MAP_NEW)); (map.m_flags & EXT4_MAP_NEW));
......
...@@ -129,15 +129,30 @@ static int ext4_sync_parent(struct inode *inode) ...@@ -129,15 +129,30 @@ static int ext4_sync_parent(struct inode *inode)
{ {
struct writeback_control wbc; struct writeback_control wbc;
struct dentry *dentry = NULL; struct dentry *dentry = NULL;
struct inode *next;
int ret = 0; int ret = 0;
while (inode && ext4_test_inode_state(inode, EXT4_STATE_NEWENTRY)) { if (!ext4_test_inode_state(inode, EXT4_STATE_NEWENTRY))
return 0;
inode = igrab(inode);
while (ext4_test_inode_state(inode, EXT4_STATE_NEWENTRY)) {
ext4_clear_inode_state(inode, EXT4_STATE_NEWENTRY); ext4_clear_inode_state(inode, EXT4_STATE_NEWENTRY);
dentry = list_entry(inode->i_dentry.next, dentry = NULL;
struct dentry, d_alias); spin_lock(&inode->i_lock);
if (!dentry || !dentry->d_parent || !dentry->d_parent->d_inode) if (!list_empty(&inode->i_dentry)) {
dentry = list_first_entry(&inode->i_dentry,
struct dentry, d_alias);
dget(dentry);
}
spin_unlock(&inode->i_lock);
if (!dentry)
break; break;
inode = dentry->d_parent->d_inode; next = igrab(dentry->d_parent->d_inode);
dput(dentry);
if (!next)
break;
iput(inode);
inode = next;
ret = sync_mapping_buffers(inode->i_mapping); ret = sync_mapping_buffers(inode->i_mapping);
if (ret) if (ret)
break; break;
...@@ -148,6 +163,7 @@ static int ext4_sync_parent(struct inode *inode) ...@@ -148,6 +163,7 @@ static int ext4_sync_parent(struct inode *inode)
if (ret) if (ret)
break; break;
} }
iput(inode);
return ret; return ret;
} }
......
...@@ -1287,7 +1287,7 @@ extern int ext4_init_inode_table(struct super_block *sb, ext4_group_t group, ...@@ -1287,7 +1287,7 @@ extern int ext4_init_inode_table(struct super_block *sb, ext4_group_t group,
group, used_blks, group, used_blks,
ext4_itable_unused_count(sb, gdp)); ext4_itable_unused_count(sb, gdp));
ret = 1; ret = 1;
goto out; goto err_out;
} }
blk = ext4_inode_table(sb, gdp) + used_blks; blk = ext4_inode_table(sb, gdp) + used_blks;
......
This diff is collapsed.
This diff is collapsed.
...@@ -202,8 +202,9 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ...@@ -202,8 +202,9 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
struct super_block *sb = inode->i_sb; struct super_block *sb = inode->i_sb;
int err, err2=0; int err, err2=0;
if (!capable(CAP_SYS_RESOURCE)) err = ext4_resize_begin(sb);
return -EPERM; if (err)
return err;
if (get_user(n_blocks_count, (__u32 __user *)arg)) if (get_user(n_blocks_count, (__u32 __user *)arg))
return -EFAULT; return -EFAULT;
...@@ -221,6 +222,7 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ...@@ -221,6 +222,7 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
if (err == 0) if (err == 0)
err = err2; err = err2;
mnt_drop_write(filp->f_path.mnt); mnt_drop_write(filp->f_path.mnt);
ext4_resize_end(sb);
return err; return err;
} }
...@@ -271,8 +273,9 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ...@@ -271,8 +273,9 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
struct super_block *sb = inode->i_sb; struct super_block *sb = inode->i_sb;
int err, err2=0; int err, err2=0;
if (!capable(CAP_SYS_RESOURCE)) err = ext4_resize_begin(sb);
return -EPERM; if (err)
return err;
if (copy_from_user(&input, (struct ext4_new_group_input __user *)arg, if (copy_from_user(&input, (struct ext4_new_group_input __user *)arg,
sizeof(input))) sizeof(input)))
...@@ -291,6 +294,7 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ...@@ -291,6 +294,7 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
if (err == 0) if (err == 0)
err = err2; err = err2;
mnt_drop_write(filp->f_path.mnt); mnt_drop_write(filp->f_path.mnt);
ext4_resize_end(sb);
return err; return err;
} }
......
This diff is collapsed.
...@@ -187,7 +187,6 @@ struct ext4_allocation_context { ...@@ -187,7 +187,6 @@ struct ext4_allocation_context {
__u16 ac_flags; /* allocation hints */ __u16 ac_flags; /* allocation hints */
__u8 ac_status; __u8 ac_status;
__u8 ac_criteria; __u8 ac_criteria;
__u8 ac_repeats;
__u8 ac_2order; /* if request is to allocate 2^N blocks and __u8 ac_2order; /* if request is to allocate 2^N blocks and
* N > 0, the field stores N, otherwise 0 */ * N > 0, the field stores N, otherwise 0 */
__u8 ac_op; /* operation, for history only */ __u8 ac_op; /* operation, for history only */
......
...@@ -289,7 +289,7 @@ static struct stats dx_show_leaf(struct dx_hash_info *hinfo, struct ext4_dir_ent ...@@ -289,7 +289,7 @@ static struct stats dx_show_leaf(struct dx_hash_info *hinfo, struct ext4_dir_ent
while (len--) printk("%c", *name++); while (len--) printk("%c", *name++);
ext4fs_dirhash(de->name, de->name_len, &h); ext4fs_dirhash(de->name, de->name_len, &h);
printk(":%x.%u ", h.hash, printk(":%x.%u ", h.hash,
((char *) de - base)); (unsigned) ((char *) de - base));
} }
space += EXT4_DIR_REC_LEN(de->name_len); space += EXT4_DIR_REC_LEN(de->name_len);
names++; names++;
...@@ -1013,7 +1013,7 @@ static struct buffer_head * ext4_dx_find_entry(struct inode *dir, const struct q ...@@ -1013,7 +1013,7 @@ static struct buffer_head * ext4_dx_find_entry(struct inode *dir, const struct q
*err = -ENOENT; *err = -ENOENT;
errout: errout:
dxtrace(printk(KERN_DEBUG "%s not found\n", name)); dxtrace(printk(KERN_DEBUG "%s not found\n", d_name->name));
dx_release (frames); dx_release (frames);
return NULL; return NULL;
} }
...@@ -1985,18 +1985,11 @@ int ext4_orphan_add(handle_t *handle, struct inode *inode) ...@@ -1985,18 +1985,11 @@ int ext4_orphan_add(handle_t *handle, struct inode *inode)
if (!list_empty(&EXT4_I(inode)->i_orphan)) if (!list_empty(&EXT4_I(inode)->i_orphan))
goto out_unlock; goto out_unlock;
/* Orphan handling is only valid for files with data blocks /*
* being truncated, or files being unlinked. */ * Orphan handling is only valid for files with data blocks
* being truncated, or files being unlinked. Note that we either
/* @@@ FIXME: Observation from aviro: * hold i_mutex, or the inode can not be referenced from outside,
* I think I can trigger J_ASSERT in ext4_orphan_add(). We block * so i_nlink should not be bumped due to race
* here (on s_orphan_lock), so race with ext4_link() which might bump
* ->i_nlink. For, say it, character device. Not a regular file,
* not a directory, not a symlink and ->i_nlink > 0.
*
* tytso, 4/25/2009: I'm not sure how that could happen;
* shouldn't the fs core protect us from these sort of
* unlink()/link() races?
*/ */
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);
......
...@@ -285,11 +285,7 @@ static int io_submit_init(struct ext4_io_submit *io, ...@@ -285,11 +285,7 @@ static int io_submit_init(struct ext4_io_submit *io,
io_end = ext4_init_io_end(inode, GFP_NOFS); io_end = ext4_init_io_end(inode, GFP_NOFS);
if (!io_end) if (!io_end)
return -ENOMEM; return -ENOMEM;
do { bio = bio_alloc(GFP_NOIO, min(nvecs, BIO_MAX_PAGES));
bio = bio_alloc(GFP_NOIO, nvecs);
nvecs >>= 1;
} while (bio == NULL);
bio->bi_sector = bh->b_blocknr * (bh->b_size >> 9); bio->bi_sector = bh->b_blocknr * (bh->b_size >> 9);
bio->bi_bdev = bh->b_bdev; bio->bi_bdev = bh->b_bdev;
bio->bi_private = io->io_end = io_end; bio->bi_private = io->io_end = io_end;
......
This diff is collapsed.
...@@ -110,6 +110,35 @@ static struct file_system_type ext3_fs_type = { ...@@ -110,6 +110,35 @@ static struct file_system_type ext3_fs_type = {
#define IS_EXT3_SB(sb) (0) #define IS_EXT3_SB(sb) (0)
#endif #endif
void *ext4_kvmalloc(size_t size, gfp_t flags)
{
void *ret;
ret = kmalloc(size, flags);
if (!ret)
ret = __vmalloc(size, flags, PAGE_KERNEL);
return ret;
}
void *ext4_kvzalloc(size_t size, gfp_t flags)
{
void *ret;
ret = kmalloc(size, flags);
if (!ret)
ret = __vmalloc(size, flags | __GFP_ZERO, PAGE_KERNEL);
return ret;
}
void ext4_kvfree(void *ptr)
{
if (is_vmalloc_addr(ptr))
vfree(ptr);
else
kfree(ptr);
}
ext4_fsblk_t ext4_block_bitmap(struct super_block *sb, ext4_fsblk_t ext4_block_bitmap(struct super_block *sb,
struct ext4_group_desc *bg) struct ext4_group_desc *bg)
{ {
...@@ -269,6 +298,7 @@ handle_t *ext4_journal_start_sb(struct super_block *sb, int nblocks) ...@@ -269,6 +298,7 @@ handle_t *ext4_journal_start_sb(struct super_block *sb, int nblocks)
journal_t *journal; journal_t *journal;
handle_t *handle; handle_t *handle;
trace_ext4_journal_start(sb, nblocks, _RET_IP_);
if (sb->s_flags & MS_RDONLY) if (sb->s_flags & MS_RDONLY)
return ERR_PTR(-EROFS); return ERR_PTR(-EROFS);
...@@ -789,11 +819,8 @@ static void ext4_put_super(struct super_block *sb) ...@@ -789,11 +819,8 @@ static void ext4_put_super(struct super_block *sb)
for (i = 0; i < sbi->s_gdb_count; i++) for (i = 0; i < sbi->s_gdb_count; i++)
brelse(sbi->s_group_desc[i]); brelse(sbi->s_group_desc[i]);
kfree(sbi->s_group_desc); ext4_kvfree(sbi->s_group_desc);
if (is_vmalloc_addr(sbi->s_flex_groups)) ext4_kvfree(sbi->s_flex_groups);
vfree(sbi->s_flex_groups);
else
kfree(sbi->s_flex_groups);
percpu_counter_destroy(&sbi->s_freeblocks_counter); percpu_counter_destroy(&sbi->s_freeblocks_counter);
percpu_counter_destroy(&sbi->s_freeinodes_counter); percpu_counter_destroy(&sbi->s_freeinodes_counter);
percpu_counter_destroy(&sbi->s_dirs_counter); percpu_counter_destroy(&sbi->s_dirs_counter);
...@@ -1976,15 +2003,11 @@ static int ext4_fill_flex_info(struct super_block *sb) ...@@ -1976,15 +2003,11 @@ static int ext4_fill_flex_info(struct super_block *sb)
((le16_to_cpu(sbi->s_es->s_reserved_gdt_blocks) + 1) << ((le16_to_cpu(sbi->s_es->s_reserved_gdt_blocks) + 1) <<
EXT4_DESC_PER_BLOCK_BITS(sb))) / groups_per_flex; EXT4_DESC_PER_BLOCK_BITS(sb))) / groups_per_flex;
size = flex_group_count * sizeof(struct flex_groups); size = flex_group_count * sizeof(struct flex_groups);
sbi->s_flex_groups = kzalloc(size, GFP_KERNEL); sbi->s_flex_groups = ext4_kvzalloc(size, GFP_KERNEL);
if (sbi->s_flex_groups == NULL) { if (sbi->s_flex_groups == NULL) {
sbi->s_flex_groups = vzalloc(size); ext4_msg(sb, KERN_ERR, "not enough memory for %u flex groups",
if (sbi->s_flex_groups == NULL) { flex_group_count);
ext4_msg(sb, KERN_ERR, goto failed;
"not enough memory for %u flex groups",
flex_group_count);
goto failed;
}
} }
for (i = 0; i < sbi->s_groups_count; i++) { for (i = 0; i < sbi->s_groups_count; i++) {
...@@ -2383,17 +2406,25 @@ static unsigned long ext4_get_stripe_size(struct ext4_sb_info *sbi) ...@@ -2383,17 +2406,25 @@ static unsigned long ext4_get_stripe_size(struct ext4_sb_info *sbi)
unsigned long stride = le16_to_cpu(sbi->s_es->s_raid_stride); unsigned long stride = le16_to_cpu(sbi->s_es->s_raid_stride);
unsigned long stripe_width = unsigned long stripe_width =
le32_to_cpu(sbi->s_es->s_raid_stripe_width); le32_to_cpu(sbi->s_es->s_raid_stripe_width);
int ret;
if (sbi->s_stripe && sbi->s_stripe <= sbi->s_blocks_per_group) if (sbi->s_stripe && sbi->s_stripe <= sbi->s_blocks_per_group)
return sbi->s_stripe; ret = sbi->s_stripe;
else if (stripe_width <= sbi->s_blocks_per_group)
if (stripe_width <= sbi->s_blocks_per_group) ret = stripe_width;
return stripe_width; else if (stride <= sbi->s_blocks_per_group)
ret = stride;
else
ret = 0;
if (stride <= sbi->s_blocks_per_group) /*
return stride; * If the stripe width is 1, this makes no sense and
* we set it to 0 to turn off stripe handling code.
*/
if (ret <= 1)
ret = 0;
return 0; return ret;
} }
/* sysfs supprt */ /* sysfs supprt */
...@@ -3408,8 +3439,9 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) ...@@ -3408,8 +3439,9 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
(EXT4_MAX_BLOCK_FILE_PHYS / EXT4_BLOCKS_PER_GROUP(sb))); (EXT4_MAX_BLOCK_FILE_PHYS / EXT4_BLOCKS_PER_GROUP(sb)));
db_count = (sbi->s_groups_count + EXT4_DESC_PER_BLOCK(sb) - 1) / db_count = (sbi->s_groups_count + EXT4_DESC_PER_BLOCK(sb) - 1) /
EXT4_DESC_PER_BLOCK(sb); EXT4_DESC_PER_BLOCK(sb);
sbi->s_group_desc = kmalloc(db_count * sizeof(struct buffer_head *), sbi->s_group_desc = ext4_kvmalloc(db_count *
GFP_KERNEL); sizeof(struct buffer_head *),
GFP_KERNEL);
if (sbi->s_group_desc == NULL) { if (sbi->s_group_desc == NULL) {
ext4_msg(sb, KERN_ERR, "not enough memory"); ext4_msg(sb, KERN_ERR, "not enough memory");
goto failed_mount; goto failed_mount;
...@@ -3491,7 +3523,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) ...@@ -3491,7 +3523,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
INIT_LIST_HEAD(&sbi->s_orphan); /* unlinked but open files */ INIT_LIST_HEAD(&sbi->s_orphan); /* unlinked but open files */
mutex_init(&sbi->s_orphan_lock); mutex_init(&sbi->s_orphan_lock);
mutex_init(&sbi->s_resize_lock); sbi->s_resize_flags = 0;
sb->s_root = NULL; sb->s_root = NULL;
...@@ -3741,12 +3773,8 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) ...@@ -3741,12 +3773,8 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
} }
failed_mount3: failed_mount3:
del_timer(&sbi->s_err_report); del_timer(&sbi->s_err_report);
if (sbi->s_flex_groups) { if (sbi->s_flex_groups)
if (is_vmalloc_addr(sbi->s_flex_groups)) ext4_kvfree(sbi->s_flex_groups);
vfree(sbi->s_flex_groups);
else
kfree(sbi->s_flex_groups);
}
percpu_counter_destroy(&sbi->s_freeblocks_counter); percpu_counter_destroy(&sbi->s_freeblocks_counter);
percpu_counter_destroy(&sbi->s_freeinodes_counter); percpu_counter_destroy(&sbi->s_freeinodes_counter);
percpu_counter_destroy(&sbi->s_dirs_counter); percpu_counter_destroy(&sbi->s_dirs_counter);
...@@ -3756,7 +3784,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) ...@@ -3756,7 +3784,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
failed_mount2: failed_mount2:
for (i = 0; i < db_count; i++) for (i = 0; i < db_count; i++)
brelse(sbi->s_group_desc[i]); brelse(sbi->s_group_desc[i]);
kfree(sbi->s_group_desc); ext4_kvfree(sbi->s_group_desc);
failed_mount: failed_mount:
if (sbi->s_proc) { if (sbi->s_proc) {
remove_proc_entry(sb->s_id, ext4_proc_root); remove_proc_entry(sb->s_id, ext4_proc_root);
......
/*
* linux/fs/ext4/truncate.h
*
* Common inline functions needed for truncate support
*/
/*
* Truncate blocks that were not used by write. We have to truncate the
* pagecache as well so that corresponding buffers get properly unmapped.
*/
static inline void ext4_truncate_failed_write(struct inode *inode)
{
truncate_inode_pages(inode->i_mapping, inode->i_size);
ext4_truncate(inode);
}
/*
* Work out how many blocks we need to proceed with the next chunk of a
* truncate transaction.
*/
static inline unsigned long ext4_blocks_for_truncate(struct inode *inode)
{
ext4_lblk_t needed;
needed = inode->i_blocks >> (inode->i_sb->s_blocksize_bits - 9);
/* Give ourselves just enough room to cope with inodes in which
* i_blocks is corrupt: we've seen disk corruptions in the past
* which resulted in random data in an inode which looked enough
* like a regular file for ext4 to try to delete it. Things
* will go a bit crazy if that happens, but at least we should
* try not to panic the whole kernel. */
if (needed < 2)
needed = 2;
/* But we need to bound the transaction so we don't overflow the
* journal. */
if (needed > EXT4_MAX_TRANS_DATA)
needed = EXT4_MAX_TRANS_DATA;
return EXT4_DATA_TRANS_BLOCKS(inode->i_sb) + needed;
}
...@@ -257,9 +257,12 @@ static void ...@@ -257,9 +257,12 @@ static void
__flush_batch(journal_t *journal, int *batch_count) __flush_batch(journal_t *journal, int *batch_count)
{ {
int i; int i;
struct blk_plug plug;
blk_start_plug(&plug);
for (i = 0; i < *batch_count; i++) for (i = 0; i < *batch_count; i++)
write_dirty_buffer(journal->j_chkpt_bhs[i], WRITE); write_dirty_buffer(journal->j_chkpt_bhs[i], WRITE_SYNC);
blk_finish_plug(&plug);
for (i = 0; i < *batch_count; i++) { for (i = 0; i < *batch_count; i++) {
struct buffer_head *bh = journal->j_chkpt_bhs[i]; struct buffer_head *bh = journal->j_chkpt_bhs[i];
......
This diff is collapsed.
...@@ -1329,12 +1329,6 @@ extern int jbd_blocks_per_page(struct inode *inode); ...@@ -1329,12 +1329,6 @@ extern int jbd_blocks_per_page(struct inode *inode);
#define BUFFER_TRACE2(bh, bh2, info) do {} while (0) #define BUFFER_TRACE2(bh, bh2, info) do {} while (0)
#define JBUFFER_TRACE(jh, info) do {} while (0) #define JBUFFER_TRACE(jh, info) do {} while (0)
/*
* jbd2_dev_to_name is a utility function used by the jbd2 and ext4
* tracing infrastructure to map a dev_t to a device name.
*/
extern const char *jbd2_dev_to_name(dev_t device);
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
#endif /* _LINUX_JBD2_H */ #endif /* _LINUX_JBD2_H */
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment