Commit 2e756758 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull ext4 updates from Ted Ts'o:
 "Many bug fixes and cleanups, and an optimization for case-insensitive
  lookups"

* tag 'ext4_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4:
  ext4: fix coverity warning on error path of filename setup
  ext4: replace ktype default_attrs with default_groups
  ext4: rename htree_inline_dir_to_tree() to ext4_inlinedir_to_tree()
  ext4: refactor initialize_dirent_tail()
  ext4: rename "dirent_csum" functions to use "dirblock"
  ext4: allow directory holes
  jbd2: drop declaration of journal_sync_buffer()
  ext4: use jbd2_inode dirty range scoping
  jbd2: introduce jbd2_inode dirty range scoping
  mm: add filemap_fdatawait_range_keep_errors()
  ext4: remove redundant assignment to node
  ext4: optimize case-insensitive lookups
  ext4: make __ext4_get_inode_loc plug
  ext4: clean up kerneldoc warnigns when building with W=1
  ext4: only set project inherit bit for directory
  ext4: enforce the immutable flag on open files
  ext4: don't allow any modifications to an immutable file
  jbd2: fix typo in comment of journal_submit_inode_data_buffers
  jbd2: fix some print format mistakes
  ext4: gracefully handle ext4_break_layouts() failure during truncate
parents 8dda9957 96fcaf86
Loading
Loading
Loading
Loading
+2 −2
Original line number Original line Diff line number Diff line
@@ -603,9 +603,9 @@ int ext4_claim_free_clusters(struct ext4_sb_info *sbi,
}
}


/**
/**
 * ext4_should_retry_alloc()
 * ext4_should_retry_alloc() - check if a block allocation should be retried
 * @sb:			super block
 * @sb:			super block
 * @retries		number of attemps has been made
 * @retries:		number of attemps has been made
 *
 *
 * ext4_should_retry_alloc() is called when ENOSPC is returned, and if
 * ext4_should_retry_alloc() is called when ENOSPC is returned, and if
 * it is profitable to retry the operation, this function will wait
 * it is profitable to retry the operation, this function will wait
+14 −13
Original line number Original line Diff line number Diff line
@@ -33,6 +33,9 @@
static int ext4_dx_readdir(struct file *, struct dir_context *);
static int ext4_dx_readdir(struct file *, struct dir_context *);


/**
/**
 * is_dx_dir() - check if a directory is using htree indexing
 * @inode: directory inode
 *
 * Check if the given dir-inode refers to an htree-indexed directory
 * Check if the given dir-inode refers to an htree-indexed directory
 * (or a directory which could potentially get converted to use htree
 * (or a directory which could potentially get converted to use htree
 * indexing).
 * indexing).
@@ -109,7 +112,6 @@ static int ext4_readdir(struct file *file, struct dir_context *ctx)
	struct inode *inode = file_inode(file);
	struct inode *inode = file_inode(file);
	struct super_block *sb = inode->i_sb;
	struct super_block *sb = inode->i_sb;
	struct buffer_head *bh = NULL;
	struct buffer_head *bh = NULL;
	int dir_has_error = 0;
	struct fscrypt_str fstr = FSTR_INIT(NULL, 0);
	struct fscrypt_str fstr = FSTR_INIT(NULL, 0);


	if (IS_ENCRYPTED(inode)) {
	if (IS_ENCRYPTED(inode)) {
@@ -145,8 +147,6 @@ static int ext4_readdir(struct file *file, struct dir_context *ctx)
			return err;
			return err;
	}
	}


	offset = ctx->pos & (sb->s_blocksize - 1);

	while (ctx->pos < inode->i_size) {
	while (ctx->pos < inode->i_size) {
		struct ext4_map_blocks map;
		struct ext4_map_blocks map;


@@ -155,9 +155,18 @@ static int ext4_readdir(struct file *file, struct dir_context *ctx)
			goto errout;
			goto errout;
		}
		}
		cond_resched();
		cond_resched();
		offset = ctx->pos & (sb->s_blocksize - 1);
		map.m_lblk = ctx->pos >> EXT4_BLOCK_SIZE_BITS(sb);
		map.m_lblk = ctx->pos >> EXT4_BLOCK_SIZE_BITS(sb);
		map.m_len = 1;
		map.m_len = 1;
		err = ext4_map_blocks(NULL, inode, &map, 0);
		err = ext4_map_blocks(NULL, inode, &map, 0);
		if (err == 0) {
			/* m_len should never be zero but let's avoid
			 * an infinite loop if it somehow is */
			if (map.m_len == 0)
				map.m_len = 1;
			ctx->pos += map.m_len * sb->s_blocksize;
			continue;
		}
		if (err > 0) {
		if (err > 0) {
			pgoff_t index = map.m_pblk >>
			pgoff_t index = map.m_pblk >>
					(PAGE_SHIFT - inode->i_blkbits);
					(PAGE_SHIFT - inode->i_blkbits);
@@ -176,13 +185,6 @@ static int ext4_readdir(struct file *file, struct dir_context *ctx)
		}
		}


		if (!bh) {
		if (!bh) {
			if (!dir_has_error) {
				EXT4_ERROR_FILE(file, 0,
						"directory contains a "
						"hole at offset %llu",
					   (unsigned long long) ctx->pos);
				dir_has_error = 1;
			}
			/* corrupt size?  Maybe no more blocks to read */
			/* corrupt size?  Maybe no more blocks to read */
			if (ctx->pos > inode->i_blocks << 9)
			if (ctx->pos > inode->i_blocks << 9)
				break;
				break;
@@ -192,8 +194,7 @@ static int ext4_readdir(struct file *file, struct dir_context *ctx)


		/* Check the checksum */
		/* Check the checksum */
		if (!buffer_verified(bh) &&
		if (!buffer_verified(bh) &&
		    !ext4_dirent_csum_verify(inode,
		    !ext4_dirblock_csum_verify(inode, bh)) {
				(struct ext4_dir_entry *)bh->b_data)) {
			EXT4_ERROR_FILE(file, 0, "directory fails checksum "
			EXT4_ERROR_FILE(file, 0, "directory fails checksum "
					"at offset %llu",
					"at offset %llu",
					(unsigned long long)ctx->pos);
					(unsigned long long)ctx->pos);
@@ -674,7 +675,7 @@ static int ext4_d_compare(const struct dentry *dentry, unsigned int len,
		return memcmp(str, name->name, len);
		return memcmp(str, name->name, len);
	}
	}


	return ext4_ci_compare(dentry->d_parent->d_inode, name, &qstr);
	return ext4_ci_compare(dentry->d_parent->d_inode, name, &qstr, false);
}
}


static int ext4_d_hash(const struct dentry *dentry, struct qstr *str)
static int ext4_d_hash(const struct dentry *dentry, struct qstr *str)
+49 −16
Original line number Original line Diff line number Diff line
@@ -421,7 +421,8 @@ struct flex_groups {
			   EXT4_PROJINHERIT_FL | EXT4_CASEFOLD_FL)
			   EXT4_PROJINHERIT_FL | EXT4_CASEFOLD_FL)


