You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
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 ...
This commit is contained in:
+29
-19
@@ -993,7 +993,7 @@ init_page_buffers(struct page *page, struct block_device *bdev,
|
||||
*/
|
||||
static int
|
||||
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 page *page;
|
||||
@@ -1002,8 +1002,8 @@ grow_dev_page(struct block_device *bdev, sector_t block,
|
||||
int ret = 0; /* Will call free_more_memory() */
|
||||
gfp_t gfp_mask;
|
||||
|
||||
gfp_mask = mapping_gfp_mask(inode->i_mapping) & ~__GFP_FS;
|
||||
gfp_mask |= __GFP_MOVABLE;
|
||||
gfp_mask = (mapping_gfp_mask(inode->i_mapping) & ~__GFP_FS) | gfp;
|
||||
|
||||
/*
|
||||
* XXX: __getblk_slow() can not really deal with failure and
|
||||
* will endlessly loop on improvised global reclaim. Prefer
|
||||
@@ -1060,7 +1060,7 @@ failed:
|
||||
* that page was dirty, the buffers are set dirty also.
|
||||
*/
|
||||
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;
|
||||
int sizebits;
|
||||
@@ -1087,11 +1087,12 @@ grow_buffers(struct block_device *bdev, sector_t block, int size)
|
||||
}
|
||||
|
||||
/* 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 *
|
||||
__getblk_slow(struct block_device *bdev, sector_t block, int size)
|
||||
struct buffer_head *
|
||||
__getblk_slow(struct block_device *bdev, sector_t block,
|
||||
unsigned size, gfp_t gfp)
|
||||
{
|
||||
/* Size must be multiple of hard sectorsize */
|
||||
if (unlikely(size & (bdev_logical_block_size(bdev)-1) ||
|
||||
@@ -1113,13 +1114,14 @@ __getblk_slow(struct block_device *bdev, sector_t block, int size)
|
||||
if (bh)
|
||||
return bh;
|
||||
|
||||
ret = grow_buffers(bdev, block, size);
|
||||
ret = grow_buffers(bdev, block, size, gfp);
|
||||
if (ret < 0)
|
||||
return NULL;
|
||||
if (ret == 0)
|
||||
free_more_memory();
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(__getblk_slow);
|
||||
|
||||
/*
|
||||
* The relationship between dirty buffers and dirty pages:
|
||||
@@ -1373,24 +1375,25 @@ __find_get_block(struct block_device *bdev, sector_t block, unsigned size)
|
||||
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
|
||||
* returned buffer has its reference count incremented.
|
||||
*
|
||||
* __getblk() will lock up the machine if grow_dev_page's try_to_free_buffers()
|
||||
* attempt is failing. FIXME, perhaps?
|
||||
* __getblk_gfp() will lock up the machine if grow_dev_page's
|
||||
* try_to_free_buffers() attempt is failing. FIXME, perhaps?
|
||||
*/
|
||||
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);
|
||||
|
||||
might_sleep();
|
||||
if (bh == NULL)
|
||||
bh = __getblk_slow(bdev, block, size);
|
||||
bh = __getblk_slow(bdev, block, size, gfp);
|
||||
return bh;
|
||||
}
|
||||
EXPORT_SYMBOL(__getblk);
|
||||
EXPORT_SYMBOL(__getblk_gfp);
|
||||
|
||||
/*
|
||||
* Do async read-ahead on a buffer..
|
||||
@@ -1406,24 +1409,28 @@ void __breadahead(struct block_device *bdev, sector_t block, unsigned size)
|
||||
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
|
||||
* @block: number of block
|
||||
* @size: size (in bytes) to read
|
||||
*
|
||||
* @gfp: page allocation flag
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
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))
|
||||
bh = __bread_slow(bh);
|
||||
return bh;
|
||||
}
|
||||
EXPORT_SYMBOL(__bread);
|
||||
EXPORT_SYMBOL(__bread_gfp);
|
||||
|
||||
/*
|
||||
* 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,
|
||||
struct page *page, void *fsdata)
|
||||
{
|
||||
struct inode *inode = mapping->host;
|
||||
loff_t old_size = inode->i_size;
|
||||
int i_size_changed = 0;
|
||||
|
||||
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,
|
||||
unlock_page(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
|
||||
* makes the holding time of page lock longer. Second, it forces lock
|
||||
|
||||
+9
-6
@@ -176,7 +176,7 @@ static unsigned int num_clusters_in_group(struct super_block *sb,
|
||||
}
|
||||
|
||||
/* 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,
|
||||
ext4_group_t block_group,
|
||||
struct ext4_group_desc *gdp)
|
||||
@@ -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
|
||||
* essentially implementing a per-group read-only flag. */
|
||||
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);
|
||||
if (!EXT4_MB_GRP_BBITMAP_CORRUPT(grp))
|
||||
percpu_counter_sub(&sbi->s_freeclusters_counter,
|
||||
@@ -205,7 +204,7 @@ static void ext4_init_block_bitmap(struct super_block *sb,
|
||||
count);
|
||||
}
|
||||
set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &grp->bb_state);
|
||||
return;
|
||||
return -EIO;
|
||||
}
|
||||
memset(bh->b_data, 0, sb->s_blocksize);
|
||||
|
||||
@@ -243,6 +242,7 @@ static void ext4_init_block_bitmap(struct super_block *sb,
|
||||
sb->s_blocksize * 8, bh->b_data);
|
||||
ext4_block_bitmap_csum_set(sb, block_group, gdp, bh);
|
||||
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
|
||||
@@ -438,11 +438,15 @@ ext4_read_block_bitmap_nowait(struct super_block *sb, ext4_group_t block_group)
|
||||
}
|
||||
ext4_lock_group(sb, block_group);
|
||||
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_buffer_uptodate(bh);
|
||||
ext4_unlock_group(sb, block_group);
|
||||
unlock_buffer(bh);
|
||||
if (err)
|
||||
ext4_error(sb, "Checksum bad for grp %u", block_group);
|
||||
return bh;
|
||||
}
|
||||
ext4_unlock_group(sb, block_group);
|
||||
@@ -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
|
||||
* fail EDQUOT for metdata, but we do account for it.
|
||||
*/
|
||||
if (!(*errp) &&
|
||||
ext4_test_inode_state(inode, EXT4_STATE_DELALLOC_RESERVED)) {
|
||||
if (!(*errp) && (flags & EXT4_MB_DELALLOC_RESERVED)) {
|
||||
spin_lock(&EXT4_I(inode)->i_block_reservation_lock);
|
||||
spin_unlock(&EXT4_I(inode)->i_block_reservation_lock);
|
||||
dquot_alloc_block_nofail(inode,
|
||||
|
||||
+4
-8
@@ -24,8 +24,7 @@ int ext4_inode_bitmap_csum_verify(struct super_block *sb, ext4_group_t group,
|
||||
__u32 provided, calculated;
|
||||
struct ext4_sb_info *sbi = EXT4_SB(sb);
|
||||
|
||||
if (!EXT4_HAS_RO_COMPAT_FEATURE(sb,
|
||||
EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
|
||||
if (!ext4_has_metadata_csum(sb))
|
||||
return 1;
|
||||
|
||||
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,
|
||||
__u32 csum;
|
||||
struct ext4_sb_info *sbi = EXT4_SB(sb);
|
||||
|
||||
if (!EXT4_HAS_RO_COMPAT_FEATURE(sb,
|
||||
EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
|
||||
if (!ext4_has_metadata_csum(sb))
|
||||
return;
|
||||
|
||||
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,
|
||||
struct ext4_sb_info *sbi = EXT4_SB(sb);
|
||||
int sz = EXT4_CLUSTERS_PER_GROUP(sb) / 8;
|
||||
|
||||
if (!EXT4_HAS_RO_COMPAT_FEATURE(sb,
|
||||
EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
|
||||
if (!ext4_has_metadata_csum(sb))
|
||||
return 1;
|
||||
|
||||
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,
|
||||
__u32 csum;
|
||||
struct ext4_sb_info *sbi = EXT4_SB(sb);
|
||||
|
||||
if (!EXT4_HAS_RO_COMPAT_FEATURE(sb,
|
||||
EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
|
||||
if (!ext4_has_metadata_csum(sb))
|
||||
return;
|
||||
|
||||
csum = ext4_chksum(sbi, sbi->s_csum_seed, (__u8 *)bh->b_data, sz);
|
||||
|
||||
+3
-5
@@ -151,13 +151,11 @@ static int ext4_readdir(struct file *file, struct dir_context *ctx)
|
||||
&file->f_ra, file,
|
||||
index, 1);
|
||||
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 (!dir_has_error) {
|
||||
EXT4_ERROR_FILE(file, 0,
|
||||
|
||||
+31
-19
@@ -572,15 +572,15 @@ enum {
|
||||
|
||||
/*
|
||||
* 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(),
|
||||
* ext4_ext_insert_extent(), and ext4_ext_create_new_leaf().
|
||||
* EXT4_EX_NOCACHE is used to indicate that the we shouldn't be
|
||||
* caching the extents when reading from the extent tree while a
|
||||
* truncate or punch hole operation is in progress.
|
||||
*/
|
||||
#define EXT4_EX_NOCACHE 0x0400
|
||||
#define EXT4_EX_FORCE_CACHE 0x0800
|
||||
#define EXT4_EX_NOCACHE 0x40000000
|
||||
#define EXT4_EX_FORCE_CACHE 0x20000000
|
||||
|
||||
/*
|
||||
* Flags used by ext4_free_blocks
|
||||
@@ -890,6 +890,7 @@ struct ext4_inode_info {
|
||||
struct ext4_es_tree i_es_tree;
|
||||
rwlock_t i_es_lock;
|
||||
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 long i_touch_when; /* jiffies of last accessing */
|
||||
|
||||
@@ -1174,6 +1175,9 @@ struct ext4_super_block {
|
||||
#define EXT4_MF_MNTDIR_SAMPLED 0x0001
|
||||
#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
|
||||
*/
|
||||
@@ -1237,7 +1241,7 @@ struct ext4_sb_info {
|
||||
u32 s_min_batch_time;
|
||||
struct block_device *journal_bdev;
|
||||
#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 */
|
||||
#endif
|
||||
unsigned int s_want_extra_isize; /* New inodes should reserve # bytes */
|
||||
@@ -1330,8 +1334,7 @@ struct ext4_sb_info {
|
||||
/* Reclaim extents from extent status tree */
|
||||
struct shrinker s_es_shrinker;
|
||||
struct list_head s_es_lru;
|
||||
unsigned long s_es_last_sorted;
|
||||
struct percpu_counter s_extent_cache_cnt;
|
||||
struct ext4_es_stats s_es_stats;
|
||||
struct mb_cache *s_mb_cache;
|
||||
spinlock_t s_es_lru_lock ____cacheline_aligned_in_smp;
|
||||
|
||||
@@ -1399,7 +1402,6 @@ enum {
|
||||
EXT4_STATE_EXT_MIGRATE, /* Inode is migrating */
|
||||
EXT4_STATE_DIO_UNWRITTEN, /* need convert on dio done*/
|
||||
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
|
||||
nolocking */
|
||||
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,
|
||||
extern int ext4_trim_fs(struct super_block *, struct fstrim_range *);
|
||||
|
||||
/* inode.c */
|
||||
struct buffer_head *ext4_getblk(handle_t *, struct inode *,
|
||||
ext4_lblk_t, int, int *);
|
||||
struct buffer_head *ext4_bread(handle_t *, struct inode *,
|
||||
ext4_lblk_t, int, int *);
|
||||
struct buffer_head *ext4_getblk(handle_t *, struct inode *, ext4_lblk_t, int);
|
||||
struct buffer_head *ext4_bread(handle_t *, struct inode *, ext4_lblk_t, int);
|
||||
int ext4_get_block_write(struct inode *inode, sector_t iblock,
|
||||
struct buffer_head *bh_result, int create);
|
||||
int ext4_get_block(struct inode *inode, sector_t iblock,
|
||||
@@ -2109,6 +2109,7 @@ int do_journal_get_write_access(handle_t *handle,
|
||||
#define CONVERT_INLINE_DATA 2
|
||||
|
||||
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_setattr(struct dentry *, struct iattr *);
|
||||
extern int ext4_getattr(struct vfsmount *mnt, struct dentry *dentry,
|
||||
@@ -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)
|
||||
{
|
||||
return EXT4_HAS_RO_COMPAT_FEATURE(sb,
|
||||
EXT4_FEATURE_RO_COMPAT_GDT_CSUM |
|
||||
EXT4_FEATURE_RO_COMPAT_METADATA_CSUM);
|
||||
EXT4_FEATURE_RO_COMPAT_GDT_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)
|
||||
{
|
||||
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,
|
||||
struct ext4_extent *ex1,
|
||||
struct ext4_extent *ex2);
|
||||
extern int ext4_ext_insert_extent(handle_t *, struct inode *,
|
||||
struct ext4_ext_path *,
|
||||
struct ext4_ext_path **,
|
||||
struct ext4_extent *, int);
|
||||
extern struct ext4_ext_path *ext4_ext_find_extent(struct inode *, ext4_lblk_t,
|
||||
struct ext4_ext_path *,
|
||||
int flags);
|
||||
extern struct ext4_ext_path *ext4_find_extent(struct inode *, ext4_lblk_t,
|
||||
struct ext4_ext_path **,
|
||||
int flags);
|
||||
extern void ext4_ext_drop_refs(struct ext4_ext_path *);
|
||||
extern int ext4_ext_check_inode(struct inode *inode);
|
||||
extern int ext4_find_delalloc_range(struct inode *inode,
|
||||
ext4_lblk_t lblk_start,
|
||||
ext4_lblk_t lblk_end);
|
||||
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,
|
||||
__u64 start, __u64 len);
|
||||
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_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 */
|
||||
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,
|
||||
extern int ext4_move_extents(struct file *o_filp, struct file *d_filp,
|
||||
__u64 start_orig, __u64 start_donor,
|
||||
__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 */
|
||||
extern int __init ext4_init_pageio(void);
|
||||
|
||||
@@ -123,6 +123,7 @@ find_ext4_extent_tail(struct ext4_extent_header *eh)
|
||||
struct ext4_ext_path {
|
||||
ext4_fsblk_t p_block;
|
||||
__u16 p_depth;
|
||||
__u16 p_maxdepth;
|
||||
struct ext4_extent *p_ext;
|
||||
struct ext4_extent_idx *p_idx;
|
||||
struct ext4_extent_header *p_hdr;
|
||||
|
||||
+2
-2
@@ -256,8 +256,8 @@ int __ext4_handle_dirty_metadata(const char *where, unsigned int line,
|
||||
set_buffer_prio(bh);
|
||||
if (ext4_handle_valid(handle)) {
|
||||
err = jbd2_journal_dirty_metadata(handle, bh);
|
||||
/* Errors can only happen if there is a bug */
|
||||
if (WARN_ON_ONCE(err)) {
|
||||
/* Errors can only happen due to aborted journal or a nasty bug */
|
||||
if (!is_handle_aborted(handle) && WARN_ON_ONCE(err)) {
|
||||
ext4_journal_abort_handle(where, line, __func__, bh,
|
||||
handle, err);
|
||||
if (inode == NULL) {
|
||||
|
||||
+3
-3
@@ -102,9 +102,9 @@
|
||||
#define EXT4_QUOTA_INIT_BLOCKS(sb) 0
|
||||
#define EXT4_QUOTA_DEL_BLOCKS(sb) 0
|
||||
#endif
|
||||
#define EXT4_MAXQUOTAS_TRANS_BLOCKS(sb) (MAXQUOTAS*EXT4_QUOTA_TRANS_BLOCKS(sb))
|
||||
#define EXT4_MAXQUOTAS_INIT_BLOCKS(sb) (MAXQUOTAS*EXT4_QUOTA_INIT_BLOCKS(sb))
|
||||
#define EXT4_MAXQUOTAS_DEL_BLOCKS(sb) (MAXQUOTAS*EXT4_QUOTA_DEL_BLOCKS(sb))
|
||||
#define EXT4_MAXQUOTAS_TRANS_BLOCKS(sb) (EXT4_MAXQUOTAS*EXT4_QUOTA_TRANS_BLOCKS(sb))
|
||||
#define EXT4_MAXQUOTAS_INIT_BLOCKS(sb) (EXT4_MAXQUOTAS*EXT4_QUOTA_INIT_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)
|
||||
{
|
||||
|
||||
+404
-217
File diff suppressed because it is too large
Load Diff
+182
-18
@@ -11,6 +11,8 @@
|
||||
*/
|
||||
#include <linux/rbtree.h>
|
||||
#include <linux/list_sort.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include "ext4.h"
|
||||
#include "extents_status.h"
|
||||
|
||||
@@ -313,19 +315,27 @@ ext4_es_alloc_extent(struct inode *inode, ext4_lblk_t lblk, ext4_lblk_t len,
|
||||
*/
|
||||
if (!ext4_es_is_delayed(es)) {
|
||||
EXT4_I(inode)->i_es_lru_nr++;
|
||||
percpu_counter_inc(&EXT4_SB(inode->i_sb)->s_extent_cache_cnt);
|
||||
percpu_counter_inc(&EXT4_SB(inode->i_sb)->
|
||||
s_es_stats.es_stats_lru_cnt);
|
||||
}
|
||||
|
||||
EXT4_I(inode)->i_es_all_nr++;
|
||||
percpu_counter_inc(&EXT4_SB(inode->i_sb)->s_es_stats.es_stats_all_cnt);
|
||||
|
||||
return es;
|
||||
}
|
||||
|
||||
static void ext4_es_free_extent(struct inode *inode, struct extent_status *es)
|
||||
{
|
||||
EXT4_I(inode)->i_es_all_nr--;
|
||||
percpu_counter_dec(&EXT4_SB(inode->i_sb)->s_es_stats.es_stats_all_cnt);
|
||||
|
||||
/* Decrease the lru counter when this es is not delayed */
|
||||
if (!ext4_es_is_delayed(es)) {
|
||||
BUG_ON(EXT4_I(inode)->i_es_lru_nr == 0);
|
||||
EXT4_I(inode)->i_es_lru_nr--;
|
||||
percpu_counter_dec(&EXT4_SB(inode->i_sb)->s_extent_cache_cnt);
|
||||
percpu_counter_dec(&EXT4_SB(inode->i_sb)->
|
||||
s_es_stats.es_stats_lru_cnt);
|
||||
}
|
||||
|
||||
kmem_cache_free(ext4_es_cachep, es);
|
||||
@@ -426,7 +436,7 @@ static void ext4_es_insert_extent_ext_check(struct inode *inode,
|
||||
unsigned short ee_len;
|
||||
int depth, ee_status, es_status;
|
||||
|
||||
path = ext4_ext_find_extent(inode, es->es_lblk, NULL, EXT4_EX_NOCACHE);
|
||||
path = ext4_find_extent(inode, es->es_lblk, NULL, EXT4_EX_NOCACHE);
|
||||
if (IS_ERR(path))
|
||||
return;
|
||||
|
||||
@@ -499,10 +509,8 @@ static void ext4_es_insert_extent_ext_check(struct inode *inode,
|
||||
}
|
||||
}
|
||||
out:
|
||||
if (path) {
|
||||
ext4_ext_drop_refs(path);
|
||||
kfree(path);
|
||||
}
|
||||
ext4_ext_drop_refs(path);
|
||||
kfree(path);
|
||||
}
|
||||
|
||||
static void ext4_es_insert_extent_ind_check(struct inode *inode,
|
||||
@@ -731,6 +739,7 @@ int ext4_es_lookup_extent(struct inode *inode, ext4_lblk_t lblk,
|
||||
struct extent_status *es)
|
||||
{
|
||||
struct ext4_es_tree *tree;
|
||||
struct ext4_es_stats *stats;
|
||||
struct extent_status *es1 = NULL;
|
||||
struct rb_node *node;
|
||||
int found = 0;
|
||||
@@ -767,11 +776,15 @@ int ext4_es_lookup_extent(struct inode *inode, ext4_lblk_t lblk,
|
||||
}
|
||||
|
||||
out:
|
||||
stats = &EXT4_SB(inode->i_sb)->s_es_stats;
|
||||
if (found) {
|
||||
BUG_ON(!es1);
|
||||
es->es_lblk = es1->es_lblk;
|
||||
es->es_len = es1->es_len;
|
||||
es->es_pblk = es1->es_pblk;
|
||||
stats->es_stats_cache_hits++;
|
||||
} else {
|
||||
stats->es_stats_cache_misses++;
|
||||
}
|
||||
|
||||
read_unlock(&EXT4_I(inode)->i_es_lock);
|
||||
@@ -933,11 +946,16 @@ static int __ext4_es_shrink(struct ext4_sb_info *sbi, int nr_to_scan,
|
||||
struct ext4_inode_info *locked_ei)
|
||||
{
|
||||
struct ext4_inode_info *ei;
|
||||
struct ext4_es_stats *es_stats;
|
||||
struct list_head *cur, *tmp;
|
||||
LIST_HEAD(skipped);
|
||||
ktime_t start_time;
|
||||
u64 scan_time;
|
||||
int nr_shrunk = 0;
|
||||
int retried = 0, skip_precached = 1, nr_skipped = 0;
|
||||
|
||||
es_stats = &sbi->s_es_stats;
|
||||
start_time = ktime_get();
|
||||
spin_lock(&sbi->s_es_lru_lock);
|
||||
|
||||
retry:
|
||||
@@ -948,7 +966,8 @@ retry:
|
||||
* If we have already reclaimed all extents from extent
|
||||
* status tree, just stop the loop immediately.
|
||||
*/
|
||||
if (percpu_counter_read_positive(&sbi->s_extent_cache_cnt) == 0)
|
||||
if (percpu_counter_read_positive(
|
||||
&es_stats->es_stats_lru_cnt) == 0)
|
||||
break;
|
||||
|
||||
ei = list_entry(cur, struct ext4_inode_info, i_es_lru);
|
||||
@@ -958,7 +977,7 @@ retry:
|
||||
* time. Normally we try hard to avoid shrinking
|
||||
* precached inodes, but we will as a last resort.
|
||||
*/
|
||||
if ((sbi->s_es_last_sorted < ei->i_touch_when) ||
|
||||
if ((es_stats->es_stats_last_sorted < ei->i_touch_when) ||
|
||||
(skip_precached && ext4_test_inode_state(&ei->vfs_inode,
|
||||
EXT4_STATE_EXT_PRECACHED))) {
|
||||
nr_skipped++;
|
||||
@@ -992,7 +1011,7 @@ retry:
|
||||
if ((nr_shrunk == 0) && nr_skipped && !retried) {
|
||||
retried++;
|
||||
list_sort(NULL, &sbi->s_es_lru, ext4_inode_touch_time_cmp);
|
||||
sbi->s_es_last_sorted = jiffies;
|
||||
es_stats->es_stats_last_sorted = jiffies;
|
||||
ei = list_first_entry(&sbi->s_es_lru, struct ext4_inode_info,
|
||||
i_es_lru);
|
||||
/*
|
||||
@@ -1010,6 +1029,22 @@ retry:
|
||||
if (locked_ei && nr_shrunk == 0)
|
||||
nr_shrunk = __es_try_to_reclaim_extents(locked_ei, nr_to_scan);
|
||||
|
||||
scan_time = ktime_to_ns(ktime_sub(ktime_get(), start_time));
|
||||
if (likely(es_stats->es_stats_scan_time))
|
||||
es_stats->es_stats_scan_time = (scan_time +
|
||||
es_stats->es_stats_scan_time*3) / 4;
|
||||
else
|
||||
es_stats->es_stats_scan_time = scan_time;
|
||||
if (scan_time > es_stats->es_stats_max_scan_time)
|
||||
es_stats->es_stats_max_scan_time = scan_time;
|
||||
if (likely(es_stats->es_stats_shrunk))
|
||||
es_stats->es_stats_shrunk = (nr_shrunk +
|
||||
es_stats->es_stats_shrunk*3) / 4;
|
||||
else
|
||||
es_stats->es_stats_shrunk = nr_shrunk;
|
||||
|
||||
trace_ext4_es_shrink(sbi->s_sb, nr_shrunk, scan_time, skip_precached,
|
||||
nr_skipped, retried);
|
||||
return nr_shrunk;
|
||||
}
|
||||
|
||||
@@ -1020,8 +1055,8 @@ static unsigned long ext4_es_count(struct shrinker *shrink,
|
||||
struct ext4_sb_info *sbi;
|
||||
|
||||
sbi = container_of(shrink, struct ext4_sb_info, s_es_shrinker);
|
||||
nr = percpu_counter_read_positive(&sbi->s_extent_cache_cnt);
|
||||
trace_ext4_es_shrink_enter(sbi->s_sb, sc->nr_to_scan, nr);
|
||||
nr = percpu_counter_read_positive(&sbi->s_es_stats.es_stats_lru_cnt);
|
||||
trace_ext4_es_shrink_count(sbi->s_sb, sc->nr_to_scan, nr);
|
||||
return nr;
|
||||
}
|
||||
|
||||
@@ -1033,31 +1068,160 @@ static unsigned long ext4_es_scan(struct shrinker *shrink,
|
||||
int nr_to_scan = sc->nr_to_scan;
|
||||
int ret, nr_shrunk;
|
||||
|
||||
ret = percpu_counter_read_positive(&sbi->s_extent_cache_cnt);
|
||||
trace_ext4_es_shrink_enter(sbi->s_sb, nr_to_scan, ret);
|
||||
ret = percpu_counter_read_positive(&sbi->s_es_stats.es_stats_lru_cnt);
|
||||
trace_ext4_es_shrink_scan_enter(sbi->s_sb, nr_to_scan, ret);
|
||||
|
||||
if (!nr_to_scan)
|
||||
return ret;
|
||||
|
||||
nr_shrunk = __ext4_es_shrink(sbi, nr_to_scan, NULL);
|
||||
|
||||
trace_ext4_es_shrink_exit(sbi->s_sb, nr_shrunk, ret);
|
||||
trace_ext4_es_shrink_scan_exit(sbi->s_sb, nr_shrunk, ret);
|
||||
return nr_shrunk;
|
||||
}
|
||||
|
||||
void ext4_es_register_shrinker(struct ext4_sb_info *sbi)
|
||||
static void *ext4_es_seq_shrinker_info_start(struct seq_file *seq, loff_t *pos)
|
||||
{
|
||||
return *pos ? NULL : SEQ_START_TOKEN;
|
||||
}
|
||||
|
||||
static void *
|
||||
ext4_es_seq_shrinker_info_next(struct seq_file *seq, void *v, loff_t *pos)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int ext4_es_seq_shrinker_info_show(struct seq_file *seq, void *v)
|
||||
{
|
||||
struct ext4_sb_info *sbi = seq->private;
|
||||
struct ext4_es_stats *es_stats = &sbi->s_es_stats;
|
||||
struct ext4_inode_info *ei, *max = NULL;
|
||||
unsigned int inode_cnt = 0;
|
||||
|
||||
if (v != SEQ_START_TOKEN)
|
||||
return 0;
|
||||
|
||||
/* here we just find an inode that has the max nr. of objects */
|
||||
spin_lock(&sbi->s_es_lru_lock);
|
||||
list_for_each_entry(ei, &sbi->s_es_lru, i_es_lru) {
|
||||
inode_cnt++;
|
||||
if (max && max->i_es_all_nr < ei->i_es_all_nr)
|
||||
max = ei;
|
||||
else if (!max)
|
||||
max = ei;
|
||||
}
|
||||
spin_unlock(&sbi->s_es_lru_lock);
|
||||
|
||||
seq_printf(seq, "stats:\n %lld objects\n %lld reclaimable objects\n",
|
||||
percpu_counter_sum_positive(&es_stats->es_stats_all_cnt),
|
||||
percpu_counter_sum_positive(&es_stats->es_stats_lru_cnt));
|
||||
seq_printf(seq, " %lu/%lu cache hits/misses\n",
|
||||
es_stats->es_stats_cache_hits,
|
||||
es_stats->es_stats_cache_misses);
|
||||
if (es_stats->es_stats_last_sorted != 0)
|
||||
seq_printf(seq, " %u ms last sorted interval\n",
|
||||
jiffies_to_msecs(jiffies -
|
||||
es_stats->es_stats_last_sorted));
|
||||
if (inode_cnt)
|
||||
seq_printf(seq, " %d inodes on lru list\n", inode_cnt);
|
||||
|
||||
seq_printf(seq, "average:\n %llu us scan time\n",
|
||||
div_u64(es_stats->es_stats_scan_time, 1000));
|
||||
seq_printf(seq, " %lu shrunk objects\n", es_stats->es_stats_shrunk);
|
||||
if (inode_cnt)
|
||||
seq_printf(seq,
|
||||
"maximum:\n %lu inode (%u objects, %u reclaimable)\n"
|
||||
" %llu us max scan time\n",
|
||||
max->vfs_inode.i_ino, max->i_es_all_nr, max->i_es_lru_nr,
|
||||
div_u64(es_stats->es_stats_max_scan_time, 1000));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ext4_es_seq_shrinker_info_stop(struct seq_file *seq, void *v)
|
||||
{
|
||||
}
|
||||
|
||||
static const struct seq_operations ext4_es_seq_shrinker_info_ops = {
|
||||
.start = ext4_es_seq_shrinker_info_start,
|
||||
.next = ext4_es_seq_shrinker_info_next,
|
||||
.stop = ext4_es_seq_shrinker_info_stop,
|
||||
.show = ext4_es_seq_shrinker_info_show,
|
||||
};
|
||||
|
||||
static int
|
||||
ext4_es_seq_shrinker_info_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = seq_open(file, &ext4_es_seq_shrinker_info_ops);
|
||||
if (!ret) {
|
||||
struct seq_file *m = file->private_data;
|
||||
m->private = PDE_DATA(inode);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
ext4_es_seq_shrinker_info_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
return seq_release(inode, file);
|
||||
}
|
||||
|
||||
static const struct file_operations ext4_es_seq_shrinker_info_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = ext4_es_seq_shrinker_info_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = ext4_es_seq_shrinker_info_release,
|
||||
};
|
||||
|
||||
int ext4_es_register_shrinker(struct ext4_sb_info *sbi)
|
||||
{
|
||||
int err;
|
||||
|
||||
INIT_LIST_HEAD(&sbi->s_es_lru);
|
||||
spin_lock_init(&sbi->s_es_lru_lock);
|
||||
sbi->s_es_last_sorted = 0;
|
||||
sbi->s_es_stats.es_stats_last_sorted = 0;
|
||||
sbi->s_es_stats.es_stats_shrunk = 0;
|
||||
sbi->s_es_stats.es_stats_cache_hits = 0;
|
||||
sbi->s_es_stats.es_stats_cache_misses = 0;
|
||||
sbi->s_es_stats.es_stats_scan_time = 0;
|
||||
sbi->s_es_stats.es_stats_max_scan_time = 0;
|
||||
err = percpu_counter_init(&sbi->s_es_stats.es_stats_all_cnt, 0, GFP_KERNEL);
|
||||
if (err)
|
||||
return err;
|
||||
err = percpu_counter_init(&sbi->s_es_stats.es_stats_lru_cnt, 0, GFP_KERNEL);
|
||||
if (err)
|
||||
goto err1;
|
||||
|
||||
sbi->s_es_shrinker.scan_objects = ext4_es_scan;
|
||||
sbi->s_es_shrinker.count_objects = ext4_es_count;
|
||||
sbi->s_es_shrinker.seeks = DEFAULT_SEEKS;
|
||||
register_shrinker(&sbi->s_es_shrinker);
|
||||
err = register_shrinker(&sbi->s_es_shrinker);
|
||||
if (err)
|
||||
goto err2;
|
||||
|
||||
if (sbi->s_proc)
|
||||
proc_create_data("es_shrinker_info", S_IRUGO, sbi->s_proc,
|
||||
&ext4_es_seq_shrinker_info_fops, sbi);
|
||||
|
||||
return 0;
|
||||
|
||||
err2:
|
||||
percpu_counter_destroy(&sbi->s_es_stats.es_stats_lru_cnt);
|
||||
err1:
|
||||
percpu_counter_destroy(&sbi->s_es_stats.es_stats_all_cnt);
|
||||
return err;
|
||||
}
|
||||
|
||||
void ext4_es_unregister_shrinker(struct ext4_sb_info *sbi)
|
||||
{
|
||||
if (sbi->s_proc)
|
||||
remove_proc_entry("es_shrinker_info", sbi->s_proc);
|
||||
percpu_counter_destroy(&sbi->s_es_stats.es_stats_all_cnt);
|
||||
percpu_counter_destroy(&sbi->s_es_stats.es_stats_lru_cnt);
|
||||
unregister_shrinker(&sbi->s_es_shrinker);
|
||||
}
|
||||
|
||||
|
||||
@@ -64,6 +64,17 @@ struct ext4_es_tree {
|
||||
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 void ext4_exit_es(void);
|
||||
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,
|
||||
(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_lru_add(struct inode *inode);
|
||||
extern void ext4_es_lru_del(struct inode *inode);
|
||||
|
||||
+1
-2
@@ -1011,8 +1011,7 @@ got:
|
||||
spin_unlock(&sbi->s_next_gen_lock);
|
||||
|
||||
/* Precompute checksum seed for inode metadata */
|
||||
if (EXT4_HAS_RO_COMPAT_FEATURE(sb,
|
||||
EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) {
|
||||
if (ext4_has_metadata_csum(sb)) {
|
||||
__u32 csum;
|
||||
__le32 inum = cpu_to_le32(inode->i_ino);
|
||||
__le32 gen = cpu_to_le32(inode->i_generation);
|
||||
|
||||
+42
-44
@@ -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
|
||||
* as described above and return 0.
|
||||
*/
|
||||
static int ext4_alloc_branch(handle_t *handle, struct inode *inode,
|
||||
ext4_lblk_t iblock, int indirect_blks,
|
||||
int *blks, ext4_fsblk_t goal,
|
||||
ext4_lblk_t *offsets, Indirect *branch)
|
||||
static int ext4_alloc_branch(handle_t *handle,
|
||||
struct ext4_allocation_request *ar,
|
||||
int indirect_blks, ext4_lblk_t *offsets,
|
||||
Indirect *branch)
|
||||
{
|
||||
struct ext4_allocation_request ar;
|
||||
struct buffer_head * bh;
|
||||
ext4_fsblk_t b, new_blocks[4];
|
||||
__le32 *p;
|
||||
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++) {
|
||||
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
|
||||
goal = new_blocks[i] = ext4_new_meta_blocks(handle, inode,
|
||||
goal, 0, NULL, &err);
|
||||
ar->goal = new_blocks[i] = ext4_new_meta_blocks(handle,
|
||||
ar->inode, ar->goal,
|
||||
ar->flags & EXT4_MB_DELALLOC_RESERVED,
|
||||
NULL, &err);
|
||||
if (err) {
|
||||
i--;
|
||||
goto failed;
|
||||
@@ -354,7 +344,7 @@ static int ext4_alloc_branch(handle_t *handle, struct inode *inode,
|
||||
if (i == 0)
|
||||
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)) {
|
||||
err = -ENOMEM;
|
||||
goto failed;
|
||||
@@ -372,7 +362,7 @@ static int ext4_alloc_branch(handle_t *handle, struct inode *inode,
|
||||
b = new_blocks[i];
|
||||
|
||||
if (i == indirect_blks)
|
||||
len = ar.len;
|
||||
len = ar->len;
|
||||
for (j = 0; j < len; j++)
|
||||
*p++ = cpu_to_le32(b++);
|
||||
|
||||
@@ -381,11 +371,10 @@ static int ext4_alloc_branch(handle_t *handle, struct inode *inode,
|
||||
unlock_buffer(bh);
|
||||
|
||||
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)
|
||||
goto failed;
|
||||
}
|
||||
*blks = ar.len;
|
||||
return 0;
|
||||
failed:
|
||||
for (; i >= 0; i--) {
|
||||
@@ -396,10 +385,10 @@ failed:
|
||||
* existing before ext4_alloc_branch() was called.
|
||||
*/
|
||||
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);
|
||||
ext4_free_blocks(handle, inode, NULL, new_blocks[i],
|
||||
(i == indirect_blks) ? ar.len : 1, 0);
|
||||
ext4_free_blocks(handle, ar->inode, NULL, new_blocks[i],
|
||||
(i == indirect_blks) ? ar->len : 1, 0);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
@@ -419,9 +408,9 @@ failed:
|
||||
* inode (->i_blocks, etc.). In case of success we end up with the full
|
||||
* chain to new block and return 0.
|
||||
*/
|
||||
static int ext4_splice_branch(handle_t *handle, struct inode *inode,
|
||||
ext4_lblk_t block, Indirect *where, int num,
|
||||
int blks)
|
||||
static int ext4_splice_branch(handle_t *handle,
|
||||
struct ext4_allocation_request *ar,
|
||||
Indirect *where, int num)
|
||||
{
|
||||
int i;
|
||||
int err = 0;
|
||||
@@ -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
|
||||
* direct blocks blocks
|
||||
*/
|
||||
if (num == 0 && blks > 1) {
|
||||
if (num == 0 && ar->len > 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++);
|
||||
}
|
||||
|
||||
@@ -465,14 +454,14 @@ static int ext4_splice_branch(handle_t *handle, struct inode *inode,
|
||||
*/
|
||||
jbd_debug(5, "splicing indirect only\n");
|
||||
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)
|
||||
goto err_out;
|
||||
} else {
|
||||
/*
|
||||
* 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");
|
||||
}
|
||||
return err;
|
||||
@@ -484,11 +473,11 @@ err_out:
|
||||
* need to revoke the block, which is why we don't
|
||||
* 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(handle, inode, NULL, le32_to_cpu(where[num].key),
|
||||
blks, 0);
|
||||
ext4_free_blocks(handle, ar->inode, NULL, le32_to_cpu(where[num].key),
|
||||
ar->len, 0);
|
||||
|
||||
return err;
|
||||
}
|
||||
@@ -525,11 +514,11 @@ int ext4_ind_map_blocks(handle_t *handle, struct inode *inode,
|
||||
struct ext4_map_blocks *map,
|
||||
int flags)
|
||||
{
|
||||
struct ext4_allocation_request ar;
|
||||
int err = -EIO;
|
||||
ext4_lblk_t offsets[4];
|
||||
Indirect chain[4];
|
||||
Indirect *partial;
|
||||
ext4_fsblk_t goal;
|
||||
int indirect_blks;
|
||||
int blocks_to_boundary = 0;
|
||||
int depth;
|
||||
@@ -579,7 +568,16 @@ int ext4_ind_map_blocks(handle_t *handle, struct inode *inode,
|
||||
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 */
|
||||
indirect_blks = (chain + depth) - partial - 1;
|
||||
@@ -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
|
||||
* direct blocks to allocate for this branch.
|
||||
*/
|
||||
count = ext4_blks_to_allocate(partial, indirect_blks,
|
||||
map->m_len, blocks_to_boundary);
|
||||
ar.len = ext4_blks_to_allocate(partial, indirect_blks,
|
||||
map->m_len, blocks_to_boundary);
|
||||
|
||||
/*
|
||||
* Block out ext4_truncate while we alter the tree
|
||||
*/
|
||||
err = ext4_alloc_branch(handle, inode, map->m_lblk, indirect_blks,
|
||||
&count, goal,
|
||||
err = ext4_alloc_branch(handle, &ar, indirect_blks,
|
||||
offsets + (partial - chain), partial);
|
||||
|
||||
/*
|
||||
@@ -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
|
||||
*/
|
||||
if (!err)
|
||||
err = ext4_splice_branch(handle, inode, map->m_lblk,
|
||||
partial, indirect_blks, count);
|
||||
err = ext4_splice_branch(handle, &ar, partial, indirect_blks);
|
||||
if (err)
|
||||
goto cleanup;
|
||||
|
||||
map->m_flags |= EXT4_MAP_NEW;
|
||||
|
||||
ext4_update_inode_fsync_trans(handle, inode, 1);
|
||||
count = ar.len;
|
||||
got_it:
|
||||
map->m_flags |= EXT4_MAP_MAPPED;
|
||||
map->m_pblk = le32_to_cpu(chain[depth-1].key);
|
||||
|
||||
+4
-3
@@ -594,6 +594,7 @@ retry:
|
||||
if (ret) {
|
||||
unlock_page(page);
|
||||
page_cache_release(page);
|
||||
page = NULL;
|
||||
ext4_orphan_add(handle, inode);
|
||||
up_write(&EXT4_I(inode)->xattr_sem);
|
||||
sem_held = 0;
|
||||
@@ -613,7 +614,8 @@ retry:
|
||||
if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries))
|
||||
goto retry;
|
||||
|
||||
block_commit_write(page, from, to);
|
||||
if (page)
|
||||
block_commit_write(page, from, to);
|
||||
out:
|
||||
if (page) {
|
||||
unlock_page(page);
|
||||
@@ -1126,8 +1128,7 @@ static int ext4_finish_convert_inline_dir(handle_t *handle,
|
||||
memcpy((void *)de, buf + EXT4_INLINE_DOTDOT_SIZE,
|
||||
inline_size - EXT4_INLINE_DOTDOT_SIZE);
|
||||
|
||||
if (EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb,
|
||||
EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
|
||||
if (ext4_has_metadata_csum(inode->i_sb))
|
||||
csum_size = sizeof(struct ext4_dir_entry_tail);
|
||||
|
||||
inode->i_size = inode->i_sb->s_blocksize;
|
||||
|
||||
+67
-66
@@ -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 !=
|
||||
cpu_to_le32(EXT4_OS_LINUX) ||
|
||||
!EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb,
|
||||
EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
|
||||
!ext4_has_metadata_csum(inode->i_sb))
|
||||
return 1;
|
||||
|
||||
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,
|
||||
|
||||
if (EXT4_SB(inode->i_sb)->s_es->s_creator_os !=
|
||||
cpu_to_le32(EXT4_OS_LINUX) ||
|
||||
!EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb,
|
||||
EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
|
||||
!ext4_has_metadata_csum(inode->i_sb))
|
||||
return;
|
||||
|
||||
csum = ext4_inode_csum(inode, raw, ei);
|
||||
@@ -224,16 +222,15 @@ void ext4_evict_inode(struct inode *inode)
|
||||
goto no_delete;
|
||||
}
|
||||
|
||||
if (!is_bad_inode(inode))
|
||||
dquot_initialize(inode);
|
||||
if (is_bad_inode(inode))
|
||||
goto no_delete;
|
||||
dquot_initialize(inode);
|
||||
|
||||
if (ext4_should_order_data(inode))
|
||||
ext4_begin_ordered_truncate(inode, 0);
|
||||
truncate_inode_pages_final(&inode->i_data);
|
||||
|
||||
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
|
||||
@@ -590,19 +587,11 @@ found:
|
||||
/*
|
||||
* New blocks allocate and/or writing to unwritten extent
|
||||
* 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.
|
||||
*/
|
||||
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
|
||||
* could have changed the inode type in between
|
||||
@@ -631,8 +620,6 @@ found:
|
||||
(flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE))
|
||||
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) {
|
||||
unsigned int status;
|
||||
@@ -734,11 +721,11 @@ int ext4_get_block(struct inode *inode, sector_t iblock,
|
||||
* `handle' can be NULL if create is zero
|
||||
*/
|
||||
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 buffer_head *bh;
|
||||
int fatal = 0, err;
|
||||
int err;
|
||||
|
||||
J_ASSERT(handle != NULL || create == 0);
|
||||
|
||||
@@ -747,21 +734,14 @@ struct buffer_head *ext4_getblk(handle_t *handle, struct inode *inode,
|
||||
err = ext4_map_blocks(handle, inode, &map,
|
||||
create ? EXT4_GET_BLOCKS_CREATE : 0);
|
||||
|
||||
/* ensure we send some value back into *errp */
|
||||
*errp = 0;
|
||||
|
||||
if (create && err == 0)
|
||||
err = -ENOSPC; /* should never happen */
|
||||
if (err == 0)
|
||||
return create ? ERR_PTR(-ENOSPC) : NULL;
|
||||
if (err < 0)
|
||||
*errp = err;
|
||||
if (err <= 0)
|
||||
return NULL;
|
||||
return ERR_PTR(err);
|
||||
|
||||
bh = sb_getblk(inode->i_sb, map.m_pblk);
|
||||
if (unlikely(!bh)) {
|
||||
*errp = -ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
if (unlikely(!bh))
|
||||
return ERR_PTR(-ENOMEM);
|
||||
if (map.m_flags & EXT4_MAP_NEW) {
|
||||
J_ASSERT(create != 0);
|
||||
J_ASSERT(handle != NULL);
|
||||
@@ -775,44 +755,44 @@ struct buffer_head *ext4_getblk(handle_t *handle, struct inode *inode,
|
||||
*/
|
||||
lock_buffer(bh);
|
||||
BUFFER_TRACE(bh, "call get_create_access");
|
||||
fatal = ext4_journal_get_create_access(handle, bh);
|
||||
if (!fatal && !buffer_uptodate(bh)) {
|
||||
err = ext4_journal_get_create_access(handle, bh);
|
||||
if (unlikely(err)) {
|
||||
unlock_buffer(bh);
|
||||
goto errout;
|
||||
}
|
||||
if (!buffer_uptodate(bh)) {
|
||||
memset(bh->b_data, 0, inode->i_sb->s_blocksize);
|
||||
set_buffer_uptodate(bh);
|
||||
}
|
||||
unlock_buffer(bh);
|
||||
BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata");
|
||||
err = ext4_handle_dirty_metadata(handle, inode, bh);
|
||||
if (!fatal)
|
||||
fatal = err;
|
||||
} else {
|
||||
if (unlikely(err))
|
||||
goto errout;
|
||||
} else
|
||||
BUFFER_TRACE(bh, "not a new buffer");
|
||||
}
|
||||
if (fatal) {
|
||||
*errp = fatal;
|
||||
brelse(bh);
|
||||
bh = NULL;
|
||||
}
|
||||
return bh;
|
||||
errout:
|
||||
brelse(bh);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
bh = ext4_getblk(handle, inode, block, create, err);
|
||||
if (!bh)
|
||||
bh = ext4_getblk(handle, inode, block, create);
|
||||
if (IS_ERR(bh))
|
||||
return bh;
|
||||
if (buffer_uptodate(bh))
|
||||
if (!bh || buffer_uptodate(bh))
|
||||
return bh;
|
||||
ll_rw_block(READ | REQ_META | REQ_PRIO, 1, &bh);
|
||||
wait_on_buffer(bh);
|
||||
if (buffer_uptodate(bh))
|
||||
return bh;
|
||||
put_bh(bh);
|
||||
*err = -EIO;
|
||||
return NULL;
|
||||
return ERR_PTR(-EIO);
|
||||
}
|
||||
|
||||
int ext4_walk_page_buffers(handle_t *handle,
|
||||
@@ -1536,7 +1516,7 @@ out_unlock:
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
* reserve space for a single block.
|
||||
*
|
||||
@@ -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
|
||||
* possible.
|
||||
*
|
||||
* We pass in the magic EXT4_GET_BLOCKS_DELALLOC_RESERVE if the blocks
|
||||
* in question are delalloc blocks. This affects functions in many
|
||||
* different parts of the allocation call path. This flag exists
|
||||
* primarily because we don't want to change *many* call functions, so
|
||||
* ext4_map_blocks() will set the EXT4_STATE_DELALLOC_RESERVED flag
|
||||
* once the inode's allocation semaphore is taken.
|
||||
* We pass in the magic EXT4_GET_BLOCKS_DELALLOC_RESERVE if
|
||||
* the blocks in question are delalloc blocks. This indicates
|
||||
* that the blocks and quotas has already been checked when
|
||||
* the data was copied into the page cache.
|
||||
*/
|
||||
get_blocks_flags = EXT4_GET_BLOCKS_CREATE |
|
||||
EXT4_GET_BLOCKS_METADATA_NOFAIL;
|
||||
@@ -2515,6 +2493,20 @@ static int ext4_nonda_switch(struct super_block *sb)
|
||||
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,
|
||||
loff_t pos, unsigned len, unsigned flags,
|
||||
struct page **pagep, void **fsdata)
|
||||
@@ -2565,7 +2557,8 @@ retry_grab:
|
||||
* of file which has an already mapped buffer.
|
||||
*/
|
||||
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)) {
|
||||
page_cache_release(page);
|
||||
return PTR_ERR(handle);
|
||||
@@ -2658,10 +2651,7 @@ static int ext4_da_write_end(struct file *file,
|
||||
if (copied && new_i_size > EXT4_I(inode)->i_disksize) {
|
||||
if (ext4_has_inline_data(inode) ||
|
||||
ext4_da_should_update_i_disksize(page, end)) {
|
||||
down_write(&EXT4_I(inode)->i_data_sem);
|
||||
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);
|
||||
ext4_update_i_disksize(inode, new_i_size);
|
||||
/* We need to mark inode dirty even if
|
||||
* new_i_size is less that inode->i_size
|
||||
* bu greater than i_disksize.(hint delalloc)
|
||||
@@ -3936,8 +3926,7 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
|
||||
ei->i_extra_isize = 0;
|
||||
|
||||
/* Precompute checksum seed for inode metadata */
|
||||
if (EXT4_HAS_RO_COMPAT_FEATURE(sb,
|
||||
EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) {
|
||||
if (ext4_has_metadata_csum(sb)) {
|
||||
struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
|
||||
__u32 csum;
|
||||
__le32 inum = cpu_to_le32(inode->i_ino);
|
||||
@@ -4127,6 +4116,13 @@ bad_inode:
|
||||
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,
|
||||
struct ext4_inode *raw_inode,
|
||||
struct ext4_inode_info *ei)
|
||||
@@ -4226,7 +4222,8 @@ static int ext4_do_update_inode(handle_t *handle,
|
||||
EXT4_INODE_SET_XTIME(i_atime, inode, 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);
|
||||
goto out_brelse;
|
||||
}
|
||||
@@ -4536,8 +4533,12 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr)
|
||||
ext4_orphan_del(NULL, inode);
|
||||
goto err_out;
|
||||
}
|
||||
} else
|
||||
} else {
|
||||
loff_t oldsize = inode->i_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
|
||||
|
||||
+10
-3
@@ -331,8 +331,7 @@ flags_out:
|
||||
if (!inode_owner_or_capable(inode))
|
||||
return -EPERM;
|
||||
|
||||
if (EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb,
|
||||
EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) {
|
||||
if (ext4_has_metadata_csum(inode->i_sb)) {
|
||||
ext4_warning(sb, "Setting inode version is not "
|
||||
"supported with metadata_csum enabled.");
|
||||
return -ENOTTY;
|
||||
@@ -532,9 +531,17 @@ group_add_out:
|
||||
}
|
||||
|
||||
case EXT4_IOC_SWAP_BOOT:
|
||||
{
|
||||
int err;
|
||||
if (!(filp->f_mode & FMODE_WRITE))
|
||||
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: {
|
||||
ext4_fsblk_t n_blocks_count;
|
||||
|
||||
+3
-12
@@ -3155,9 +3155,8 @@ ext4_mb_normalize_request(struct ext4_allocation_context *ac,
|
||||
"start %lu, size %lu, fe_logical %lu",
|
||||
(unsigned long) start, (unsigned long) size,
|
||||
(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));
|
||||
|
||||
/* now prepare goal request */
|
||||
@@ -4410,14 +4409,7 @@ ext4_fsblk_t ext4_mb_new_blocks(handle_t *handle,
|
||||
if (IS_NOQUOTA(ar->inode))
|
||||
ar->flags |= EXT4_MB_USE_ROOT_BLOCKS;
|
||||
|
||||
/*
|
||||
* 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 {
|
||||
if ((ar->flags & EXT4_MB_DELALLOC_RESERVED) == 0) {
|
||||
/* Without delayed allocation we need to verify
|
||||
* there is enough free blocks to do block allocation
|
||||
* and verify allocation doesn't exceed the quota limits.
|
||||
@@ -4528,8 +4520,7 @@ out:
|
||||
if (inquota && ar->len < inquota)
|
||||
dquot_free_block(ar->inode, EXT4_C2B(sbi, inquota - ar->len));
|
||||
if (!ar->len) {
|
||||
if (!ext4_test_inode_state(ar->inode,
|
||||
EXT4_STATE_DELALLOC_RESERVED))
|
||||
if ((ar->flags & EXT4_MB_DELALLOC_RESERVED) == 0)
|
||||
/* release all the reserved blocks if non delalloc */
|
||||
percpu_counter_sub(&sbi->s_dirtyclusters_counter,
|
||||
reserv_clstrs);
|
||||
|
||||
+4
-7
@@ -41,8 +41,7 @@ static int finish_range(handle_t *handle, struct inode *inode,
|
||||
ext4_ext_store_pblock(&newext, lb->first_pblock);
|
||||
/* Locking only for convinience since we are operating on temp inode */
|
||||
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)) {
|
||||
retval = PTR_ERR(path);
|
||||
path = NULL;
|
||||
@@ -81,13 +80,11 @@ static int finish_range(handle_t *handle, struct inode *inode,
|
||||
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:
|
||||
up_write((&EXT4_I(inode)->i_data_sem));
|
||||
if (path) {
|
||||
ext4_ext_drop_refs(path);
|
||||
kfree(path);
|
||||
}
|
||||
ext4_ext_drop_refs(path);
|
||||
kfree(path);
|
||||
lb->first_pblock = 0;
|
||||
return retval;
|
||||
}
|
||||
|
||||
+2
-4
@@ -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)
|
||||
{
|
||||
if (!EXT4_HAS_RO_COMPAT_FEATURE(sb,
|
||||
EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
|
||||
if (!ext4_has_metadata_csum(sb))
|
||||
return 1;
|
||||
|
||||
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)
|
||||
|
||||
static void ext4_mmp_csum_set(struct super_block *sb, struct mmp_struct *mmp)
|
||||
{
|
||||
if (!EXT4_HAS_RO_COMPAT_FEATURE(sb,
|
||||
EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
|
||||
if (!ext4_has_metadata_csum(sb))
|
||||
return;
|
||||
|
||||
mmp->mmp_checksum = ext4_mmp_csum(sb, mmp);
|
||||
|
||||
+122
-944
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user