Commit bc32a633 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull ext4 updates from Ted Ts'o:
 "The first two changes involve files outside of fs/ext4:

   - submit_bh() can never return an error, so change it to return void,
     and remove the unused checks from its callers

   - fix I_DIRTY_TIME handling so it will be set even if the inode
     already has I_DIRTY_INODE

  Performance:

   - Always enable i_version counter (as btrfs and xfs already do).
     Remove some uneeded i_version bumps to avoid unnecessary nfs cache
     invalidations

   - Wake up journal waiters in FIFO order, to avoid some journal users
     from not getting a journal handle for an unfairly long time

   - In ext4_write_begin() allocate any necessary buffer heads before
     starting the journal handle

   - Don't try to prefetch the block allocation bitmaps for a read-only
     file system

  Bug Fixes:

   - Fix a number of fast commit bugs, including resources leaks and out
     of bound references in various error handling paths and/or if the
     fast commit log is corrupted

   - Avoid stopping the online resize early when expanding a file system
     which is less than 16TiB to a size greater than 16TiB

   - Fix apparent metadata corruption caused by a race with a metadata
     buffer head getting migrated while it was trying to be read

   - Mark the lazy initialization thread freezable to prevent suspend
     failures

   - Other miscellaneous bug fixes

  Cleanups:

   - Break up the incredibly long ext4_full_super() function by
     refactoring to move code into more understandable, smaller
     functions

   - Remove the deprecated (and ignored) noacl and nouser_attr mount
     option

   - Factor out some common code in fast commit handling

   - Other miscellaneous cleanups"

* tag 'ext4_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4: (53 commits)
  ext4: fix potential out of bound read in ext4_fc_replay_scan()
  ext4: factor out ext4_fc_get_tl()
  ext4: introduce EXT4_FC_TAG_BASE_LEN helper
  ext4: factor out ext4_free_ext_path()
  ext4: remove unnecessary drop path references in mext_check_coverage()
  ext4: update 'state->fc_regions_size' after successful memory allocation
  ext4: fix potential memory leak in ext4_fc_record_regions()
  ext4: fix potential memory leak in ext4_fc_record_modified_inode()
  ext4: remove redundant checking in ext4_ioctl_checkpoint
  jbd2: add miss release buffer head in fc_do_one_pass()
  ext4: move DIOREAD_NOLOCK setting to ext4_set_def_opts()
  ext4: remove useless local variable 'blocksize'
  ext4: unify the ext4 super block loading operation
  ext4: factor out ext4_journal_data_mode_check()
  ext4: factor out ext4_load_and_init_journal()
  ext4: factor out ext4_group_desc_init() and ext4_group_desc_free()
  ext4: factor out ext4_geometry_check()
  ext4: factor out ext4_check_feature_compatibility()
  ext4: factor out ext4_init_metadata_csum()
  ext4: factor out ext4_encoding_init()
  ...
parents 7f198ba7 1b45cc5c
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -274,6 +274,9 @@ or bottom half).
	This is specifically for the inode itself being marked dirty,
	not its data.  If the update needs to be persisted by fdatasync(),
	then I_DIRTY_DATASYNC will be set in the flags argument.
	I_DIRTY_TIME will be set in the flags in case lazytime is enabled
	and struct inode has times updated since the last ->dirty_inode
	call.

``write_inode``
	this method is called when the VFS needs to write an inode to
+10 −13
Original line number Diff line number Diff line
@@ -52,7 +52,7 @@
#include "internal.h"

static int fsync_buffers_list(spinlock_t *lock, struct list_head *list);
static int submit_bh_wbc(blk_opf_t opf, struct buffer_head *bh,
static void submit_bh_wbc(blk_opf_t opf, struct buffer_head *bh,
			  struct writeback_control *wbc);

#define BH_ENTRY(list) list_entry((list), struct buffer_head, b_assoc_buffers)
@@ -2673,7 +2673,7 @@ static void end_bio_bh_io_sync(struct bio *bio)
	bio_put(bio);
}