/* Flags that are appropriate for regular files (all but dir-specific ones). */
/* Flags that are appropriate for regular files (all but dir-specific ones). */
#define EXT4_REG_FLMASK (~(EXT4_DIRSYNC_FL | EXT4_TOPDIR_FL | EXT4_CASEFOLD_FL))
#define EXT4_REG_FLMASK (~(EXT4_DIRSYNC_FL | EXT4_TOPDIR_FL | EXT4_CASEFOLD_FL |\
			   EXT4_PROJINHERIT_FL))


/* Flags that are appropriate for non-directories/regular files. */
/* Flags that are appropriate for non-directories/regular files. */
#define EXT4_OTHER_FLMASK (EXT4_NODUMP_FL | EXT4_NOATIME_FL)
#define EXT4_OTHER_FLMASK (EXT4_NODUMP_FL | EXT4_NOATIME_FL)
@@ -2077,6 +2078,9 @@ struct ext4_filename {
#ifdef CONFIG_FS_ENCRYPTION
#ifdef CONFIG_FS_ENCRYPTION
	struct fscrypt_str crypto_buf;
	struct fscrypt_str crypto_buf;
#endif
#endif
#ifdef CONFIG_UNICODE
	struct fscrypt_str cf_name;
#endif
};
};


#define fname_name(p) ((p)->disk_name.name)
#define fname_name(p) ((p)->disk_name.name)
@@ -2302,6 +2306,12 @@ extern unsigned ext4_free_clusters_after_init(struct super_block *sb,
					      struct ext4_group_desc *gdp);
					      struct ext4_group_desc *gdp);
