Commit c2661b80 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull ext4 updates from Ted Ts'o:
 "A large number of cleanups and bug fixes, with some (minor) journal
  optimizations"

[ This got sent to me before -rc1, but was stuck in my spam folder.   - Linus ]

* tag 'ext4_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4: (67 commits)
  ext4: check s_chksum_driver when looking for bg csum presence
  ext4: move error report out of atomic context in ext4_init_block_bitmap()
  ext4: Replace open coded mdata csum feature to helper function
  ext4: delete useless comments about ext4_move_extents
  ext4: fix reservation overflow in ext4_da_write_begin
  ext4: add ext4_iget_normal() which is to be used for dir tree lookups
  ext4: don't orphan or truncate the boot loader inode
  ext4: grab missed write_count for EXT4_IOC_SWAP_BOOT
  ext4: optimize block allocation on grow indepth
  ext4: get rid of code duplication
  ext4: fix over-defensive complaint after journal abort
  ext4: fix return value of ext4_do_update_inode
  ext4: fix mmap data corruption when blocksize < pagesize
  vfs: fix data corruption when blocksize < pagesize for mmaped data
  ext4: fold ext4_nojournal_sops into ext4_sops
  ext4: support freezing ext2 (nojournal) file systems
  ext4: fold ext4_sync_fs_nojournal() into ext4_sync_fs()
  ext4: don't check quota format when there are no quota files
  jbd2: simplify calling convention around __jbd2_journal_clean_checkpoint_list
  jbd2: avoid pointless scanning of checkpoint lists
  ...