static int submit_bh_wbc(blk_opf_t opf, struct buffer_head *bh,
static void submit_bh_wbc(blk_opf_t opf, struct buffer_head *bh,
			  struct writeback_control *wbc)
{
	const enum req_op op = opf & REQ_OP_MASK;
@@ -2717,12 +2717,11 @@ static int submit_bh_wbc(blk_opf_t opf, struct buffer_head *bh,
	}

	submit_bio(bio);
	return 0;
}

int submit_bh(blk_opf_t opf, struct buffer_head *bh)
void submit_bh(blk_opf_t opf, struct buffer_head *bh)
{
	return submit_bh_wbc(opf, bh, NULL);
	submit_bh_wbc(opf, bh, NULL);
}
EXPORT_SYMBOL(submit_bh);

@@ -2801,8 +2800,6 @@ EXPORT_SYMBOL(write_dirty_buffer);
 */
int __sync_dirty_buffer(struct buffer_head *bh, blk_opf_t op_flags)
{
	int ret = 0;

	WARN_ON(atomic_read(&bh->b_count) < 1);
	lock_buffer(bh);
	if (test_clear_buffer_dirty(bh)) {
@@ -2817,14 +2814,14 @@ int __sync_dirty_buffer(struct buffer_head *bh, blk_opf_t op_flags)

		get_bh(bh);
		bh->b_end_io = end_buffer_write_sync;
		ret = submit_bh(REQ_OP_WRITE | op_flags, bh);
		submit_bh(REQ_OP_WRITE | op_flags, bh);
		wait_on_buffer(bh);
		if (!ret && !buffer_uptodate(bh))
			ret = -EIO;
		if (!buffer_uptodate(bh))
			return -EIO;
	} else {
		unlock_buffer(bh);
	}
	return ret;
	return 0;
}
EXPORT_SYMBOL(__sync_dirty_buffer);

+1 −4
Original line number Diff line number Diff line
@@ -3592,9 +3592,6 @@ extern bool empty_inline_dir(struct inode *dir, int *has_inline_data);
extern struct buffer_head *ext4_get_first_inline_block(struct inode *inode,
					struct ext4_dir_entry_2 **parent_de,
					int *retval);
extern int ext4_inline_data_fiemap(struct inode *inode,
				   struct fiemap_extent_info *fieinfo,
				   int *has_inline, __u64 start, __u64 len);
extern void *ext4_read_inline_link(struct inode *inode);

struct iomap;
@@ -3713,7 +3710,7 @@ extern int ext4_ext_insert_extent(handle_t *, struct inode *,
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 void ext4_free_ext_path(struct ext4_ext_path *);
extern int ext4_ext_check_inode(struct inode *inode);
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,
+44 −63
Original line number Diff line number Diff line
@@ -106,6 +106,25 @@ static int ext4_ext_trunc_restart_fn(struct inode *inode, int *dropped)
	return 0;
}

static void ext4_ext_drop_refs(struct ext4_ext_path *path)
{
	int depth, i;

	if (!path)
		return;
	depth = path->p_depth;
	for (i = 0; i <= depth; i++, path++) {
		brelse(path->p_bh);
		path->p_bh = NULL;
	}
}

void ext4_free_ext_path(struct ext4_ext_path *path)
{
	ext4_ext_drop_refs(path);
	kfree(path);
}

/*
 * Make sure 'handle' has at least 'check_cred' credits. If not, restart
 * transaction with 'restart_cred' credits. The function drops i_data_sem
@@ -636,8 +655,7 @@ int ext4_ext_precache(struct inode *inode)
	ext4_set_inode_state(inode, EXT4_STATE_EXT_PRECACHED);
out:
	up_read(&ei->i_data_sem);
	ext4_ext_drop_refs(path);
	kfree(path);
	ext4_free_ext_path(path);
	return ret;
}

@@ -724,19 +742,6 @@ static void ext4_ext_show_move(struct inode *inode, struct ext4_ext_path *path,
#define ext4_ext_show_move(inode, path, newblock, level)
#endif

void ext4_ext_drop_refs(struct ext4_ext_path *path)
{
	int depth, i;

	if (!path)
		return;
	depth = path->p_depth;
	for (i = 0; i <= depth; i++, path++) {
		brelse(path->p_bh);
		path->p_bh = NULL;
	}
}

/*
 * ext4_ext_binsearch_idx:
 * binary search for the closest index of the given block
@@ -955,8 +960,7 @@ ext4_find_extent(struct inode *inode, ext4_lblk_t block,
	return path;

err:
	ext4_ext_drop_refs(path);
	kfree(path);
	ext4_free_ext_path(path);
	if (orig_path)
		*orig_path = NULL;
	return ERR_PTR(ret);
@@ -2174,8 +2178,7 @@ int ext4_ext_insert_extent(handle_t *handle, struct inode *inode,
	err = ext4_ext_dirty(handle, inode, path + path->p_depth);

cleanup:
	ext4_ext_drop_refs(npath);
	kfree(npath);
	ext4_free_ext_path(npath);
	return err;
}

@@ -3061,8 +3064,7 @@ int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start,
		}
	}
out:
	ext4_ext_drop_refs(path);
	kfree(path);
	ext4_free_ext_path(path);
	path = NULL;
	if (err == -EAGAIN)
		goto again;
@@ -4375,8 +4377,7 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
	allocated = map->m_len;
	ext4_ext_show_leaf(inode, path);
out:
	ext4_ext_drop_refs(path);
	kfree(path);
	ext4_free_ext_path(path);

	trace_ext4_ext_map_blocks_exit(inode, flags, map,
				       err ? err : allocated);
@@ -5245,8 +5246,7 @@ ext4_ext_shift_extents(struct inode *inode, handle_t *handle,
			break;
	}
out:
	ext4_ext_drop_refs(path);
	kfree(path);
	ext4_free_ext_path(path);
	return ret;
}

@@ -5538,15 +5538,13 @@ static int ext4_insert_range(struct file *file, loff_t offset, loff_t len)
					EXT4_GET_BLOCKS_METADATA_NOFAIL);
		}

		ext4_ext_drop_refs(path);
		kfree(path);
		ext4_free_ext_path(path);
		if (ret < 0) {
			up_write(&EXT4_I(inode)->i_data_sem);
			goto out_stop;
		}
	} else {
		ext4_ext_drop_refs(path);
		kfree(path);
		ext4_free_ext_path(path);
	}

	ret = ext4_es_remove_extent(inode, offset_lblk,
@@ -5766,10 +5764,8 @@ ext4_swap_extents(handle_t *handle, struct inode *inode1,
		count -= len;

	repeat:
		ext4_ext_drop_refs(path1);
		kfree(path1);
		ext4_ext_drop_refs(path2);
		kfree(path2);
		ext4_free_ext_path(path1);
		ext4_free_ext_path(path2);
		path1 = path2 = NULL;
	}
	return replaced_count;
@@ -5848,8 +5844,7 @@ int ext4_clu_mapped(struct inode *inode, ext4_lblk_t lclu)
	}

out:
	ext4_ext_drop_refs(path);
	kfree(path);
	ext4_free_ext_path(path);

	return err ? err : mapped;
}
@@ -5916,8 +5911,7 @@ int ext4_ext_replay_update_ex(struct inode *inode, ext4_lblk_t start,
	ret = ext4_ext_dirty(NULL, inode, &path[path->p_depth]);
	up_write(&EXT4_I(inode)->i_data_sem);
out:
	ext4_ext_drop_refs(path);
	kfree(path);
	ext4_free_ext_path(path);
	ext4_mark_inode_dirty(NULL, inode);
	return ret;
}
@@ -5935,8 +5929,7 @@ void ext4_ext_replay_shrink_inode(struct inode *inode, ext4_lblk_t end)
			return;
		ex = path[path->p_depth].p_ext;
		if (!ex) {
			ext4_ext_drop_refs(path);
			kfree(path);
			ext4_free_ext_path(path);
			ext4_mark_inode_dirty(NULL, inode);
			return;
		}
@@ -5949,8 +5942,7 @@ void ext4_ext_replay_shrink_inode(struct inode *inode, ext4_lblk_t end)
		ext4_ext_dirty(NULL, inode, &path[path->p_depth]);
		up_write(&EXT4_I(inode)->i_data_sem);
		ext4_mark_inode_dirty(NULL, inode);
		ext4_ext_drop_refs(path);
		kfree(path);
		ext4_free_ext_path(path);
	}
}

@@ -5989,13 +5981,11 @@ int ext4_ext_replay_set_iblocks(struct inode *inode)
		return PTR_ERR(path);
	ex = path[path->p_depth].p_ext;
	if (!ex) {
		ext4_ext_drop_refs(path);
		kfree(path);
		ext4_free_ext_path(path);
		goto out;
	}
	end = le32_to_cpu(ex->ee_block) + ext4_ext_get_actual_len(ex);
	ext4_ext_drop_refs(path);
	kfree(path);
	ext4_free_ext_path(path);

	/* Count the number of data blocks */
	cur = 0;
@@ -6025,30 +6015,26 @@ int ext4_ext_replay_set_iblocks(struct inode *inode)
	if (IS_ERR(path))
		goto out;
	numblks += path->p_depth;
	ext4_ext_drop_refs(path);
	kfree(path);
	ext4_free_ext_path(path);
	while (cur < end) {
		path = ext4_find_extent(inode, cur, NULL, 0);
		if (IS_ERR(path))
			break;
		ex = path[path->p_depth].p_ext;
		if (!ex) {
			ext4_ext_drop_refs(path);
			kfree(path);
			ext4_free_ext_path(path);
			return 0;
		}
		cur = max(cur + 1, le32_to_cpu(ex->ee_block) +
					ext4_ext_get_actual_len(ex));
		ret = skip_hole(inode, &cur);
		if (ret < 0) {
			ext4_ext_drop_refs(path);
			kfree(path);
			ext4_free_ext_path(path);
			break;
		}
		path2 = ext4_find_extent(inode, cur, NULL, 0);
		if (IS_ERR(path2)) {
			ext4_ext_drop_refs(path);
			kfree(path);
			ext4_free_ext_path(path);
			break;
		}
		for (i = 0; i <= max(path->p_depth, path2->p_depth); i++) {
@@ -6062,10 +6048,8 @@ int ext4_ext_replay_set_iblocks(struct inode *inode)
			if (cmp1 != cmp2 && cmp2 != 0)
				numblks++;
		}
		ext4_ext_drop_refs(path);
		ext4_ext_drop_refs(path2);
		kfree(path);
		kfree(path2);
		ext4_free_ext_path(path);
		ext4_free_ext_path(path2);
	}

out:
@@ -6092,13 +6076,11 @@ int ext4_ext_clear_bb(struct inode *inode)
		return PTR_ERR(path);
	ex = path[path->p_depth].p_ext;
	if (!ex) {
		ext4_ext_drop_refs(path);
		kfree(path);
		ext4_free_ext_path(path);
		return 0;
	}
	end = le32_to_cpu(ex->ee_block) + ext4_ext_get_actual_len(ex);
	ext4_ext_drop_refs(path);
	kfree(path);
	ext4_free_ext_path(path);

	cur = 0;
	while (cur < end) {
@@ -6117,8 +6099,7 @@ int ext4_ext_clear_bb(struct inode *inode)
					ext4_fc_record_regions(inode->i_sb, inode->i_ino,
							0, path[j].p_block, 1, 1);
				}
				ext4_ext_drop_refs(path);
				kfree(path);
				ext4_free_ext_path(path);
			}
			ext4_mb_mark_bb(inode->i_sb, map.m_pblk, map.m_len, 0);
			ext4_fc_record_regions(inode->i_sb, inode->i_ino,
+1 −2
Original line number Diff line number Diff line
@@ -667,8 +667,7 @@ static void ext4_es_insert_extent_ext_check(struct inode *inode,
		}
	}
out:
	ext4_ext_drop_refs(path);
	kfree(path);
	ext4_free_ext_path(path);
}

static void ext4_es_insert_extent_ind_check(struct inode *inode,
Loading