ext4_fsblk_t ext4_inode_to_goal_block(struct inode *);
ext4_fsblk_t ext4_inode_to_goal_block(struct inode *);


#ifdef CONFIG_UNICODE
extern void ext4_fname_setup_ci_filename(struct inode *dir,
					 const struct qstr *iname,
					 struct fscrypt_str *fname);
#endif

#ifdef CONFIG_FS_ENCRYPTION
#ifdef CONFIG_FS_ENCRYPTION
static inline void ext4_fname_from_fscrypt_name(struct ext4_filename *dst,
static inline void ext4_fname_from_fscrypt_name(struct ext4_filename *dst,
						const struct fscrypt_name *src)
						const struct fscrypt_name *src)
@@ -2328,6 +2338,10 @@ static inline int ext4_fname_setup_filename(struct inode *dir,
		return err;
		return err;


	ext4_fname_from_fscrypt_name(fname, &name);
	ext4_fname_from_fscrypt_name(fname, &name);

#ifdef CONFIG_UNICODE
	ext4_fname_setup_ci_filename(dir, iname, &fname->cf_name);
#endif
	return 0;
	return 0;
}
}


@@ -2343,6 +2357,10 @@ static inline int ext4_fname_prepare_lookup(struct inode *dir,
		return err;
		return err;


	ext4_fname_from_fscrypt_name(fname, &name);
	ext4_fname_from_fscrypt_name(fname, &name);

#ifdef CONFIG_UNICODE
	ext4_fname_setup_ci_filename(dir, &dentry->d_name, &fname->cf_name);
#endif
	return 0;
	return 0;
}
}


@@ -2356,6 +2374,11 @@ static inline void ext4_fname_free_filename(struct ext4_filename *fname)
	fname->crypto_buf.name = NULL;
	fname->crypto_buf.name = NULL;
	fname->usr_fname = NULL;
	fname->usr_fname = NULL;
	fname->disk_name.name = NULL;
	fname->disk_name.name = NULL;

#ifdef CONFIG_UNICODE
	kfree(fname->cf_name.name);
	fname->cf_name.name = NULL;
#endif
}
}
#else /* !CONFIG_FS_ENCRYPTION */
#else /* !CONFIG_FS_ENCRYPTION */
static inline int ext4_fname_setup_filename(struct inode *dir,
static inline int ext4_fname_setup_filename(struct inode *dir,
@@ -2366,6 +2389,11 @@ static inline int ext4_fname_setup_filename(struct inode *dir,
	fname->usr_fname = iname;
	fname->usr_fname = iname;
	fname->disk_name.name = (unsigned char *) iname->name;
	fname->disk_name.name = (unsigned char *) iname->name;
	fname->disk_name.len = iname->len;
	fname->disk_name.len = iname->len;

#ifdef CONFIG_UNICODE
	ext4_fname_setup_ci_filename(dir, iname, &fname->cf_name);
#endif

	return 0;
	return 0;
}
}


@@ -2376,7 +2404,13 @@ static inline int ext4_fname_prepare_lookup(struct inode *dir,
	return ext4_fname_setup_filename(dir, &dentry->d_name, 1, fname);
	return ext4_fname_setup_filename(dir, &dentry->d_name, 1, fname);
}
}


static inline void ext4_fname_free_filename(struct ext4_filename *fname) { }
static inline void ext4_fname_free_filename(struct ext4_filename *fname)
{
#ifdef CONFIG_UNICODE
	kfree(fname->cf_name.name);
	fname->cf_name.name = NULL;
#endif
}
#endif /* !CONFIG_FS_ENCRYPTION */
#endif /* !CONFIG_FS_ENCRYPTION */


/* dir.c */
/* dir.c */
@@ -2568,8 +2602,8 @@ extern int ext4_ext_migrate(struct inode *);
extern int ext4_ind_migrate(struct inode *inode);
extern int ext4_ind_migrate(struct inode *inode);


/* namei.c */
/* namei.c */
extern int ext4_dirent_csum_verify(struct inode *inode,
extern int ext4_dirblock_csum_verify(struct inode *inode,
				   struct ext4_dir_entry *dirent);
				     struct buffer_head *bh);