parents f114040e 813d32f9
...@@ -993,7 +993,7 @@ init_page_buffers(struct page *page, struct block_device *bdev, ...@@ -993,7 +993,7 @@ init_page_buffers(struct page *page, struct block_device *bdev,
*/ */
static int static int
grow_dev_page(struct block_device *bdev, sector_t block, grow_dev_page(struct block_device *bdev, sector_t block,
pgoff_t index, int size, int sizebits) pgoff_t index, int size, int sizebits, gfp_t gfp)
{ {
struct inode *inode = bdev->bd_inode; struct inode *inode = bdev->bd_inode;
struct page *page; struct page *page;
...@@ -1002,8 +1002,8 @@ grow_dev_page(struct block_device *bdev, sector_t block, ...@@ -1002,8 +1002,8 @@ grow_dev_page(struct block_device *bdev, sector_t block,
int ret = 0; /* Will call free_more_memory() */ int ret = 0; /* Will call free_more_memory() */
gfp_t gfp_mask; gfp_t gfp_mask;
gfp_mask = mapping_gfp_mask(inode->i_mapping) & ~__GFP_FS; gfp_mask = (mapping_gfp_mask(inode->i_mapping) & ~__GFP_FS) | gfp;
gfp_mask |= __GFP_MOVABLE;
/* /*
* XXX: __getblk_slow() can not really deal with failure and * XXX: __getblk_slow() can not really deal with failure and
* will endlessly loop on improvised global reclaim. Prefer * will endlessly loop on improvised global reclaim. Prefer
...@@ -1060,7 +1060,7 @@ grow_dev_page(struct block_device *bdev, sector_t block, ...@@ -1060,7 +1060,7 @@ grow_dev_page(struct block_device *bdev, sector_t block,
* that page was dirty, the buffers are set dirty also. * that page was dirty, the buffers are set dirty also.
*/ */
static int static int
grow_buffers(struct block_device *bdev, sector_t block, int size) grow_buffers(struct block_device *bdev, sector_t block, int size, gfp_t gfp)
{ {
pgoff_t index; pgoff_t index;
int sizebits; int sizebits;
...@@ -1087,11 +1087,12 @@ grow_buffers(struct block_device *bdev, sector_t block, int size) ...@@ -1087,11 +1087,12 @@ grow_buffers(struct block_device *bdev, sector_t block, int size)
} }
/* Create a page with the proper size buffers.. */ /* Create a page with the proper size buffers.. */
return grow_dev_page(bdev, block, index, size, sizebits); return grow_dev_page(bdev, block, index, size, sizebits, gfp);
} }
static struct buffer_head * struct buffer_head *
__getblk_slow(struct block_device *bdev, sector_t block, int size) __getblk_slow(struct block_device *bdev, sector_t block,
unsigned size, gfp_t gfp)
{ {
/* Size must be multiple of hard sectorsize */ /* Size must be multiple of hard sectorsize */
if (unlikely(size & (bdev_logical_block_size(bdev)-1) || if (unlikely(size & (bdev_logical_block_size(bdev)-1) ||
...@@ -1113,13 +1114,14 @@ __getblk_slow(struct block_device *bdev, sector_t block, int size) ...@@ -1113,13 +1114,14 @@ __getblk_slow(struct block_device *bdev, sector_t block, int size)
if (bh) if (bh)
return bh; return bh;
ret = grow_buffers(bdev, block, size); ret = grow_buffers(bdev, block, size, gfp);
if (ret < 0) if (ret < 0)
return NULL; return NULL;
if (ret == 0) if (ret == 0)
free_more_memory(); free_more_memory();
} }
} }
EXPORT_SYMBOL(__getblk_slow);
/* /*
* The relationship between dirty buffers and dirty pages: * The relationship between dirty buffers and dirty pages:
...@@ -1373,24 +1375,25 @@ __find_get_block(struct block_device *bdev, sector_t block, unsigned size) ...@@ -1373,24 +1375,25 @@ __find_get_block(struct block_device *bdev, sector_t block, unsigned size)
EXPORT_SYMBOL(__find_get_block); EXPORT_SYMBOL(__find_get_block);
/* /*
* __getblk will locate (and, if necessary, create) the buffer_head * __getblk_gfp() will locate (and, if necessary, create) the buffer_head
* which corresponds to the passed block_device, block and size. The * which corresponds to the passed block_device, block and size. The
* returned buffer has its reference count incremented. * returned buffer has its reference count incremented.
* *
* __getblk() will lock up the machine if grow_dev_page's try_to_free_buffers() * __getblk_gfp() will lock up the machine if grow_dev_page's
* attempt is failing. FIXME, perhaps? * try_to_free_buffers() attempt is failing. FIXME, perhaps?
*/ */
struct buffer_head * struct buffer_head *
__getblk(struct block_device *bdev, sector_t block, unsigned size) __getblk_gfp(struct block_device *bdev, sector_t block,
unsigned size, gfp_t gfp)
{ {
struct buffer_head *bh = __find_get_block(bdev, block, size); struct buffer_head *bh = __find_get_block(bdev, block, size);
might_sleep(); might_sleep();
if (bh == NULL) if (bh == NULL)
bh = __getblk_slow(bdev, block, size); bh = __getblk_slow(bdev, block, size, gfp);
return bh; return bh;
} }
EXPORT_SYMBOL(__getblk); EXPORT_SYMBOL(__getblk_gfp);
/* /*
* Do async read-ahead on a buffer.. * Do async read-ahead on a buffer..
...@@ -1406,24 +1409,28 @@ void __breadahead(struct block_device *bdev, sector_t block, unsigned size) ...@@ -1406,24 +1409,28 @@ void __breadahead(struct block_device *bdev, sector_t block, unsigned size)
EXPORT_SYMBOL(__breadahead); EXPORT_SYMBOL(__breadahead);
/** /**
* __bread() - reads a specified block and returns the bh * __bread_gfp() - reads a specified block and returns the bh
* @bdev: the block_device to read from * @bdev: the block_device to read from
* @block: number of block * @block: number of block
* @size: size (in bytes) to read * @size: size (in bytes) to read
* * @gfp: page allocation flag
*
* Reads a specified block, and returns buffer head that contains it. * Reads a specified block, and returns buffer head that contains it.
* The page cache can be allocated from non-movable area
* not to prevent page migration if you set gfp to zero.
* It returns NULL if the block was unreadable. * It returns NULL if the block was unreadable.
*/ */
struct buffer_head * struct buffer_head *
__bread(struct block_device *bdev, sector_t block, unsigned size) __bread_gfp(struct block_device *bdev, sector_t block,
unsigned size, gfp_t gfp)
{ {
struct buffer_head *bh = __getblk(bdev, block, size); struct buffer_head *bh = __getblk_gfp(bdev, block, size, gfp);
if (likely(bh) && !buffer_uptodate(bh)) if (likely(bh) && !buffer_uptodate(bh))
bh = __bread_slow(bh); bh = __bread_slow(bh);
return bh; return bh;
} }
EXPORT_SYMBOL(__bread); EXPORT_SYMBOL(__bread_gfp);
/* /*
* invalidate_bh_lrus() is called rarely - but not only at unmount. * invalidate_bh_lrus() is called rarely - but not only at unmount.
...@@ -2082,6 +2089,7 @@ int generic_write_end(struct file *file, struct address_space *mapping, ...@@ -2082,6 +2089,7 @@ int generic_write_end(struct file *file, struct address_space *mapping,
struct page *page, void *fsdata) struct page *page, void *fsdata)
{ {
struct inode *inode = mapping->host; struct inode *inode = mapping->host;
loff_t old_size = inode->i_size;
int i_size_changed = 0; int i_size_changed = 0;
copied = block_write_end(file, mapping, pos, len, copied, page, fsdata); copied = block_write_end(file, mapping, pos, len, copied, page, fsdata);
...@@ -2101,6 +2109,8 @@ int generic_write_end(struct file *file, struct address_space *mapping, ...@@ -2101,6 +2109,8 @@ int generic_write_end(struct file *file, struct address_space *mapping,
unlock_page(page); unlock_page(page);
page_cache_release(page); page_cache_release(page);
if (old_size < pos)
pagecache_isize_extended(inode, old_size, pos);
/* /*
* Don't mark the inode dirty under page lock. First, it unnecessarily * Don't mark the inode dirty under page lock. First, it unnecessarily
* makes the holding time of page lock longer. Second, it forces lock * makes the holding time of page lock longer. Second, it forces lock
......
...@@ -176,7 +176,7 @@ static unsigned int num_clusters_in_group(struct super_block *sb, ...@@ -176,7 +176,7 @@ static unsigned int num_clusters_in_group(struct super_block *sb,
} }
/* Initializes an uninitialized block bitmap */ /* Initializes an uninitialized block bitmap */
static void ext4_init_block_bitmap(struct super_block *sb, static int ext4_init_block_bitmap(struct super_block *sb,
struct buffer_head *bh, struct buffer_head *bh,
ext4_group_t block_group, ext4_group_t block_group,
struct ext4_group_desc *gdp) struct ext4_group_desc *gdp)
...@@ -192,7 +192,6 @@ static void ext4_init_block_bitmap(struct super_block *sb, ...@@ -192,7 +192,6 @@ static void ext4_init_block_bitmap(struct super_block *sb,
/* If checksum is bad mark all blocks used to prevent allocation /* If checksum is bad mark all blocks used to prevent allocation
* essentially implementing a per-group read-only flag. */ * essentially implementing a per-group read-only flag. */
if (!ext4_group_desc_csum_verify(sb, block_group, gdp)) { if (!ext4_group_desc_csum_verify(sb, block_group, gdp)) {
ext4_error(sb, "Checksum bad for group %u", block_group);
grp = ext4_get_group_info(sb, block_group); grp = ext4_get_group_info(sb, block_group);
if (!EXT4_MB_GRP_BBITMAP_CORRUPT(grp)) if (!EXT4_MB_GRP_BBITMAP_CORRUPT(grp))
percpu_counter_sub(&sbi->s_freeclusters_counter, percpu_counter_sub(&sbi->s_freeclusters_counter,
...@@ -205,7 +204,7 @@ static void ext4_init_block_bitmap(struct super_block *sb, ...@@ -205,7 +204,7 @@ static void ext4_init_block_bitmap(struct super_block *sb,
count); count);
} }
set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &grp->bb_state); set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &grp->bb_state);
return; return -EIO;
} }
memset(bh->b_data, 0, sb->s_blocksize); memset(bh->b_data, 0, sb->s_blocksize);
...@@ -243,6 +242,7 @@ static void ext4_init_block_bitmap(struct super_block *sb, ...@@ -243,6 +242,7 @@ static void ext4_init_block_bitmap(struct super_block *sb,
sb->s_blocksize * 8, bh->b_data); sb->s_blocksize * 8, bh->b_data);
ext4_block_bitmap_csum_set(sb, block_group, gdp, bh); ext4_block_bitmap_csum_set(sb, block_group, gdp, bh);
ext4_group_desc_csum_set(sb, block_group, gdp); ext4_group_desc_csum_set(sb, block_group, gdp);
return 0;
} }
/* Return the number of free blocks in a block group. It is used when /* Return the number of free blocks in a block group. It is used when
...@@ -438,11 +438,15 @@ ext4_read_block_bitmap_nowait(struct super_block *sb, ext4_group_t block_group) ...@@ -438,11 +438,15 @@ ext4_read_block_bitmap_nowait(struct super_block *sb, ext4_group_t block_group)
} }
ext4_lock_group(sb, block_group); ext4_lock_group(sb, block_group);
if (desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) { if (desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) {
ext4_init_block_bitmap(sb, bh, block_group, desc); int err;
err = ext4_init_block_bitmap(sb, bh, block_group, desc);
set_bitmap_uptodate(bh); set_bitmap_uptodate(bh);
set_buffer_uptodate(bh); set_buffer_uptodate(bh);
ext4_unlock_group(sb, block_group); ext4_unlock_group(sb, block_group);
unlock_buffer(bh); unlock_buffer(bh);
if (err)
ext4_error(sb, "Checksum bad for grp %u", block_group);
return bh; return bh;
} }
ext4_unlock_group(sb, block_group); ext4_unlock_group(sb, block_group);
...@@ -636,8 +640,7 @@ ext4_fsblk_t ext4_new_meta_blocks(handle_t *handle, struct inode *inode, ...@@ -636,8 +640,7 @@ ext4_fsblk_t ext4_new_meta_blocks(handle_t *handle, struct inode *inode,
* Account for the allocated meta blocks. We will never * Account for the allocated meta blocks. We will never
* fail EDQUOT for metdata, but we do account for it. * fail EDQUOT for metdata, but we do account for it.
*/ */
if (!(*errp) && if (!(*errp) && (flags & EXT4_MB_DELALLOC_RESERVED)) {
ext4_test_inode_state(inode, EXT4_STATE_DELALLOC_RESERVED)) {
spin_lock(&EXT4_I(inode)->i_block_reservation_lock); spin_lock(&EXT4_I(inode)->i_block_reservation_lock);
spin_unlock(&EXT4_I(inode)->i_block_reservation_lock); spin_unlock(&EXT4_I(inode)->i_block_reservation_lock);
dquot_alloc_block_nofail(inode, dquot_alloc_block_nofail(inode,
......
...@@ -24,8 +24,7 @@ int ext4_inode_bitmap_csum_verify(struct super_block *sb, ext4_group_t group, ...@@ -24,8 +24,7 @@ int ext4_inode_bitmap_csum_verify(struct super_block *sb, ext4_group_t group,
__u32 provided, calculated; __u32 provided, calculated;
struct ext4_sb_info *sbi = EXT4_SB(sb); struct ext4_sb_info *sbi = EXT4_SB(sb);
if (!EXT4_HAS_RO_COMPAT_FEATURE(sb, if (!ext4_has_metadata_csum(sb))
EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
return 1; return 1;
provided = le16_to_cpu(gdp->bg_inode_bitmap_csum_lo); provided = le16_to_cpu(gdp->bg_inode_bitmap_csum_lo);
...@@ -46,8 +45,7 @@ void ext4_inode_bitmap_csum_set(struct super_block *sb, ext4_group_t group, ...@@ -46,8 +45,7 @@ void ext4_inode_bitmap_csum_set(struct super_block *sb, ext4_group_t group,
__u32 csum; __u32 csum;
struct ext4_sb_info *sbi = EXT4_SB(sb); struct ext4_sb_info *sbi = EXT4_SB(sb);
if (!EXT4_HAS_RO_COMPAT_FEATURE(sb, if (!ext4_has_metadata_csum(sb))
EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
return; return;
csum = ext4_chksum(sbi, sbi->s_csum_seed, (__u8 *)bh->b_data, sz); csum = ext4_chksum(sbi, sbi->s_csum_seed, (__u8 *)bh->b_data, sz);
...@@ -65,8 +63,7 @@ int ext4_block_bitmap_csum_verify(struct super_block *sb, ext4_group_t group, ...@@ -65,8 +63,7 @@ int ext4_block_bitmap_csum_verify(struct super_block *sb, ext4_group_t group,
struct ext4_sb_info *sbi = EXT4_SB(sb); struct ext4_sb_info *sbi = EXT4_SB(sb);
int sz = EXT4_CLUSTERS_PER_GROUP(sb) / 8; int sz = EXT4_CLUSTERS_PER_GROUP(sb) / 8;
if (!EXT4_HAS_RO_COMPAT_FEATURE(sb, if (!ext4_has_metadata_csum(sb))
EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
return 1; return 1;
provided = le16_to_cpu(gdp->bg_block_bitmap_csum_lo); provided = le16_to_cpu(gdp->bg_block_bitmap_csum_lo);
...@@ -91,8 +88,7 @@ void ext4_block_bitmap_csum_set(struct super_block *sb, ext4_group_t group, ...@@ -91,8 +88,7 @@ void ext4_block_bitmap_csum_set(struct super_block *sb, ext4_group_t group,
__u32 csum; __u32 csum;
struct ext4_sb_info *sbi = EXT4_SB(sb); struct ext4_sb_info *sbi = EXT4_SB(sb);
if (!EXT4_HAS_RO_COMPAT_FEATURE(sb, if (!ext4_has_metadata_csum(sb))
EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
return; return;
csum = ext4_chksum(sbi, sbi->s_csum_seed, (__u8 *)bh->b_data, sz); csum = ext4_chksum(sbi, sbi->s_csum_seed, (__u8 *)bh->b_data, sz);
......
...@@ -151,13 +151,11 @@ static int ext4_readdir(struct file *file, struct dir_context *ctx) ...@@ -151,13 +151,11 @@ static int ext4_readdir(struct file *file, struct dir_context *ctx)
&file->f_ra, file, &file->f_ra, file,
index, 1); index, 1);
file->f_ra.prev_pos = (loff_t)index << PAGE_CACHE_SHIFT; file->f_ra.prev_pos = (loff_t)index << PAGE_CACHE_SHIFT;
bh = ext4_bread(NULL, inode, map.m_lblk, 0, &err); bh = ext4_bread(NULL, inode, map.m_lblk, 0);
if (IS_ERR(bh))
return PTR_ERR(bh);
} }
/*
* We ignore I/O errors on directories so users have a chance
* of recovering data when there's a bad sector
*/
if (!bh) { if (!bh) {
if (!dir_has_error) { if (!dir_has_error) {
EXT4_ERROR_FILE(file, 0, EXT4_ERROR_FILE(file, 0,
......
...@@ -572,15 +572,15 @@ enum { ...@@ -572,15 +572,15 @@ enum {
/* /*
* The bit position of these flags must not overlap with any of the * The bit position of these flags must not overlap with any of the
* EXT4_GET_BLOCKS_*. They are used by ext4_ext_find_extent(), * EXT4_GET_BLOCKS_*. They are used by ext4_find_extent(),
* read_extent_tree_block(), ext4_split_extent_at(), * read_extent_tree_block(), ext4_split_extent_at(),
* ext4_ext_insert_extent(), and ext4_ext_create_new_leaf(). * ext4_ext_insert_extent(), and ext4_ext_create_new_leaf().
* EXT4_EX_NOCACHE is used to indicate that the we shouldn't be * EXT4_EX_NOCACHE is used to indicate that the we shouldn't be
* caching the extents when reading from the extent tree while a * caching the extents when reading from the extent tree while a
* truncate or punch hole operation is in progress. * truncate or punch hole operation is in progress.
*/ */
#define EXT4_EX_NOCACHE 0x0400 #define EXT4_EX_NOCACHE 0x40000000
#define EXT4_EX_FORCE_CACHE 0x0800 #define EXT4_EX_FORCE_CACHE 0x20000000
/* /*
* Flags used by ext4_free_blocks * Flags used by ext4_free_blocks
...@@ -890,6 +890,7 @@ struct ext4_inode_info { ...@@ -890,6 +890,7 @@ struct ext4_inode_info {
struct ext4_es_tree i_es_tree; struct ext4_es_tree i_es_tree;
rwlock_t i_es_lock; rwlock_t i_es_lock;
struct list_head i_es_lru; struct list_head i_es_lru;
unsigned int i_es_all_nr; /* protected by i_es_lock */
unsigned int i_es_lru_nr; /* protected by i_es_lock */ unsigned int i_es_lru_nr; /* protected by i_es_lock */
unsigned long i_touch_when; /* jiffies of last accessing */ unsigned long i_touch_when; /* jiffies of last accessing */
...@@ -1174,6 +1175,9 @@ struct ext4_super_block { ...@@ -1174,6 +1175,9 @@ struct ext4_super_block {
#define EXT4_MF_MNTDIR_SAMPLED 0x0001 #define EXT4_MF_MNTDIR_SAMPLED 0x0001
#define EXT4_MF_FS_ABORTED 0x0002 /* Fatal error detected */ #define EXT4_MF_FS_ABORTED 0x0002 /* Fatal error detected */
/* Number of quota types we support */
#define EXT4_MAXQUOTAS 2
/* /*
* fourth extended-fs super-block data in memory * fourth extended-fs super-block data in memory
*/ */
...@@ -1237,7 +1241,7 @@ struct ext4_sb_info { ...@@ -1237,7 +1241,7 @@ struct ext4_sb_info {
u32 s_min_batch_time; u32 s_min_batch_time;
struct block_device *journal_bdev; struct block_device *journal_bdev;
#ifdef CONFIG_QUOTA #ifdef CONFIG_QUOTA
char *s_qf_names[MAXQUOTAS]; /* Names of quota files with journalled quota */ char *s_qf_names[EXT4_MAXQUOTAS]; /* Names of quota files with journalled quota */
int s_jquota_fmt; /* Format of quota to use */ int s_jquota_fmt; /* Format of quota to use */
#endif #endif
unsigned int s_want_extra_isize; /* New inodes should reserve # bytes */ unsigned int s_want_extra_isize; /* New inodes should reserve # bytes */
...@@ -1330,8 +1334,7 @@ struct ext4_sb_info { ...@@ -1330,8 +1334,7 @@ struct ext4_sb_info {
/* Reclaim extents from extent status tree */ /* Reclaim extents from extent status tree */
struct shrinker s_es_shrinker; struct shrinker s_es_shrinker;
struct list_head s_es_lru; struct list_head s_es_lru;
unsigned long s_es_last_sorted; struct ext4_es_stats s_es_stats;
struct percpu_counter s_extent_cache_cnt;
struct mb_cache *s_mb_cache; struct mb_cache *s_mb_cache;
spinlock_t s_es_lru_lock ____cacheline_aligned_in_smp; spinlock_t s_es_lru_lock ____cacheline_aligned_in_smp;
...@@ -1399,7 +1402,6 @@ enum { ...@@ -1399,7 +1402,6 @@ enum {
EXT4_STATE_EXT_MIGRATE, /* Inode is migrating */ EXT4_STATE_EXT_MIGRATE, /* Inode is migrating */
EXT4_STATE_DIO_UNWRITTEN, /* need convert on dio done*/ EXT4_STATE_DIO_UNWRITTEN, /* need convert on dio done*/
EXT4_STATE_NEWENTRY, /* File just added to dir */ EXT4_STATE_NEWENTRY, /* File just added to dir */
EXT4_STATE_DELALLOC_RESERVED, /* blks already reserved for delalloc */
EXT4_STATE_DIOREAD_LOCK, /* Disable support for dio read EXT4_STATE_DIOREAD_LOCK, /* Disable support for dio read
nolocking */ nolocking */
EXT4_STATE_MAY_INLINE_DATA, /* may have in-inode data */ EXT4_STATE_MAY_INLINE_DATA, /* may have in-inode data */
...@@ -2086,10 +2088,8 @@ extern int ext4_group_add_blocks(handle_t *handle, struct super_block *sb, ...@@ -2086,10 +2088,8 @@ extern int ext4_group_add_blocks(handle_t *handle, struct super_block *sb,
extern int ext4_trim_fs(struct super_block *, struct fstrim_range *); extern int ext4_trim_fs(struct super_block *, struct fstrim_range *);
/* inode.c */ /* inode.c */
struct buffer_head *ext4_getblk(handle_t *, struct inode *, struct buffer_head *ext4_getblk(handle_t *, struct inode *, ext4_lblk_t, int);
ext4_lblk_t, int, int *); struct buffer_head *ext4_bread(handle_t *, struct inode *, ext4_lblk_t, int);
struct buffer_head *ext4_bread(handle_t *, struct inode *,
ext4_lblk_t, int, int *);
int ext4_get_block_write(struct inode *inode, sector_t iblock, int ext4_get_block_write(struct inode *inode, sector_t iblock,
struct buffer_head *bh_result, int create); struct buffer_head *bh_result, int create);
int ext4_get_block(struct inode *inode, sector_t iblock, int ext4_get_block(struct inode *inode, sector_t iblock,
...@@ -2109,6 +2109,7 @@ int do_journal_get_write_access(handle_t *handle, ...@@ -2109,6 +2109,7 @@ int do_journal_get_write_access(handle_t *handle,
#define CONVERT_INLINE_DATA 2 #define CONVERT_INLINE_DATA 2
extern struct inode *ext4_iget(struct super_block *, unsigned long); extern struct inode *ext4_iget(struct super_block *, unsigned long);
extern struct inode *ext4_iget_normal(struct super_block *, unsigned long);
extern int ext4_write_inode(struct inode *, struct writeback_control *); extern int ext4_write_inode(struct inode *, struct writeback_control *);
extern int ext4_setattr(struct dentry *, struct iattr *); extern int ext4_setattr(struct dentry *, struct iattr *);
extern int ext4_getattr(struct vfsmount *mnt, struct dentry *dentry, extern int ext4_getattr(struct vfsmount *mnt, struct dentry *dentry,
...@@ -2332,10 +2333,18 @@ extern int ext4_register_li_request(struct super_block *sb, ...@@ -2332,10 +2333,18 @@ extern int ext4_register_li_request(struct super_block *sb,
static inline int ext4_has_group_desc_csum(struct super_block *sb) static inline int ext4_has_group_desc_csum(struct super_block *sb)
{ {
return EXT4_HAS_RO_COMPAT_FEATURE(sb, return EXT4_HAS_RO_COMPAT_FEATURE(sb,
EXT4_FEATURE_RO_COMPAT_GDT_CSUM | EXT4_FEATURE_RO_COMPAT_GDT_CSUM) ||
EXT4_FEATURE_RO_COMPAT_METADATA_CSUM); (EXT4_SB(sb)->s_chksum_driver != NULL);
} }
static inline int ext4_has_metadata_csum(struct super_block *sb)
{
WARN_ON_ONCE(EXT4_HAS_RO_COMPAT_FEATURE(sb,
EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) &&
!EXT4_SB(sb)->s_chksum_driver);
return (EXT4_SB(sb)->s_chksum_driver != NULL);
}
static inline ext4_fsblk_t ext4_blocks_count(struct ext4_super_block *es) static inline ext4_fsblk_t ext4_blocks_count(struct ext4_super_block *es)
{ {
return ((ext4_fsblk_t)le32_to_cpu(es->s_blocks_count_hi) << 32) | return ((ext4_fsblk_t)le32_to_cpu(es->s_blocks_count_hi) << 32) |
...@@ -2731,21 +2740,26 @@ extern int ext4_can_extents_be_merged(struct inode *inode, ...@@ -2731,21 +2740,26 @@ extern int ext4_can_extents_be_merged(struct inode *inode,
struct ext4_extent *ex1, struct ext4_extent *ex1,
struct ext4_extent *ex2); struct ext4_extent *ex2);
extern int ext4_ext_insert_extent(handle_t *, struct inode *, extern int ext4_ext_insert_extent(handle_t *, struct inode *,
struct ext4_ext_path *, struct ext4_ext_path **,
struct ext4_extent *, int); struct ext4_extent *, int);
extern struct ext4_ext_path *ext4_ext_find_extent(struct inode *, ext4_lblk_t, extern struct ext4_ext_path *ext4_find_extent(struct inode *, ext4_lblk_t,
struct ext4_ext_path *, struct ext4_ext_path **,
int flags); int flags);
extern void ext4_ext_drop_refs(struct ext4_ext_path *); extern void ext4_ext_drop_refs(struct ext4_ext_path *);
extern int ext4_ext_check_inode(struct inode *inode); extern int ext4_ext_check_inode(struct inode *inode);
extern int ext4_find_delalloc_range(struct inode *inode, extern int ext4_find_delalloc_range(struct inode *inode,
ext4_lblk_t lblk_start, ext4_lblk_t lblk_start,
ext4_lblk_t lblk_end); ext4_lblk_t lblk_end);
extern int ext4_find_delalloc_cluster(struct inode *inode, ext4_lblk_t lblk); extern int ext4_find_delalloc_cluster(struct inode *inode, ext4_lblk_t lblk);
extern ext4_lblk_t ext4_ext_next_allocated_block(struct ext4_ext_path *path);
extern int ext4_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, extern int ext4_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
__u64 start, __u64 len); __u64 start, __u64 len);
extern int ext4_ext_precache(struct inode *inode); extern int ext4_ext_precache(struct inode *inode);
extern int ext4_collapse_range(struct inode *inode, loff_t offset, loff_t len); extern int ext4_collapse_range(struct inode *inode, loff_t offset, loff_t len);
extern int ext4_swap_extents(handle_t *handle, struct inode *inode1,
struct inode *inode2, ext4_lblk_t lblk1,
ext4_lblk_t lblk2, ext4_lblk_t count,
int mark_unwritten,int *err);
/* move_extent.c */ /* move_extent.c */
extern void ext4_double_down_write_data_sem(struct inode *first, extern void ext4_double_down_write_data_sem(struct inode *first,
...@@ -2755,8 +2769,6 @@ extern void ext4_double_up_write_data_sem(struct inode *orig_inode, ...@@ -2755,8 +2769,6 @@ extern void ext4_double_up_write_data_sem(struct inode *orig_inode,
extern int ext4_move_extents(struct file *o_filp, struct file *d_filp, extern int ext4_move_extents(struct file *o_filp, struct file *d_filp,
__u64 start_orig, __u64 start_donor, __u64 start_orig, __u64 start_donor,
__u64 len, __u64 *moved_len); __u64 len, __u64 *moved_len);
extern int mext_next_extent(struct inode *inode, struct ext4_ext_path *path,
struct ext4_extent **extent);
/* page-io.c */ /* page-io.c */
extern int __init ext4_init_pageio(void); extern int __init ext4_init_pageio(void);
......
...@@ -123,6 +123,7 @@ find_ext4_extent_tail(struct ext4_extent_header *eh) ...@@ -123,6 +123,7 @@ find_ext4_extent_tail(struct ext4_extent_header *eh)
struct ext4_ext_path { struct ext4_ext_path {
ext4_fsblk_t p_block; ext4_fsblk_t p_block;
__u16 p_depth; __u16 p_depth;
__u16 p_maxdepth;
struct ext4_extent *p_ext; struct ext4_extent *p_ext;
struct ext4_extent_idx *p_idx; struct ext4_extent_idx *p_idx;
struct ext4_extent_header *p_hdr; struct ext4_extent_header *p_hdr;
......
...@@ -256,8 +256,8 @@ int __ext4_handle_dirty_metadata(const char *where, unsigned int line, ...@@ -256,8 +256,8 @@ int __ext4_handle_dirty_metadata(const char *where, unsigned int line,
set_buffer_prio(bh); set_buffer_prio(bh);
if (ext4_handle_valid(handle)) { if (ext4_handle_valid(handle)) {
err = jbd2_journal_dirty_metadata(handle, bh); err = jbd2_journal_dirty_metadata(handle, bh);
/* Errors can only happen if there is a bug */ /* Errors can only happen due to aborted journal or a nasty bug */
if (WARN_ON_ONCE(err)) { if (!is_handle_aborted(handle) && WARN_ON_ONCE(err)) {
ext4_journal_abort_handle(where, line, __func__, bh, ext4_journal_abort_handle(where, line, __func__, bh,
handle, err); handle, err);
if (inode == NULL) { if (inode == NULL) {
......
...@@ -102,9 +102,9 @@ ...@@ -102,9 +102,9 @@
#define EXT4_QUOTA_INIT_BLOCKS(sb) 0 #define EXT4_QUOTA_INIT_BLOCKS(sb) 0
#define EXT4_QUOTA_DEL_BLOCKS(sb) 0 #define EXT4_QUOTA_DEL_BLOCKS(sb) 0
#endif #endif
#define EXT4_MAXQUOTAS_TRANS_BLOCKS(sb) (MAXQUOTAS*EXT4_QUOTA_TRANS_BLOCKS(sb)) #define EXT4_MAXQUOTAS_TRANS_BLOCKS(sb) (EXT4_MAXQUOTAS*EXT4_QUOTA_TRANS_BLOCKS(sb))
#define EXT4_MAXQUOTAS_INIT_BLOCKS(sb) (MAXQUOTAS*EXT4_QUOTA_INIT_BLOCKS(sb)) #define EXT4_MAXQUOTAS_INIT_BLOCKS(sb) (EXT4_MAXQUOTAS*EXT4_QUOTA_INIT_BLOCKS(sb))
#define EXT4_MAXQUOTAS_DEL_BLOCKS(sb) (MAXQUOTAS*EXT4_QUOTA_DEL_BLOCKS(sb)) #define EXT4_MAXQUOTAS_DEL_BLOCKS(sb) (EXT4_MAXQUOTAS*EXT4_QUOTA_DEL_BLOCKS(sb))
static inline int ext4_jbd2_credits_xattr(struct inode *inode) static inline int ext4_jbd2_credits_xattr(struct inode *inode)
{ {
......
This diff is collapsed.
This diff is collapsed.
...@@ -64,6 +64,17 @@ struct ext4_es_tree { ...@@ -64,6 +64,17 @@ struct ext4_es_tree {
struct extent_status *cache_es; /* recently accessed extent */ struct extent_status *cache_es; /* recently accessed extent */
}; };
struct ext4_es_stats {
unsigned long es_stats_last_sorted;
unsigned long es_stats_shrunk;
unsigned long es_stats_cache_hits;
unsigned long es_stats_cache_misses;
u64 es_stats_scan_time;
u64 es_stats_max_scan_time;
struct percpu_counter es_stats_all_cnt;
struct percpu_counter es_stats_lru_cnt;
};
extern int __init ext4_init_es(void); extern int __init ext4_init_es(void);
extern void ext4_exit_es(void); extern void ext4_exit_es(void);
extern void ext4_es_init_tree(struct ext4_es_tree *tree); extern void ext4_es_init_tree(struct ext4_es_tree *tree);
...@@ -138,7 +149,7 @@ static inline void ext4_es_store_pblock_status(struct extent_status *es, ...@@ -138,7 +149,7 @@ static inline void ext4_es_store_pblock_status(struct extent_status *es,
(pb & ~ES_MASK)); (pb & ~ES_MASK));
} }
extern void ext4_es_register_shrinker(struct ext4_sb_info *sbi); extern int ext4_es_register_shrinker(struct ext4_sb_info *sbi);
extern void ext4_es_unregister_shrinker(struct ext4_sb_info *sbi); extern void ext4_es_unregister_shrinker(struct ext4_sb_info *sbi);
extern void ext4_es_lru_add(struct inode *inode); extern void ext4_es_lru_add(struct inode *inode);
extern void ext4_es_lru_del(struct inode *inode); extern void ext4_es_lru_del(struct inode *inode);
......
...@@ -1011,8 +1011,7 @@ struct inode *__ext4_new_inode(handle_t *handle, struct inode *dir, ...@@ -1011,8 +1011,7 @@ struct inode *__ext4_new_inode(handle_t *handle, struct inode *dir,
spin_unlock(&sbi->s_next_gen_lock); spin_unlock(&sbi->s_next_gen_lock);
/* Precompute checksum seed for inode metadata */ /* Precompute checksum seed for inode metadata */
if (EXT4_HAS_RO_COMPAT_FEATURE(sb, if (ext4_has_metadata_csum(sb)) {
EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) {
__u32 csum; __u32 csum;
__le32 inum = cpu_to_le32(inode->i_ino); __le32 inum = cpu_to_le32(inode->i_ino);
__le32 gen = cpu_to_le32(inode->i_generation); __le32 gen = cpu_to_le32(inode->i_generation);
......
...@@ -318,34 +318,24 @@ static int ext4_blks_to_allocate(Indirect *branch, int k, unsigned int blks, ...@@ -318,34 +318,24 @@ static int ext4_blks_to_allocate(Indirect *branch, int k, unsigned int blks,
* ext4_alloc_block() (normally -ENOSPC). Otherwise we set the chain * ext4_alloc_block() (normally -ENOSPC). Otherwise we set the chain
* as described above and return 0. * as described above and return 0.
*/ */
static int ext4_alloc_branch(handle_t *handle, struct inode *inode, static int ext4_alloc_branch(handle_t *handle,
ext4_lblk_t iblock, int indirect_blks, struct ext4_allocation_request *ar,
int *blks, ext4_fsblk_t goal, int indirect_blks, ext4_lblk_t *offsets,
ext4_lblk_t *offsets, Indirect *branch) Indirect *branch)
{ {
struct ext4_allocation_request ar;
struct buffer_head * bh; struct buffer_head * bh;
ext4_fsblk_t b, new_blocks[4]; ext4_fsblk_t b, new_blocks[4];
__le32 *p; __le32 *p;
int i, j, err, len = 1; int i, j, err, len = 1;
/*
* Set up for the direct block allocation
*/
memset(&ar, 0, sizeof(ar));
ar.inode = inode;
ar.len = *blks;
ar.logical = iblock;
if (S_ISREG(inode->i_mode))
ar.flags = EXT4_MB_HINT_DATA;
for (i = 0; i <= indirect_blks; i++) { for (i = 0; i <= indirect_blks; i++) {
if (i == indirect_blks) { if (i == indirect_blks) {
ar.goal = goal; new_blocks[i] = ext4_mb_new_blocks(handle, ar, &err);
new_blocks[i] = ext4_mb_new_blocks(handle, &ar, &err);
} else } else
goal = new_blocks[i] = ext4_new_meta_blocks(handle, inode, ar->goal = new_blocks[i] = ext4_new_meta_blocks(handle,
goal, 0, NULL, &err); ar->inode, ar->goal,
ar->flags & EXT4_MB_DELALLOC_RESERVED,
NULL, &err);
if (err) { if (err) {
i--; i--;
goto failed; goto failed;
...@@ -354,7 +344,7 @@ static int ext4_alloc_branch(handle_t *handle, struct inode *inode, ...@@ -354,7 +344,7 @@ static int ext4_alloc_branch(handle_t *handle, struct inode *inode,
if (i == 0) if (i == 0)
continue; continue;
bh = branch[i].bh = sb_getblk(inode->i_sb, new_blocks[i-1]); bh = branch[i].bh = sb_getblk(ar->inode->i_sb, new_blocks[i-1]);
if (unlikely(!bh)) { if (unlikely(!bh)) {
err = -ENOMEM; err = -ENOMEM;
goto failed; goto failed;
...@@ -372,7 +362,7 @@ static int ext4_alloc_branch(handle_t *handle, struct inode *inode, ...@@ -372,7 +362,7 @@ static int ext4_alloc_branch(handle_t *handle, struct inode *inode,
b = new_blocks[i]; b = new_blocks[i];
if (i == indirect_blks) if (i == indirect_blks)
len = ar.len; len = ar->len;
for (j = 0; j < len; j++) for (j = 0; j < len; j++)
*p++ = cpu_to_le32(b++); *p++ = cpu_to_le32(b++);
...@@ -381,11 +371,10 @@ static int ext4_alloc_branch(handle_t *handle, struct inode *inode, ...@@ -381,11 +371,10 @@ static int ext4_alloc_branch(handle_t *handle, struct inode *inode,
unlock_buffer(bh); unlock_buffer(bh);
BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata"); BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata");
err = ext4_handle_dirty_metadata(handle, inode, bh); err = ext4_handle_dirty_metadata(handle, ar->inode, bh);
if (err) if (err)
goto failed; goto failed;
} }
*blks = ar.len;
return 0; return 0;
failed: failed:
for (; i >= 0; i--) { for (; i >= 0; i--) {
...@@ -396,10 +385,10 @@ static int ext4_alloc_branch(handle_t *handle, struct inode *inode, ...@@ -396,10 +385,10 @@ static int ext4_alloc_branch(handle_t *handle, struct inode *inode,
* existing before ext4_alloc_branch() was called. * existing before ext4_alloc_branch() was called.
*/ */
if (i > 0 && i != indirect_blks && branch[i].bh) if (i > 0 && i != indirect_blks && branch[i].bh)
ext4_forget(handle, 1, inode, branch[i].bh, ext4_forget(handle, 1, ar->inode, branch[i].bh,
branch[i].bh->b_blocknr); branch[i].bh->b_blocknr);
ext4_free_blocks(handle, inode, NULL, new_blocks[i], ext4_free_blocks(handle, ar->inode, NULL, new_blocks[i],
(i == indirect_blks) ? ar.len : 1, 0); (i == indirect_blks) ? ar->len : 1, 0);
} }
return err; return err;
} }
...@@ -419,9 +408,9 @@ static int ext4_alloc_branch(handle_t *handle, struct inode *inode, ...@@ -419,9 +408,9 @@ static int ext4_alloc_branch(handle_t *handle, struct inode *inode,
* inode (->i_blocks, etc.). In case of success we end up with the full * inode (->i_blocks, etc.). In case of success we end up with the full
* chain to new block and return 0. * chain to new block and return 0.
*/ */
static int ext4_splice_branch(handle_t *handle, struct inode *inode, static int ext4_splice_branch(handle_t *handle,
ext4_lblk_t block, Indirect *where, int num, struct ext4_allocation_request *ar,
int blks) Indirect *where, int num)
{ {
int i; int i;
int err = 0; int err = 0;
...@@ -446,9 +435,9 @@ static int ext4_splice_branch(handle_t *handle, struct inode *inode, ...@@ -446,9 +435,9 @@ static int ext4_splice_branch(handle_t *handle, struct inode *inode,
* Update the host buffer_head or inode to point to more just allocated * Update the host buffer_head or inode to point to more just allocated
* direct blocks blocks * direct blocks blocks
*/ */
if (num == 0 && blks > 1) { if (num == 0 && ar->len > 1) {
current_block = le32_to_cpu(where->key) + 1; current_block = le32_to_cpu(where->key) + 1;
for (i = 1; i < blks; i++) for (i = 1; i < ar->len; i++)
*(where->p + i) = cpu_to_le32(current_block++); *(where->p + i) = cpu_to_le32(current_block++);
} }
...@@ -465,14 +454,14 @@ static int ext4_splice_branch(handle_t *handle, struct inode *inode, ...@@ -465,14 +454,14 @@ static int ext4_splice_branch(handle_t *handle, struct inode *inode,
*/ */
jbd_debug(5, "splicing indirect only\n"); jbd_debug(5, "splicing indirect only\n");
BUFFER_TRACE(where->bh, "call ext4_handle_dirty_metadata"); BUFFER_TRACE(where->bh, "call ext4_handle_dirty_metadata");
err = ext4_handle_dirty_metadata(handle, inode, where->bh); err = ext4_handle_dirty_metadata(handle, ar->inode, where->bh);
if (err) if (err)
goto err_out; goto err_out;
} else { } else {
/* /*
* OK, we spliced it into the inode itself on a direct block. * OK, we spliced it into the inode itself on a direct block.
*/ */
ext4_mark_inode_dirty(handle, inode); ext4_mark_inode_dirty(handle, ar->inode);
jbd_debug(5, "splicing direct\n"); jbd_debug(5, "splicing direct\n");
} }
return err; return err;
...@@ -484,11 +473,11 @@ static int ext4_splice_branch(handle_t *handle, struct inode *inode, ...@@ -484,11 +473,11 @@ static int ext4_splice_branch(handle_t *handle, struct inode *inode,
* need to revoke the block, which is why we don't * need to revoke the block, which is why we don't
* need to set EXT4_FREE_BLOCKS_METADATA. * need to set EXT4_FREE_BLOCKS_METADATA.
*/ */
ext4_free_blocks(handle, inode, where[i].bh, 0, 1, ext4_free_blocks(handle, ar->inode, where[i].bh, 0, 1,
EXT4_FREE_BLOCKS_FORGET); EXT4_FREE_BLOCKS_FORGET);
} }
ext4_free_blocks(handle, inode, NULL, le32_to_cpu(where[num].key), ext4_free_blocks(handle, ar->inode, NULL, le32_to_cpu(where[num].key),
blks, 0); ar->len, 0);
return err; return err;
} }
...@@ -525,11 +514,11 @@ int ext4_ind_map_blocks(handle_t *handle, struct inode *inode, ...@@ -525,11 +514,11 @@ int ext4_ind_map_blocks(handle_t *handle, struct inode *inode,
struct ext4_map_blocks *map, struct ext4_map_blocks *map,
int flags) int flags)
{ {
struct ext4_allocation_request ar;
int err = -EIO; int err = -EIO;
ext4_lblk_t offsets[4]; ext4_lblk_t offsets[4];
Indirect chain[4]; Indirect chain[4];
Indirect *partial; Indirect *partial;
ext4_fsblk_t goal;
int indirect_blks; int indirect_blks;
int blocks_to_boundary = 0; int blocks_to_boundary = 0;
int depth; int depth;
...@@ -579,7 +568,16 @@ int ext4_ind_map_blocks(handle_t *handle, struct inode *inode, ...@@ -579,7 +568,16 @@ int ext4_ind_map_blocks(handle_t *handle, struct inode *inode,
return -ENOSPC; return -ENOSPC;
} }
goal = ext4_find_goal(inode, map->m_lblk, partial); /* Set up for the direct block allocation */
memset(&ar, 0, sizeof(ar));
ar.inode = inode;
ar.logical = map->m_lblk;
if (S_ISREG(inode->i_mode))
ar.flags = EXT4_MB_HINT_DATA;
if (flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE)
ar.flags |= EXT4_MB_DELALLOC_RESERVED;
ar.goal = ext4_find_goal(inode, map->m_lblk, partial);
/* the number of blocks need to allocate for [d,t]indirect blocks */ /* the number of blocks need to allocate for [d,t]indirect blocks */
indirect_blks = (chain + depth) - partial - 1; indirect_blks = (chain + depth) - partial - 1;
...@@ -588,13 +586,13 @@ int ext4_ind_map_blocks(handle_t *handle, struct inode *inode, ...@@ -588,13 +586,13 @@ int ext4_ind_map_blocks(handle_t *handle, struct inode *inode,
* Next look up the indirect map to count the totoal number of * Next look up the indirect map to count the totoal number of
* direct blocks to allocate for this branch. * direct blocks to allocate for this branch.
*/ */
count = ext4_blks_to_allocate(partial, indirect_blks, ar.len = ext4_blks_to_allocate(partial, indirect_blks,
map->m_len, blocks_to_boundary); map->m_len, blocks_to_boundary);
/* /*
* Block out ext4_truncate while we alter the tree * Block out ext4_truncate while we alter the tree
*/ */
err = ext4_alloc_branch(handle, inode, map->m_lblk, indirect_blks, err = ext4_alloc_branch(handle, &ar, indirect_blks,
&count, goal,
offsets + (partial - chain), partial); offsets + (partial - chain), partial);
/* /*
...@@ -605,14 +603,14 @@ int ext4_ind_map_blocks(handle_t *handle, struct inode *inode, ...@@ -605,14 +603,14 @@ int ext4_ind_map_blocks(handle_t *handle, struct inode *inode,
* may need to return -EAGAIN upwards in the worst case. --sct * may need to return -EAGAIN upwards in the worst case. --sct
*/ */
if (!err) if (!err)
err = ext4_splice_branch(handle, inode, map->m_lblk, err = ext4_splice_branch(handle, &ar, partial, indirect_blks);
partial, indirect_blks, count);
if (err) if (err)
goto cleanup; goto cleanup;
map->m_flags |= EXT4_MAP_NEW; map->m_flags |= EXT4_MAP_NEW;
ext4_update_inode_fsync_trans(handle, inode, 1); ext4_update_inode_fsync_trans(handle, inode, 1);
count = ar.len;
got_it: got_it:
map->m_flags |= EXT4_MAP_MAPPED; map->m_flags |= EXT4_MAP_MAPPED;
map->m_pblk = le32_to_cpu(chain[depth-1].key); map->m_pblk = le32_to_cpu(chain[depth-1].key);
......
...@@ -594,6 +594,7 @@ static int ext4_convert_inline_data_to_extent(struct address_space *mapping, ...@@ -594,6 +594,7 @@ static int ext4_convert_inline_data_to_extent(struct address_space *mapping,
if (ret) { if (ret) {
unlock_page(page); unlock_page(page);
page_cache_release(page); page_cache_release(page);
page = NULL;
ext4_orphan_add(handle, inode); ext4_orphan_add(handle, inode);
up_write(&EXT4_I(inode)->xattr_sem); up_write(&EXT4_I(inode)->xattr_sem);
sem_held = 0; sem_held = 0;
...@@ -613,7 +614,8 @@ static int ext4_convert_inline_data_to_extent(struct address_space *mapping, ...@@ -613,7 +614,8 @@ static int ext4_convert_inline_data_to_extent(struct address_space *mapping,
if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries)) if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries))
goto retry; goto retry;
block_commit_write(page, from, to); if (page)
block_commit_write(page, from, to);
out: out:
if (page) { if (page) {
unlock_page(page); unlock_page(page);
...@@ -1126,8 +1128,7 @@ static int ext4_finish_convert_inline_dir(handle_t *handle, ...@@ -1126,8 +1128,7 @@ static int ext4_finish_convert_inline_dir(handle_t *handle,
memcpy((void *)de, buf + EXT4_INLINE_DOTDOT_SIZE, memcpy((void *)de, buf + EXT4_INLINE_DOTDOT_SIZE,
inline_size - EXT4_INLINE_DOTDOT_SIZE); inline_size - EXT4_INLINE_DOTDOT_SIZE);
if (EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb, if (ext4_has_metadata_csum(inode->i_sb))
EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
csum_size = sizeof(struct ext4_dir_entry_tail); csum_size = sizeof(struct ext4_dir_entry_tail);
inode->i_size = inode->i_sb->s_blocksize; inode->i_size = inode->i_sb->s_blocksize;
......
...@@ -83,8 +83,7 @@ static int ext4_inode_csum_verify(struct inode *inode, struct ext4_inode *raw, ...@@ -83,8 +83,7 @@ static int ext4_inode_csum_verify(struct inode *inode, struct ext4_inode *raw,
if (EXT4_SB(inode->i_sb)->s_es->s_creator_os != if (EXT4_SB(inode->i_sb)->s_es->s_creator_os !=
cpu_to_le32(EXT4_OS_LINUX) || cpu_to_le32(EXT4_OS_LINUX) ||
!EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb, !ext4_has_metadata_csum(inode->i_sb))
EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
return 1; return 1;
provided = le16_to_cpu(raw->i_checksum_lo); provided = le16_to_cpu(raw->i_checksum_lo);
...@@ -105,8 +104,7 @@ static void ext4_inode_csum_set(struct inode *inode, struct ext4_inode *raw, ...@@ -105,8 +104,7 @@ static void ext4_inode_csum_set(struct inode *inode, struct ext4_inode *raw,
if (EXT4_SB(inode->i_sb)->s_es->s_creator_os != if (EXT4_SB(inode->i_sb)->s_es->s_creator_os !=
cpu_to_le32(EXT4_OS_LINUX) || cpu_to_le32(EXT4_OS_LINUX) ||
!EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb, !ext4_has_metadata_csum(inode->i_sb))
EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
return; return;
csum = ext4_inode_csum(inode, raw, ei); csum = ext4_inode_csum(inode, raw, ei);
...@@ -224,16 +222,15 @@ void ext4_evict_inode(struct inode *inode) ...@@ -224,16 +222,15 @@ void ext4_evict_inode(struct inode *inode)
goto no_delete; goto no_delete;
} }
if (!is_bad_inode(inode)) if (is_bad_inode(inode))
dquot_initialize(inode); goto no_delete;
dquot_initialize(inode);
if (ext4_should_order_data(inode)) if (ext4_should_order_data(inode))
ext4_begin_ordered_truncate(inode, 0); ext4_begin_ordered_truncate(inode, 0);
truncate_inode_pages_final(&inode->i_data); truncate_inode_pages_final(&inode->i_data);
WARN_ON(atomic_read(&EXT4_I(inode)->i_ioend_count)); WARN_ON(atomic_read(&EXT4_I(inode)->i_ioend_count));
if (is_bad_inode(inode))
goto no_delete;
/* /*
* Protect us against freezing - iput() caller didn't have to have any * Protect us against freezing - iput() caller didn't have to have any
...@@ -590,19 +587,11 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode, ...@@ -590,19 +587,11 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode,
/* /*
* New blocks allocate and/or writing to unwritten 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_block()
* 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
* we have already reserved fs blocks for allocation
* let the underlying get_block() function know to
* avoid double accounting
*/
if (flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE)
ext4_set_inode_state(inode, EXT4_STATE_DELALLOC_RESERVED);
/* /*
* We need to check for EXT4 here because migrate * We need to check for EXT4 here because migrate
* could have changed the inode type in between * could have changed the inode type in between
...@@ -631,8 +620,6 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode, ...@@ -631,8 +620,6 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode,
(flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE)) (flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE))
ext4_da_update_reserve_space(inode, retval, 1); ext4_da_update_reserve_space(inode, retval, 1);
} }
if (flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE)
ext4_clear_inode_state(inode, EXT4_STATE_DELALLOC_RESERVED);
if (retval > 0) { if (retval > 0) {
unsigned int status; unsigned int status;
...@@ -734,11 +721,11 @@ int ext4_get_block(struct inode *inode, sector_t iblock, ...@@ -734,11 +721,11 @@ int ext4_get_block(struct inode *inode, sector_t iblock,
* `handle' can be NULL if create is zero * `handle' can be NULL if create is zero
*/ */
struct buffer_head *ext4_getblk(handle_t *handle, struct inode *inode, struct buffer_head *ext4_getblk(handle_t *handle, struct inode *inode,
ext4_lblk_t block, int create, int *errp) ext4_lblk_t block, int create)
{ {
struct ext4_map_blocks map; struct ext4_map_blocks map;
struct buffer_head *bh; struct buffer_head *bh;
int fatal = 0, err; int err;
J_ASSERT(handle != NULL || create == 0); J_ASSERT(handle != NULL || create == 0);
...@@ -747,21 +734,14 @@ struct buffer_head *ext4_getblk(handle_t *handle, struct inode *inode, ...@@ -747,21 +734,14 @@ struct buffer_head *ext4_getblk(handle_t *handle, struct inode *inode,
err = ext4_map_blocks(handle, inode, &map, err = ext4_map_blocks(handle, inode, &map,
create ? EXT4_GET_BLOCKS_CREATE : 0); create ? EXT4_GET_BLOCKS_CREATE : 0);
/* ensure we send some value back into *errp */ if (err == 0)
*errp = 0; return create ? ERR_PTR(-ENOSPC) : NULL;
if (create && err == 0)
err = -ENOSPC; /* should never happen */
if (err < 0) if (err < 0)
*errp = err; return ERR_PTR(err);
if (err <= 0)
return NULL;
bh = sb_getblk(inode->i_sb, map.m_pblk); bh = sb_getblk(inode->i_sb, map.m_pblk);
if (unlikely(!bh)) { if (unlikely(!bh))
*errp = -ENOMEM; return ERR_PTR(-ENOMEM);
return NULL;
}
if (map.m_flags & EXT4_MAP_NEW) { if (map.m_flags & EXT4_MAP_NEW) {
J_ASSERT(create != 0); J_ASSERT(create != 0);
J_ASSERT(handle != NULL); J_ASSERT(handle != NULL);
...@@ -775,44 +755,44 @@ struct buffer_head *ext4_getblk(handle_t *handle, struct inode *inode, ...@@ -775,44 +755,44 @@ struct buffer_head *ext4_getblk(handle_t *handle, struct inode *inode,
*/ */
lock_buffer(bh); lock_buffer(bh);
BUFFER_TRACE(bh, "call get_create_access"); BUFFER_TRACE(bh, "call get_create_access");
fatal = ext4_journal_get_create_access(handle, bh); err = ext4_journal_get_create_access(handle, bh);
if (!fatal && !buffer_uptodate(bh)) { if (unlikely(err)) {
unlock_buffer(bh);
goto errout;
}
if (!buffer_uptodate(bh)) {
memset(bh->b_data, 0, inode->i_sb->s_blocksize); memset(bh->b_data, 0, inode->i_sb->s_blocksize);
set_buffer_uptodate(bh); set_buffer_uptodate(bh);
} }
unlock_buffer(bh); unlock_buffer(bh);
BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata"); BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata");
err = ext4_handle_dirty_metadata(handle, inode, bh); err = ext4_handle_dirty_metadata(handle, inode, bh);
if (!fatal) if (unlikely(err))
fatal = err; goto errout;
} else { } else
BUFFER_TRACE(bh, "not a new buffer"); BUFFER_TRACE(bh, "not a new buffer");
}
if (fatal) {
*errp = fatal;
brelse(bh);
bh = NULL;
}
return bh; return bh;
errout:
brelse(bh);
return ERR_PTR(err);
} }
struct buffer_head *ext4_bread(handle_t *handle, struct inode *inode, struct buffer_head *ext4_bread(handle_t *handle, struct inode *inode,
ext4_lblk_t block, int create, int *err) ext4_lblk_t block, int create)
{ {
struct buffer_head *bh; struct buffer_head *bh;
bh = ext4_getblk(handle, inode, block, create, err); bh = ext4_getblk(handle, inode, block, create);
if (!bh) if (IS_ERR(bh))
return bh; return bh;
if (buffer_uptodate(bh)) if (!bh || buffer_uptodate(bh))
return bh; return bh;
ll_rw_block(READ | REQ_META | REQ_PRIO, 1, &bh); ll_rw_block(READ | REQ_META | REQ_PRIO, 1, &bh);
wait_on_buffer(bh); wait_on_buffer(bh);
if (buffer_uptodate(bh)) if (buffer_uptodate(bh))
return bh; return bh;
put_bh(bh); put_bh(bh);
*err = -EIO; return ERR_PTR(-EIO);
return NULL;
} }
int ext4_walk_page_buffers(handle_t *handle, int ext4_walk_page_buffers(handle_t *handle,
...@@ -1536,7 +1516,7 @@ static int ext4_da_map_blocks(struct inode *inode, sector_t iblock, ...@@ -1536,7 +1516,7 @@ static int ext4_da_map_blocks(struct inode *inode, sector_t iblock,
} }
/* /*
* This is a special get_blocks_t callback which is used by * This is a special get_block_t callback which is used by
* ext4_da_write_begin(). It will either return mapped block or * ext4_da_write_begin(). It will either return mapped block or
* reserve space for a single block. * reserve space for a single block.
* *
...@@ -2011,12 +1991,10 @@ static int mpage_map_one_extent(handle_t *handle, struct mpage_da_data *mpd) ...@@ -2011,12 +1991,10 @@ static int mpage_map_one_extent(handle_t *handle, struct mpage_da_data *mpd)
* in data loss. So use reserved blocks to allocate metadata if * in data loss. So use reserved blocks to allocate metadata if
* possible. * possible.
* *
* We pass in the magic EXT4_GET_BLOCKS_DELALLOC_RESERVE if the blocks * We pass in the magic EXT4_GET_BLOCKS_DELALLOC_RESERVE if
* in question are delalloc blocks. This affects functions in many * the blocks in question are delalloc blocks. This indicates
* different parts of the allocation call path. This flag exists * that the blocks and quotas has already been checked when
* primarily because we don't want to change *many* call functions, so * the data was copied into the page cache.
* ext4_map_blocks() will set the EXT4_STATE_DELALLOC_RESERVED flag
* once the inode's allocation semaphore is taken.
*/ */
get_blocks_flags = EXT4_GET_BLOCKS_CREATE | get_blocks_flags = EXT4_GET_BLOCKS_CREATE |
EXT4_GET_BLOCKS_METADATA_NOFAIL; EXT4_GET_BLOCKS_METADATA_NOFAIL;
...@@ -2515,6 +2493,20 @@ static int ext4_nonda_switch(struct super_block *sb) ...@@ -2515,6 +2493,20 @@ static int ext4_nonda_switch(struct super_block *sb)
return 0; return 0;
} }
/* We always reserve for an inode update; the superblock could be there too */
static int ext4_da_write_credits(struct inode *inode, loff_t pos, unsigned len)
{
if (likely(EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb,
EXT4_FEATURE_RO_COMPAT_LARGE_FILE)))
return 1;
if (pos + len <= 0x7fffffffULL)
return 1;
/* We might need to update the superblock to set LARGE_FILE */
return 2;
}
static int ext4_da_write_begin(struct file *file, struct address_space *mapping, static int ext4_da_write_begin(struct file *file, struct address_space *mapping,
loff_t pos, unsigned len, unsigned flags, loff_t pos, unsigned len, unsigned flags,
struct page **pagep, void **fsdata) struct page **pagep, void **fsdata)
...@@ -2565,7 +2557,8 @@ static int ext4_da_write_begin(struct file *file, struct address_space *mapping, ...@@ -2565,7 +2557,8 @@ static int ext4_da_write_begin(struct file *file, struct address_space *mapping,
* of file which has an already mapped buffer. * of file which has an already mapped buffer.
*/ */
retry_journal: retry_journal:
handle = ext4_journal_start(inode, EXT4_HT_WRITE_PAGE, 1); handle = ext4_journal_start(inode, EXT4_HT_WRITE_PAGE,
ext4_da_write_credits(inode, pos, len));
if (IS_ERR(handle)) { if (IS_ERR(handle)) {
page_cache_release(page); page_cache_release(page);
return PTR_ERR(handle); return PTR_ERR(handle);
...@@ -2658,10 +2651,7 @@ static int ext4_da_write_end(struct file *file, ...@@ -2658,10 +2651,7 @@ static int ext4_da_write_end(struct file *file,
if (copied && new_i_size > EXT4_I(inode)->i_disksize) { if (copied && new_i_size > EXT4_I(inode)->i_disksize) {
if (ext4_has_inline_data(inode) || if (ext4_has_inline_data(inode) ||
ext4_da_should_update_i_disksize(page, end)) { ext4_da_should_update_i_disksize(page, end)) {
down_write(&EXT4_I(inode)->i_data_sem); ext4_update_i_disksize(inode, new_i_size);
if (new_i_size > EXT4_I(inode)->i_disksize)
EXT4_I(inode)->i_disksize = new_i_size;
up_write(&EXT4_I(inode)->i_data_sem);
/* We need to mark inode dirty even if /* We need to mark inode dirty even if
* new_i_size is less that inode->i_size * new_i_size is less that inode->i_size
* bu greater than i_disksize.(hint delalloc) * bu greater than i_disksize.(hint delalloc)
...@@ -3936,8 +3926,7 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino) ...@@ -3936,8 +3926,7 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
ei->i_extra_isize = 0; ei->i_extra_isize = 0;
/* Precompute checksum seed for inode metadata */ /* Precompute checksum seed for inode metadata */
if (EXT4_HAS_RO_COMPAT_FEATURE(sb, if (ext4_has_metadata_csum(sb)) {
EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) {
struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
__u32 csum; __u32 csum;
__le32 inum = cpu_to_le32(inode->i_ino); __le32 inum = cpu_to_le32(inode->i_ino);
...@@ -4127,6 +4116,13 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino) ...@@ -4127,6 +4116,13 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
return ERR_PTR(ret); return ERR_PTR(ret);
} }
struct inode *ext4_iget_normal(struct super_block *sb, unsigned long ino)
{
if (ino < EXT4_FIRST_INO(sb) && ino != EXT4_ROOT_INO)
return ERR_PTR(-EIO);
return ext4_iget(sb, ino);
}
static int ext4_inode_blocks_set(handle_t *handle, static int ext4_inode_blocks_set(handle_t *handle,
struct ext4_inode *raw_inode, struct ext4_inode *raw_inode,
struct ext4_inode_info *ei) struct ext4_inode_info *ei)
...@@ -4226,7 +4222,8 @@ static int ext4_do_update_inode(handle_t *handle, ...@@ -4226,7 +4222,8 @@ 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)) { err = ext4_inode_blocks_set(handle, raw_inode, ei);
if (err) {
spin_unlock(&ei->i_raw_lock); spin_unlock(&ei->i_raw_lock);
goto out_brelse; goto out_brelse;
} }
...@@ -4536,8 +4533,12 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr) ...@@ -4536,8 +4533,12 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr)
ext4_orphan_del(NULL, inode); ext4_orphan_del(NULL, inode);
goto err_out; goto err_out;
} }
} else } else {
loff_t oldsize = inode->i_size;
i_size_write(inode, attr->ia_size); i_size_write(inode, attr->ia_size);
pagecache_isize_extended(inode, oldsize, inode->i_size);
}
/* /*
* Blocks are going to be removed from the inode. Wait * Blocks are going to be removed from the inode. Wait
......
...@@ -331,8 +331,7 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ...@@ -331,8 +331,7 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
if (!inode_owner_or_capable(inode)) if (!inode_owner_or_capable(inode))
return -EPERM; return -EPERM;
if (EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb, if (ext4_has_metadata_csum(inode->i_sb)) {
EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) {
ext4_warning(sb, "Setting inode version is not " ext4_warning(sb, "Setting inode version is not "
"supported with metadata_csum enabled."); "supported with metadata_csum enabled.");
return -ENOTTY; return -ENOTTY;
...@@ -532,9 +531,17 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ...@@ -532,9 +531,17 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
} }
case EXT4_IOC_SWAP_BOOT: case EXT4_IOC_SWAP_BOOT:
{
int err;
if (!(filp->f_mode & FMODE_WRITE)) if (!(filp->f_mode & FMODE_WRITE))
return -EBADF; return -EBADF;
return swap_inode_boot_loader(sb, inode); err = mnt_want_write_file(filp);
if (err)
return err;
err = swap_inode_boot_loader(sb, inode);
mnt_drop_write_file(filp);
return err;
}
case EXT4_IOC_RESIZE_FS: { case EXT4_IOC_RESIZE_FS: {
ext4_fsblk_t n_blocks_count; ext4_fsblk_t n_blocks_count;
......
...@@ -3155,9 +3155,8 @@ ext4_mb_normalize_request(struct ext4_allocation_context *ac, ...@@ -3155,9 +3155,8 @@ ext4_mb_normalize_request(struct ext4_allocation_context *ac,
"start %lu, size %lu, fe_logical %lu", "start %lu, size %lu, fe_logical %lu",
(unsigned long) start, (unsigned long) size, (unsigned long) start, (unsigned long) size,
(unsigned long) ac->ac_o_ex.fe_logical); (unsigned long) ac->ac_o_ex.fe_logical);
BUG();
} }
BUG_ON(start + size <= ac->ac_o_ex.fe_logical &&
start > ac->ac_o_ex.fe_logical);
BUG_ON(size <= 0 || size > EXT4_BLOCKS_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 */
...@@ -4410,14 +4409,7 @@ ext4_fsblk_t ext4_mb_new_blocks(handle_t *handle, ...@@ -4410,14 +4409,7 @@ ext4_fsblk_t ext4_mb_new_blocks(handle_t *handle,
if (IS_NOQUOTA(ar->inode)) if (IS_NOQUOTA(ar->inode))
ar->flags |= EXT4_MB_USE_ROOT_BLOCKS; ar->flags |= EXT4_MB_USE_ROOT_BLOCKS;
/* if ((ar->flags & EXT4_MB_DELALLOC_RESERVED) == 0) {
* For delayed allocation, we could skip the ENOSPC and
* EDQUOT check, as blocks and quotas have been already
* reserved when data being copied into pagecache.
*/
if (ext4_test_inode_state(ar->inode, EXT4_STATE_DELALLOC_RESERVED))
ar->flags |= EXT4_MB_DELALLOC_RESERVED;
else {
/* Without delayed allocation we need to verify /* Without delayed allocation we need to verify
* there is enough free blocks to do block allocation * there is enough free blocks to do block allocation
* and verify allocation doesn't exceed the quota limits. * and verify allocation doesn't exceed the quota limits.
...@@ -4528,8 +4520,7 @@ ext4_fsblk_t ext4_mb_new_blocks(handle_t *handle, ...@@ -4528,8 +4520,7 @@ ext4_fsblk_t ext4_mb_new_blocks(handle_t *handle,
if (inquota && ar->len < inquota) if (inquota && ar->len < inquota)
dquot_free_block(ar->inode, EXT4_C2B(sbi, inquota - ar->len)); dquot_free_block(ar->inode, EXT4_C2B(sbi, inquota - ar->len));
if (!ar->len) { if (!ar->len) {
if (!ext4_test_inode_state(ar->inode, if ((ar->flags & EXT4_MB_DELALLOC_RESERVED) == 0)
EXT4_STATE_DELALLOC_RESERVED))
/* release all the reserved blocks if non delalloc */ /* release all the reserved blocks if non delalloc */
percpu_counter_sub(&sbi->s_dirtyclusters_counter, percpu_counter_sub(&sbi->s_dirtyclusters_counter,
reserv_clstrs); reserv_clstrs);
......
...@@ -41,8 +41,7 @@ static int finish_range(handle_t *handle, struct inode *inode, ...@@ -41,8 +41,7 @@ static int finish_range(handle_t *handle, struct inode *inode,
ext4_ext_store_pblock(&newext, lb->first_pblock); ext4_ext_store_pblock(&newext, lb->first_pblock);
/* Locking only for convinience since we are operating on temp inode */ /* Locking only for convinience since we are operating on temp inode */
down_write(&EXT4_I(inode)->i_data_sem); down_write(&EXT4_I(inode)->i_data_sem);
path = ext4_ext_find_extent(inode, lb->first_block, NULL, 0); path = ext4_find_extent(inode, lb->first_block, NULL, 0);
if (IS_ERR(path)) { if (IS_ERR(path)) {
retval = PTR_ERR(path); retval = PTR_ERR(path);
path = NULL; path = NULL;
...@@ -81,13 +80,11 @@ static int finish_range(handle_t *handle, struct inode *inode, ...@@ -81,13 +80,11 @@ static int finish_range(handle_t *handle, struct inode *inode,
goto err_out; goto err_out;
} }
} }
retval = ext4_ext_insert_extent(handle, inode, path, &newext, 0); retval = ext4_ext_insert_extent(handle, inode, &path, &newext, 0);
err_out: err_out:
up_write((&EXT4_I(inode)->i_data_sem)); up_write((&EXT4_I(inode)->i_data_sem));
if (path) { ext4_ext_drop_refs(path);
ext4_ext_drop_refs(path); kfree(path);
kfree(path);
}
lb->first_pblock = 0; lb->first_pblock = 0;
return retval; return retval;
} }
......
...@@ -20,8 +20,7 @@ static __le32 ext4_mmp_csum(struct super_block *sb, struct mmp_struct *mmp) ...@@ -20,8 +20,7 @@ static __le32 ext4_mmp_csum(struct super_block *sb, struct mmp_struct *mmp)
static 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_metadata_csum(sb))
EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
return 1; return 1;
return mmp->mmp_checksum == ext4_mmp_csum(sb, mmp); return mmp->mmp_checksum == ext4_mmp_csum(sb, mmp);
...@@ -29,8 +28,7 @@ static int ext4_mmp_csum_verify(struct super_block *sb, struct mmp_struct *mmp) ...@@ -29,8 +28,7 @@ static int ext4_mmp_csum_verify(struct super_block *sb, struct mmp_struct *mmp)
static 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_metadata_csum(sb))
EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
return; return;
mmp->mmp_checksum = ext4_mmp_csum(sb, mmp); mmp->mmp_checksum = ext4_mmp_csum(sb, mmp);
......
This diff is collapsed.
This diff is collapsed.
...@@ -1212,8 +1212,7 @@ static int ext4_set_bitmap_checksums(struct super_block *sb, ...@@ -1212,8 +1212,7 @@ static int ext4_set_bitmap_checksums(struct super_block *sb,
{ {
struct buffer_head *bh; struct buffer_head *bh;
if (!EXT4_HAS_RO_COMPAT_FEATURE(sb, if (!ext4_has_metadata_csum(sb))
EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
return 0; return 0;
bh = ext4_get_bitmap(sb, group_data->inode_bitmap); bh = ext4_get_bitmap(sb, group_data->inode_bitmap);
......
This diff is collapsed.
...@@ -142,8 +142,7 @@ static int ext4_xattr_block_csum_verify(struct inode *inode, ...@@ -142,8 +142,7 @@ static int ext4_xattr_block_csum_verify(struct inode *inode,
sector_t block_nr, sector_t block_nr,
struct ext4_xattr_header *hdr) struct ext4_xattr_header *hdr)
{ {
if (EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb, if (ext4_has_metadata_csum(inode->i_sb) &&
EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) &&
(hdr->h_checksum != ext4_xattr_block_csum(inode, block_nr, hdr))) (hdr->h_checksum != ext4_xattr_block_csum(inode, block_nr, hdr)))
return 0; return 0;
return 1; return 1;
...@@ -153,8 +152,7 @@ static void ext4_xattr_block_csum_set(struct inode *inode, ...@@ -153,8 +152,7 @@ static void ext4_xattr_block_csum_set(struct inode *inode,
sector_t block_nr, sector_t block_nr,
struct ext4_xattr_header *hdr) struct ext4_xattr_header *hdr)
{ {
if (!EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb, if (!ext4_has_metadata_csum(inode->i_sb))
EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
return; return;
hdr->h_checksum = ext4_xattr_block_csum(inode, block_nr, hdr); hdr->h_checksum = ext4_xattr_block_csum(inode, block_nr, hdr);
...@@ -190,14 +188,28 @@ ext4_listxattr(struct dentry *dentry, char *buffer, size_t size) ...@@ -190,14 +188,28 @@ ext4_listxattr(struct dentry *dentry, char *buffer, size_t size)
} }
static int static int
ext4_xattr_check_names(struct ext4_xattr_entry *entry, void *end) ext4_xattr_check_names(struct ext4_xattr_entry *entry, void *end,
void *value_start)
{ {
while (!IS_LAST_ENTRY(entry)) { struct ext4_xattr_entry *e = entry;
struct ext4_xattr_entry *next = EXT4_XATTR_NEXT(entry);
while (!IS_LAST_ENTRY(e)) {
struct ext4_xattr_entry *next = EXT4_XATTR_NEXT(e);
if ((void *)next >= end) if ((void *)next >= end)
return -EIO; return -EIO;
entry = next; e = next;
} }
while (!IS_LAST_ENTRY(entry)) {
if (entry->e_value_size != 0 &&
(value_start + le16_to_cpu(entry->e_value_offs) <
(void *)e + sizeof(__u32) ||
value_start + le16_to_cpu(entry->e_value_offs) +
le32_to_cpu(entry->e_value_size) > end))
return -EIO;
entry = EXT4_XATTR_NEXT(entry);
}
return 0; return 0;
} }
...@@ -214,7 +226,8 @@ ext4_xattr_check_block(struct inode *inode, struct buffer_head *bh) ...@@ -214,7 +226,8 @@ ext4_xattr_check_block(struct inode *inode, struct buffer_head *bh)
return -EIO; return -EIO;
if (!ext4_xattr_block_csum_verify(inode, bh->b_blocknr, BHDR(bh))) if (!ext4_xattr_block_csum_verify(inode, bh->b_blocknr, BHDR(bh)))
return -EIO; return -EIO;
error = ext4_xattr_check_names(BFIRST(bh), bh->b_data + bh->b_size); error = ext4_xattr_check_names(BFIRST(bh), bh->b_data + bh->b_size,
bh->b_data);
if (!error) if (!error)
set_buffer_verified(bh); set_buffer_verified(bh);
return error; return error;
...@@ -331,7 +344,7 @@ ext4_xattr_ibody_get(struct inode *inode, int name_index, const char *name, ...@@ -331,7 +344,7 @@ ext4_xattr_ibody_get(struct inode *inode, int name_index, const char *name,
header = IHDR(inode, raw_inode); header = IHDR(inode, raw_inode);
entry = IFIRST(header); entry = IFIRST(header);
end = (void *)raw_inode + EXT4_SB(inode->i_sb)->s_inode_size; end = (void *)raw_inode + EXT4_SB(inode->i_sb)->s_inode_size;
error = ext4_xattr_check_names(entry, end); error = ext4_xattr_check_names(entry, end, entry);
if (error) if (error)
goto cleanup; goto cleanup;
error = ext4_xattr_find_entry(&entry, name_index, name, error = ext4_xattr_find_entry(&entry, name_index, name,
...@@ -463,7 +476,7 @@ ext4_xattr_ibody_list(struct dentry *dentry, char *buffer, size_t buffer_size) ...@@ -463,7 +476,7 @@ ext4_xattr_ibody_list(struct dentry *dentry, char *buffer, size_t buffer_size)
raw_inode = ext4_raw_inode(&iloc); raw_inode = ext4_raw_inode(&iloc);
header = IHDR(inode, raw_inode); header = IHDR(inode, raw_inode);
end = (void *)raw_inode + EXT4_SB(inode->i_sb)->s_inode_size; end = (void *)raw_inode + EXT4_SB(inode->i_sb)->s_inode_size;
error = ext4_xattr_check_names(IFIRST(header), end); error = ext4_xattr_check_names(IFIRST(header), end, IFIRST(header));
if (error) if (error)
goto cleanup; goto cleanup;
error = ext4_xattr_list_entries(dentry, IFIRST(header), error = ext4_xattr_list_entries(dentry, IFIRST(header),
...@@ -899,14 +912,8 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode, ...@@ -899,14 +912,8 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode,
if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))) if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)))
goal = goal & EXT4_MAX_BLOCK_FILE_PHYS; goal = goal & EXT4_MAX_BLOCK_FILE_PHYS;
/*
* take i_data_sem because we will test
* i_delalloc_reserved_flag in ext4_mb_new_blocks
*/
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));
if (error) if (error)
goto cleanup; goto cleanup;
...@@ -986,7 +993,8 @@ int ext4_xattr_ibody_find(struct inode *inode, struct ext4_xattr_info *i, ...@@ -986,7 +993,8 @@ int ext4_xattr_ibody_find(struct inode *inode, struct ext4_xattr_info *i,
is->s.here = is->s.first; is->s.here = is->s.first;
is->s.end = (void *)raw_inode + EXT4_SB(inode->i_sb)->s_inode_size; is->s.end = (void *)raw_inode + EXT4_SB(inode->i_sb)->s_inode_size;
if (ext4_test_inode_state(inode, EXT4_STATE_XATTR)) { if (ext4_test_inode_state(inode, EXT4_STATE_XATTR)) {
error = ext4_xattr_check_names(IFIRST(header), is->s.end); error = ext4_xattr_check_names(IFIRST(header), is->s.end,
IFIRST(header));
if (error) if (error)
return error; return error;
/* Find the named attribute. */ /* Find the named attribute. */
......
...@@ -886,7 +886,7 @@ journal_t * journal_init_inode (struct inode *inode) ...@@ -886,7 +886,7 @@ journal_t * journal_init_inode (struct inode *inode)
goto out_err; goto out_err;
} }
bh = __getblk(journal->j_dev, blocknr, journal->j_blocksize); bh = getblk_unmovable(journal->j_dev, blocknr, journal->j_blocksize);
if (!bh) { if (!bh) {
printk(KERN_ERR printk(KERN_ERR
"%s: Cannot get buffer for journal superblock\n", "%s: Cannot get buffer for journal superblock\n",
......
This diff is collapsed.
...@@ -1237,7 +1237,7 @@ journal_t * jbd2_journal_init_inode (struct inode *inode) ...@@ -1237,7 +1237,7 @@ journal_t * jbd2_journal_init_inode (struct inode *inode)
goto out_err; goto out_err;
} }
bh = __getblk(journal->j_dev, blocknr, journal->j_blocksize); bh = getblk_unmovable(journal->j_dev, blocknr, journal->j_blocksize);
if (!bh) { if (!bh) {
printk(KERN_ERR printk(KERN_ERR
"%s: Cannot get buffer for journal superblock\n", "%s: Cannot get buffer for journal superblock\n",
...@@ -1522,14 +1522,6 @@ static int journal_get_superblock(journal_t *journal) ...@@ -1522,14 +1522,6 @@ static int journal_get_superblock(journal_t *journal)
goto out; goto out;
} }
if (jbd2_journal_has_csum_v2or3(journal) &&
JBD2_HAS_COMPAT_FEATURE(journal, JBD2_FEATURE_COMPAT_CHECKSUM)) {
/* Can't have checksum v1 and v2 on at the same time! */
printk(KERN_ERR "JBD2: Can't enable checksumming v1 and v2 "
"at the same time!\n");
goto out;
}
if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_CSUM_V2) && if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_CSUM_V2) &&
JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_CSUM_V3)) { JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_CSUM_V3)) {
/* Can't have checksum v2 and v3 at the same time! */ /* Can't have checksum v2 and v3 at the same time! */
...@@ -1538,6 +1530,14 @@ static int journal_get_superblock(journal_t *journal) ...@@ -1538,6 +1530,14 @@ static int journal_get_superblock(journal_t *journal)
goto out; goto out;
} }
if (jbd2_journal_has_csum_v2or3(journal) &&
JBD2_HAS_COMPAT_FEATURE(journal, JBD2_FEATURE_COMPAT_CHECKSUM)) {
/* Can't have checksum v1 and v2 on at the same time! */
printk(KERN_ERR "JBD2: Can't enable checksumming v1 and v2/3 "
"at the same time!\n");
goto out;
}
if (!jbd2_verify_csum_type(journal, sb)) { if (!jbd2_verify_csum_type(journal, sb)) {
printk(KERN_ERR "JBD2: Unknown checksum type\n"); printk(KERN_ERR "JBD2: Unknown checksum type\n");
goto out; goto out;
......
...@@ -525,6 +525,7 @@ static int do_one_pass(journal_t *journal, ...@@ -525,6 +525,7 @@ static int do_one_pass(journal_t *journal,
!jbd2_descr_block_csum_verify(journal, !jbd2_descr_block_csum_verify(journal,
bh->b_data)) { bh->b_data)) {
err = -EIO; err = -EIO;
brelse(bh);
goto failed; goto failed;
} }
......
This diff is collapsed.
...@@ -1042,7 +1042,7 @@ void jbd2_update_log_tail(journal_t *journal, tid_t tid, unsigned long block); ...@@ -1042,7 +1042,7 @@ void jbd2_update_log_tail(journal_t *journal, tid_t tid, unsigned long block);
extern void jbd2_journal_commit_transaction(journal_t *); extern void jbd2_journal_commit_transaction(journal_t *);
/* Checkpoint list management */ /* Checkpoint list management */
int __jbd2_journal_clean_checkpoint_list(journal_t *journal); void __jbd2_journal_clean_checkpoint_list(journal_t *journal);
int __jbd2_journal_remove_checkpoint(struct journal_head *); int __jbd2_journal_remove_checkpoint(struct journal_head *);
void __jbd2_journal_insert_checkpoint(struct journal_head *, transaction_t *); void __jbd2_journal_insert_checkpoint(struct journal_head *, transaction_t *);
......
...@@ -1176,6 +1176,7 @@ static inline void unmap_shared_mapping_range(struct address_space *mapping, ...@@ -1176,6 +1176,7 @@ static inline void unmap_shared_mapping_range(struct address_space *mapping,
extern void truncate_pagecache(struct inode *inode, loff_t new); extern void truncate_pagecache(struct inode *inode, loff_t new);
extern void truncate_setsize(struct inode *inode, loff_t newsize); extern void truncate_setsize(struct inode *inode, loff_t newsize);
void pagecache_isize_extended(struct inode *inode, loff_t from, loff_t to);
void truncate_pagecache_range(struct inode *inode, loff_t offset, loff_t end); void truncate_pagecache_range(struct inode *inode, loff_t offset, loff_t end);
int truncate_inode_page(struct address_space *mapping, struct page *page); int truncate_inode_page(struct address_space *mapping, struct page *page);
int generic_error_remove_page(struct address_space *mapping, struct page *page); int generic_error_remove_page(struct address_space *mapping, struct page *page);
......
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