extern int ext4_orphan_add(handle_t *, struct inode *);
extern int ext4_orphan_add(handle_t *, struct inode *);
extern int ext4_orphan_del(handle_t *, struct inode *);
extern int ext4_orphan_del(handle_t *, struct inode *);
extern int ext4_htree_fill_tree(struct file *dir_file, __u32 start_hash,
extern int ext4_htree_fill_tree(struct file *dir_file, __u32 start_hash,
@@ -3070,7 +3104,7 @@ extern int ext4_try_create_inline_dir(handle_t *handle,
extern int ext4_read_inline_dir(struct file *filp,
extern int ext4_read_inline_dir(struct file *filp,
				struct dir_context *ctx,
				struct dir_context *ctx,
				int *has_inline_data);
				int *has_inline_data);
extern int htree_inlinedir_to_tree(struct file *dir_file,
extern int ext4_inlinedir_to_tree(struct file *dir_file,
				  struct inode *dir, ext4_lblk_t block,
				  struct inode *dir, ext4_lblk_t block,
				  struct dx_hash_info *hinfo,
				  struct dx_hash_info *hinfo,
				  __u32 start_hash, __u32 start_minor_hash,
				  __u32 start_hash, __u32 start_minor_hash,
@@ -3113,14 +3147,13 @@ extern struct ext4_dir_entry_2 *ext4_init_dot_dotdot(struct inode *inode,
				 struct ext4_dir_entry_2 *de,
				 struct ext4_dir_entry_2 *de,
				 int blocksize, int csum_size,
				 int blocksize, int csum_size,
				 unsigned int parent_ino, int dotdot_real_len);
				 unsigned int parent_ino, int dotdot_real_len);
extern void initialize_dirent_tail(struct ext4_dir_entry_tail *t,
extern void ext4_initialize_dirent_tail(struct buffer_head *bh,
					unsigned int blocksize);
					unsigned int blocksize);
extern int ext4_handle_dirty_dirent_node(handle_t *handle,
extern int ext4_handle_dirty_dirblock(handle_t *handle, struct inode *inode,
					 struct inode *inode,
				      struct buffer_head *bh);
				      struct buffer_head *bh);
extern int ext4_ci_compare(const struct inode *parent,
extern int ext4_ci_compare(const struct inode *parent,
			   const struct qstr *name,
			   const struct qstr *fname,
			   const struct qstr *entry);
			   const struct qstr *entry, bool quick);


#define S_SHIFT 12
#define S_SHIFT 12
static const unsigned char ext4_type_by_mode[(S_IFMT >> S_SHIFT) + 1] = {
static const unsigned char ext4_type_by_mode[(S_IFMT >> S_SHIFT) + 1] = {
+6 −6
Original line number Original line Diff line number Diff line
@@ -361,20 +361,20 @@ static inline int ext4_journal_force_commit(journal_t *journal)
}
}


static inline int ext4_jbd2_inode_add_write(handle_t *handle,
static inline int ext4_jbd2_inode_add_write(handle_t *handle,
					    struct inode *inode)
		struct inode *inode, loff_t start_byte, loff_t length)
{
{
	if (ext4_handle_valid(handle))
	if (ext4_handle_valid(handle))
		return jbd2_journal_inode_add_write(handle,
		return jbd2_journal_inode_ranged_write(handle,
						    EXT4_I(inode)->jinode);
				EXT4_I(inode)->jinode, start_byte, length);
	return 0;
	return 0;
}
}


static inline int ext4_jbd2_inode_add_wait(handle_t *handle,
static inline int ext4_jbd2_inode_add_wait(handle_t *handle,
					   struct inode *inode)
		struct inode *inode, loff_t start_byte, loff_t length)
{
{
	if (ext4_handle_valid(handle))
	if (ext4_handle_valid(handle))
		return jbd2_journal_inode_add_wait(handle,
		return jbd2_journal_inode_ranged_wait(handle,
						   EXT4_I(inode)->jinode);
				EXT4_I(inode)->jinode, start_byte, length);
	return 0;
	return 0;
}
}


+2 −2
Original line number Original line Diff line number Diff line
@@ -5676,8 +5676,8 @@ out_mutex:
}
}


/**
/**
 * ext4_swap_extents - Swap extents between two inodes
 * ext4_swap_extents() - Swap extents between two inodes
 *
 * @handle: handle for this transaction
 * @inode1:	First inode
 * @inode1:	First inode
 * @inode2:	Second inode
 * @inode2:	Second inode
 * @lblk1:	Start block for first inode
 * @lblk1:	Start block for first inode
Loading