Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4edebed8 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull Ext4 updates from Theodore Ts'o:
 "The major new feature added in this update is Darrick J Wong's
  metadata checksum feature, which adds crc32 checksums to ext4's
  metadata fields.

  There is also the usual set of cleanups and bug fixes."

* tag 'ext4_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4: (44 commits)
  ext4: hole-punch use truncate_pagecache_range
  jbd2: use kmem_cache_zalloc wrapper instead of flag
  ext4: remove mb_groups before tearing down the buddy_cache
  ext4: add ext4_mb_unload_buddy in the error path
  ext4: don't trash state flags in EXT4_IOC_SETFLAGS
  ext4: let getattr report the right blocks in delalloc+bigalloc
  ext4: add missing save_error_info() to ext4_error()
  ext4: add debugging trigger for ext4_error()
  ext4: protect group inode free counting with group lock
  ext4: use consistent ssize_t type in ext4_file_write()
  ext4: fix format flag in ext4_ext_binsearch_idx()
  ext4: cleanup in ext4_discard_allocated_blocks()
  ext4: return ENOMEM when mounts fail due to lack of memory
  ext4: remove redundundant "(char *) bh->b_data" casts
  ext4: disallow hard-linked directory in ext4_lookup
  ext4: fix potential integer overflow in alloc_flex_gd()
  ext4: remove needs_recovery in ext4_mb_init()
  ext4: force ro mount if ext4_setup_super() fails
  ext4: fix potential NULL dereference in ext4_free_inodes_counts()
  ext4/jbd2: add metadata checksumming to the list of supported features
  ...
parents 51eab603 5e44f8c3
Loading
Loading
Loading
Loading
+2 −0
Original line number Original line Diff line number Diff line
@@ -2,6 +2,8 @@ config EXT4_FS
	tristate "The Extended 4 (ext4) filesystem"
	tristate "The Extended 4 (ext4) filesystem"
	select JBD2
	select JBD2
	select CRC16
	select CRC16
	select CRYPTO
	select CRYPTO_CRC32C
	help
	help
	  This is the next generation of the ext3 filesystem.
	  This is the next generation of the ext3 filesystem.


+33 −8
Original line number Original line Diff line number Diff line
@@ -168,12 +168,14 @@ void ext4_init_block_bitmap(struct super_block *sb, struct buffer_head *bh,


	/* 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(sbi, block_group, gdp)) {
	if (!ext4_group_desc_csum_verify(sb, block_group, gdp)) {
		ext4_error(sb, "Checksum bad for group %u", block_group);
		ext4_error(sb, "Checksum bad for group %u", block_group);
		ext4_free_group_clusters_set(sb, gdp, 0);
		ext4_free_group_clusters_set(sb, gdp, 0);
		ext4_free_inodes_set(sb, gdp, 0);
		ext4_free_inodes_set(sb, gdp, 0);
		ext4_itable_unused_set(sb, gdp, 0);
		ext4_itable_unused_set(sb, gdp, 0);
		memset(bh->b_data, 0xff, sb->s_blocksize);
		memset(bh->b_data, 0xff, sb->s_blocksize);
		ext4_block_bitmap_csum_set(sb, block_group, gdp, bh,
					   EXT4_BLOCKS_PER_GROUP(sb) / 8);
		return;
		return;
	}
	}
	memset(bh->b_data, 0, sb->s_blocksize);
	memset(bh->b_data, 0, sb->s_blocksize);
@@ -210,6 +212,9 @@ void ext4_init_block_bitmap(struct super_block *sb, struct buffer_head *bh,
	 */
	 */
	ext4_mark_bitmap_end(num_clusters_in_group(sb, block_group),
	ext4_mark_bitmap_end(num_clusters_in_group(sb, block_group),
			     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_BLOCKS_PER_GROUP(sb) / 8);
	ext4_group_desc_csum_set(sb, block_group, gdp);
}
}


/* 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
@@ -325,6 +330,23 @@ static int ext4_valid_block_bitmap(struct super_block *sb,
			block_group, bitmap_blk);
			block_group, bitmap_blk);
	return 0;
	return 0;
}
}

void ext4_validate_block_bitmap(struct super_block *sb,
			       struct ext4_group_desc *desc,
			       unsigned int block_group,
			       struct buffer_head *bh)
{
	if (buffer_verified(bh))
		return;

	ext4_lock_group(sb, block_group);
	if (ext4_valid_block_bitmap(sb, desc, block_group, bh) &&
	    ext4_block_bitmap_csum_verify(sb, block_group, desc, bh,
					  EXT4_BLOCKS_PER_GROUP(sb) / 8))
		set_buffer_verified(bh);
	ext4_unlock_group(sb, block_group);
}

/**
/**
 * ext4_read_block_bitmap()
 * ext4_read_block_bitmap()
 * @sb:			super block
 * @sb:			super block
@@ -355,12 +377,12 @@ ext4_read_block_bitmap_nowait(struct super_block *sb, ext4_group_t block_group)
	}
	}


	if (bitmap_uptodate(bh))
	if (bitmap_uptodate(bh))
		return bh;
		goto verify;


	lock_buffer(bh);
	lock_buffer(bh);
	if (bitmap_uptodate(bh)) {
	if (bitmap_uptodate(bh)) {
		unlock_buffer(bh);
		unlock_buffer(bh);
		return bh;
		goto verify;
	}
	}
	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)) {
@@ -379,7 +401,7 @@ ext4_read_block_bitmap_nowait(struct super_block *sb, ext4_group_t block_group)
		 */
		 */
		set_bitmap_uptodate(bh);
		set_bitmap_uptodate(bh);
		unlock_buffer(bh);
		unlock_buffer(bh);
		return bh;
		goto verify;
	}
	}
	/*
	/*
	 * submit the buffer_head for reading
	 * submit the buffer_head for reading
@@ -390,6 +412,9 @@ ext4_read_block_bitmap_nowait(struct super_block *sb, ext4_group_t block_group)
	get_bh(bh);
	get_bh(bh);
	submit_bh(READ, bh);
	submit_bh(READ, bh);
	return bh;
	return bh;
verify:
	ext4_validate_block_bitmap(sb, desc, block_group, bh);
	return bh;
}
}


/* Returns 0 on success, 1 on error */
/* Returns 0 on success, 1 on error */
@@ -412,7 +437,7 @@ int ext4_wait_block_bitmap(struct super_block *sb, ext4_group_t block_group,
	}
	}
	clear_buffer_new(bh);
	clear_buffer_new(bh);
	/* Panic or remount fs read-only if block bitmap is invalid */
	/* Panic or remount fs read-only if block bitmap is invalid */
	ext4_valid_block_bitmap(sb, desc, block_group, bh);
	ext4_validate_block_bitmap(sb, desc, block_group, bh);
	return 0;
	return 0;
}
}


+83 −0
Original line number Original line Diff line number Diff line
@@ -29,3 +29,86 @@ unsigned int ext4_count_free(struct buffer_head *map, unsigned int numchars)


#endif  /*  EXT4FS_DEBUG  */
#endif  /*  EXT4FS_DEBUG  */


int ext4_inode_bitmap_csum_verify(struct super_block *sb, ext4_group_t group,
				  struct ext4_group_desc *gdp,
				  struct buffer_head *bh, int sz)
{
	__u32 hi;
	__u32 provided, calculated;
	struct ext4_sb_info *sbi = EXT4_SB(sb);

	if (!EXT4_HAS_RO_COMPAT_FEATURE(sb,
					EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
		return 1;

	provided = le16_to_cpu(gdp->bg_inode_bitmap_csum_lo);
	calculated = ext4_chksum(sbi, sbi->s_csum_seed, (__u8 *)bh->b_data, sz);
	if (sbi->s_desc_size >= EXT4_BG_INODE_BITMAP_CSUM_HI_END) {
		hi = le16_to_cpu(gdp->bg_inode_bitmap_csum_hi);
		provided |= (hi << 16);
	} else
		calculated &= 0xFFFF;

	return provided == calculated;
}

void ext4_inode_bitmap_csum_set(struct super_block *sb, ext4_group_t group,
				struct ext4_group_desc *gdp,
				struct buffer_head *bh, int sz)
{
	__u32 csum;
	struct ext4_sb_info *sbi = EXT4_SB(sb);

	if (!EXT4_HAS_RO_COMPAT_FEATURE(sb,
					EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
		return;

	csum = ext4_chksum(sbi, sbi->s_csum_seed, (__u8 *)bh->b_data, sz);
	gdp->bg_inode_bitmap_csum_lo = cpu_to_le16(csum & 0xFFFF);
	if (sbi->s_desc_size >= EXT4_BG_INODE_BITMAP_CSUM_HI_END)
		gdp->bg_inode_bitmap_csum_hi = cpu_to_le16(csum >> 16);
}

int ext4_block_bitmap_csum_verify(struct super_block *sb, ext4_group_t group,
				  struct ext4_group_desc *gdp,
				  struct buffer_head *bh, int sz)
{
	__u32 hi;
	__u32 provided, calculated;
	struct ext4_sb_info *sbi = EXT4_SB(sb);

	if (!EXT4_HAS_RO_COMPAT_FEATURE(sb,
					EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
		return 1;

	provided = le16_to_cpu(gdp->bg_block_bitmap_csum_lo);
	calculated = ext4_chksum(sbi, sbi->s_csum_seed, (__u8 *)bh->b_data, sz);
	if (sbi->s_desc_size >= EXT4_BG_BLOCK_BITMAP_CSUM_HI_END) {
		hi = le16_to_cpu(gdp->bg_block_bitmap_csum_hi);
		provided |= (hi << 16);
	} else
		calculated &= 0xFFFF;

	if (provided == calculated)
		return 1;

	ext4_error(sb, "Bad block bitmap checksum: block_group = %u", group);
	return 0;
}

void ext4_block_bitmap_csum_set(struct super_block *sb, ext4_group_t group,
				struct ext4_group_desc *gdp,
				struct buffer_head *bh, int sz)
{
	__u32 csum;
	struct ext4_sb_info *sbi = EXT4_SB(sb);

	if (!EXT4_HAS_RO_COMPAT_FEATURE(sb,
			EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
		return;

	csum = ext4_chksum(sbi, sbi->s_csum_seed, (__u8 *)bh->b_data, sz);
	gdp->bg_block_bitmap_csum_lo = cpu_to_le16(csum & 0xFFFF);
	if (sbi->s_desc_size >= EXT4_BG_BLOCK_BITMAP_CSUM_HI_END)
		gdp->bg_block_bitmap_csum_hi = cpu_to_le16(csum >> 16);
}
+12 −0
Original line number Original line Diff line number Diff line
@@ -179,6 +179,18 @@ static int ext4_readdir(struct file *filp,
			continue;
			continue;
		}
		}


		/* Check the checksum */
		if (!buffer_verified(bh) &&
		    !ext4_dirent_csum_verify(inode,
				(struct ext4_dir_entry *)bh->b_data)) {
			EXT4_ERROR_FILE(filp, 0, "directory fails checksum "
					"at offset %llu",
					(unsigned long long)filp->f_pos);
			filp->f_pos += sb->s_blocksize - offset;
			continue;
		}
		set_buffer_verified(bh);

revalidate:
revalidate:
		/* If the dir block has changed since the last call to
		/* If the dir block has changed since the last call to
		 * readdir(2), then we might be pointing to an invalid
		 * readdir(2), then we might be pointing to an invalid
+117 −13
Original line number Original line Diff line number Diff line
@@ -29,6 +29,7 @@
#include <linux/wait.h>
#include <linux/wait.h>
#include <linux/blockgroup_lock.h>
#include <linux/blockgroup_lock.h>
#include <linux/percpu_counter.h>
#include <linux/percpu_counter.h>
#include <crypto/hash.h>
#ifdef __KERNEL__
#ifdef __KERNEL__
#include <linux/compat.h>
#include <linux/compat.h>
#endif
#endif
@@ -298,7 +299,9 @@ struct ext4_group_desc
	__le16	bg_free_inodes_count_lo;/* Free inodes count */
	__le16	bg_free_inodes_count_lo;/* Free inodes count */
	__le16	bg_used_dirs_count_lo;	/* Directories count */
	__le16	bg_used_dirs_count_lo;	/* Directories count */
	__le16	bg_flags;		/* EXT4_BG_flags (INODE_UNINIT, etc) */
	__le16	bg_flags;		/* EXT4_BG_flags (INODE_UNINIT, etc) */
	__u32	bg_reserved[2];		/* Likely block/inode bitmap checksum */
	__le32  bg_exclude_bitmap_lo;   /* Exclude bitmap for snapshots */
	__le16  bg_block_bitmap_csum_lo;/* crc32c(s_uuid+grp_num+bbitmap) LE */
	__le16  bg_inode_bitmap_csum_lo;/* crc32c(s_uuid+grp_num+ibitmap) LE */
	__le16  bg_itable_unused_lo;	/* Unused inodes count */
	__le16  bg_itable_unused_lo;	/* Unused inodes count */
	__le16  bg_checksum;		/* crc16(sb_uuid+group+desc) */
	__le16  bg_checksum;		/* crc16(sb_uuid+group+desc) */
	__le32	bg_block_bitmap_hi;	/* Blocks bitmap block MSB */
	__le32	bg_block_bitmap_hi;	/* Blocks bitmap block MSB */
@@ -308,9 +311,19 @@ struct ext4_group_desc
	__le16	bg_free_inodes_count_hi;/* Free inodes count MSB */
	__le16	bg_free_inodes_count_hi;/* Free inodes count MSB */
	__le16	bg_used_dirs_count_hi;	/* Directories count MSB */
	__le16	bg_used_dirs_count_hi;	/* Directories count MSB */
	__le16  bg_itable_unused_hi;    /* Unused inodes count MSB */
	__le16  bg_itable_unused_hi;    /* Unused inodes count MSB */
	__u32	bg_reserved2[3];
	__le32  bg_exclude_bitmap_hi;   /* Exclude bitmap block MSB */
	__le16  bg_block_bitmap_csum_hi;/* crc32c(s_uuid+grp_num+bbitmap) BE */
	__le16  bg_inode_bitmap_csum_hi;/* crc32c(s_uuid+grp_num+ibitmap) BE */
	__u32   bg_reserved;
};
};


#define EXT4_BG_INODE_BITMAP_CSUM_HI_END	\
	(offsetof(struct ext4_group_desc, bg_inode_bitmap_csum_hi) + \
	 sizeof(__le16))
#define EXT4_BG_BLOCK_BITMAP_CSUM_HI_END	\
	(offsetof(struct ext4_group_desc, bg_block_bitmap_csum_hi) + \
	 sizeof(__le16))

/*
/*
 * Structure of a flex block group info
 * Structure of a flex block group info
 */
 */
@@ -650,7 +663,8 @@ struct ext4_inode {
			__le16	l_i_file_acl_high;
			__le16	l_i_file_acl_high;
			__le16	l_i_uid_high;	/* these 2 fields */
			__le16	l_i_uid_high;	/* these 2 fields */
			__le16	l_i_gid_high;	/* were reserved2[0] */
			__le16	l_i_gid_high;	/* were reserved2[0] */
			__u32	l_i_reserved2;
			__le16	l_i_checksum_lo;/* crc32c(uuid+inum+inode) LE */
			__le16	l_i_reserved;
		} linux2;
		} linux2;
		struct {
		struct {
			__le16	h_i_reserved1;	/* Obsoleted fragment number/size which are removed in ext4 */
			__le16	h_i_reserved1;	/* Obsoleted fragment number/size which are removed in ext4 */
@@ -666,7 +680,7 @@ struct ext4_inode {
		} masix2;
		} masix2;
	} osd2;				/* OS dependent 2 */
	} osd2;				/* OS dependent 2 */
	__le16	i_extra_isize;
	__le16	i_extra_isize;
	__le16	i_pad1;
	__le16	i_checksum_hi;	/* crc32c(uuid+inum+inode) BE */
	__le32  i_ctime_extra;  /* extra Change time      (nsec << 2 | epoch) */
	__le32  i_ctime_extra;  /* extra Change time      (nsec << 2 | epoch) */
	__le32  i_mtime_extra;  /* extra Modification time(nsec << 2 | epoch) */
	__le32  i_mtime_extra;  /* extra Modification time(nsec << 2 | epoch) */
	__le32  i_atime_extra;  /* extra Access time      (nsec << 2 | epoch) */
	__le32  i_atime_extra;  /* extra Access time      (nsec << 2 | epoch) */
@@ -768,7 +782,7 @@ do { \
#define i_gid_low	i_gid
#define i_gid_low	i_gid
#define i_uid_high	osd2.linux2.l_i_uid_high
#define i_uid_high	osd2.linux2.l_i_uid_high
#define i_gid_high	osd2.linux2.l_i_gid_high
#define i_gid_high	osd2.linux2.l_i_gid_high
#define i_reserved2	osd2.linux2.l_i_reserved2
#define i_checksum_lo	osd2.linux2.l_i_checksum_lo


#elif defined(__GNU__)
#elif defined(__GNU__)


@@ -908,6 +922,9 @@ struct ext4_inode_info {
	 */
	 */
	tid_t i_sync_tid;
	tid_t i_sync_tid;
	tid_t i_datasync_tid;
	tid_t i_datasync_tid;

	/* Precomputed uuid+inum+igen checksum for seeding inode checksums */
	__u32 i_csum_seed;
};
};


/*
/*
@@ -1001,6 +1018,9 @@ extern void ext4_set_bits(void *bm, int cur, int len);
#define EXT4_ERRORS_PANIC		3	/* Panic */
#define EXT4_ERRORS_PANIC		3	/* Panic */
#define EXT4_ERRORS_DEFAULT		EXT4_ERRORS_CONTINUE
#define EXT4_ERRORS_DEFAULT		EXT4_ERRORS_CONTINUE


/* Metadata checksum algorithm codes */
#define EXT4_CRC32C_CHKSUM		1

/*
/*
 * Structure of the super block
 * Structure of the super block
 */
 */
@@ -1087,7 +1107,7 @@ struct ext4_super_block {
	__le64  s_mmp_block;            /* Block for multi-mount protection */
	__le64  s_mmp_block;            /* Block for multi-mount protection */
	__le32  s_raid_stripe_width;    /* blocks on all data disks (N*stride)*/
	__le32  s_raid_stripe_width;    /* blocks on all data disks (N*stride)*/
	__u8	s_log_groups_per_flex;  /* FLEX_BG group size */
	__u8	s_log_groups_per_flex;  /* FLEX_BG group size */
	__u8	s_reserved_char_pad;
	__u8	s_checksum_type;	/* metadata checksum algorithm used */
	__le16  s_reserved_pad;
	__le16  s_reserved_pad;
	__le64	s_kbytes_written;	/* nr of lifetime kilobytes written */
	__le64	s_kbytes_written;	/* nr of lifetime kilobytes written */
	__le32	s_snapshot_inum;	/* Inode number of active snapshot */
	__le32	s_snapshot_inum;	/* Inode number of active snapshot */
@@ -1113,7 +1133,8 @@ struct ext4_super_block {
	__le32	s_usr_quota_inum;	/* inode for tracking user quota */
	__le32	s_usr_quota_inum;	/* inode for tracking user quota */
	__le32	s_grp_quota_inum;	/* inode for tracking group quota */
	__le32	s_grp_quota_inum;	/* inode for tracking group quota */
	__le32	s_overhead_clusters;	/* overhead blocks/clusters in fs */
	__le32	s_overhead_clusters;	/* overhead blocks/clusters in fs */
	__le32  s_reserved[109];        /* Padding to the end of the block */
	__le32	s_reserved[108];	/* Padding to the end of the block */
	__le32	s_checksum;		/* crc32c(superblock) */
};
};


#define EXT4_S_ERR_LEN (EXT4_S_ERR_END - EXT4_S_ERR_START)
#define EXT4_S_ERR_LEN (EXT4_S_ERR_END - EXT4_S_ERR_START)
@@ -1176,6 +1197,7 @@ struct ext4_sb_info {
	struct proc_dir_entry *s_proc;
	struct proc_dir_entry *s_proc;
	struct kobject s_kobj;
	struct kobject s_kobj;
	struct completion s_kobj_unregister;
	struct completion s_kobj_unregister;
	struct super_block *s_sb;


	/* Journaling */
	/* Journaling */
	struct journal_s *s_journal;
	struct journal_s *s_journal;
@@ -1266,6 +1288,12 @@ struct ext4_sb_info {


	/* record the last minlen when FITRIM is called. */
	/* record the last minlen when FITRIM is called. */
	atomic_t s_last_trim_minblks;
	atomic_t s_last_trim_minblks;

	/* Reference to checksum algorithm driver via cryptoapi */
	struct crypto_shash *s_chksum_driver;

	/* Precomputed FS UUID checksum for seeding other checksums */
	__u32 s_csum_seed;
};
};


static inline struct ext4_sb_info *EXT4_SB(struct super_block *sb)
static inline struct ext4_sb_info *EXT4_SB(struct super_block *sb)
@@ -1414,6 +1442,12 @@ static inline void ext4_clear_state_flags(struct ext4_inode_info *ei)
#define EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE	0x0040
#define EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE	0x0040
#define EXT4_FEATURE_RO_COMPAT_QUOTA		0x0100
#define EXT4_FEATURE_RO_COMPAT_QUOTA		0x0100
#define EXT4_FEATURE_RO_COMPAT_BIGALLOC		0x0200
#define EXT4_FEATURE_RO_COMPAT_BIGALLOC		0x0200
/*
 * METADATA_CSUM also enables group descriptor checksums (GDT_CSUM).  When
 * METADATA_CSUM is set, group descriptor checksums use the same algorithm as
 * all other data structures' checksums.  However, the METADATA_CSUM and
 * GDT_CSUM bits are mutually exclusive.
 */
#define EXT4_FEATURE_RO_COMPAT_METADATA_CSUM	0x0400
#define EXT4_FEATURE_RO_COMPAT_METADATA_CSUM	0x0400


#define EXT4_FEATURE_INCOMPAT_COMPRESSION	0x0001
#define EXT4_FEATURE_INCOMPAT_COMPRESSION	0x0001
@@ -1461,7 +1495,8 @@ static inline void ext4_clear_state_flags(struct ext4_inode_info *ei)
					 EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE | \
					 EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE | \
					 EXT4_FEATURE_RO_COMPAT_BTREE_DIR |\
					 EXT4_FEATURE_RO_COMPAT_BTREE_DIR |\
					 EXT4_FEATURE_RO_COMPAT_HUGE_FILE |\
					 EXT4_FEATURE_RO_COMPAT_HUGE_FILE |\
					 EXT4_FEATURE_RO_COMPAT_BIGALLOC)
					 EXT4_FEATURE_RO_COMPAT_BIGALLOC |\
					 EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)


/*
/*
 * Default values for user and/or group using reserved blocks
 * Default values for user and/or group using reserved blocks
@@ -1526,6 +1561,18 @@ struct ext4_dir_entry_2 {
	char	name[EXT4_NAME_LEN];	/* File name */
	char	name[EXT4_NAME_LEN];	/* File name */
};
};


/*
 * This is a bogus directory entry at the end of each leaf block that
 * records checksums.
 */
struct ext4_dir_entry_tail {
	__le32	det_reserved_zero1;	/* Pretend to be unused */
	__le16	det_rec_len;		/* 12 */
	__u8	det_reserved_zero2;	/* Zero name length */
	__u8	det_reserved_ft;	/* 0xDE, fake file type */
	__le32	det_checksum;		/* crc32c(uuid+inum+dirblock) */
};

/*
/*
 * Ext4 directory file types.  Only the low 3 bits are used.  The
 * Ext4 directory file types.  Only the low 3 bits are used.  The
 * other bits are reserved for now.
 * other bits are reserved for now.
@@ -1541,6 +1588,8 @@ struct ext4_dir_entry_2 {


#define EXT4_FT_MAX		8
#define EXT4_FT_MAX		8


#define EXT4_FT_DIR_CSUM	0xDE

/*
/*
 * EXT4_DIR_PAD defines the directory entries boundaries
 * EXT4_DIR_PAD defines the directory entries boundaries
 *
 *
@@ -1609,6 +1658,25 @@ static inline __le16 ext4_rec_len_to_disk(unsigned len, unsigned blocksize)
#define DX_HASH_HALF_MD4_UNSIGNED	4
#define DX_HASH_HALF_MD4_UNSIGNED	4
#define DX_HASH_TEA_UNSIGNED		5
#define DX_HASH_TEA_UNSIGNED		5


static inline u32 ext4_chksum(struct ext4_sb_info *sbi, u32 crc,
			      const void *address, unsigned int length)
{
	struct {
		struct shash_desc shash;
		char ctx[crypto_shash_descsize(sbi->s_chksum_driver)];
	} desc;
	int err;

	desc.shash.tfm = sbi->s_chksum_driver;
	desc.shash.flags = 0;
	*(u32 *)desc.ctx = crc;

	err = crypto_shash_update(&desc.shash, address, length);
	BUG_ON(err);

	return *(u32 *)desc.ctx;
}

#ifdef __KERNEL__
#ifdef __KERNEL__


/* hash info structure used by the directory hash */
/* hash info structure used by the directory hash */
@@ -1741,7 +1809,8 @@ struct mmp_struct {
	__le16	mmp_check_interval;
	__le16	mmp_check_interval;


	__le16	mmp_pad1;
	__le16	mmp_pad1;
	__le32	mmp_pad2[227];
	__le32	mmp_pad2[226];
	__le32	mmp_checksum;		/* crc32c(uuid+mmp_block) */
};
};


/* arguments passed to the mmp thread */
/* arguments passed to the mmp thread */
@@ -1784,8 +1853,24 @@ struct mmpd_data {


/* bitmap.c */
/* bitmap.c */
extern unsigned int ext4_count_free(struct buffer_head *, unsigned);
extern unsigned int ext4_count_free(struct buffer_head *, unsigned);
void ext4_inode_bitmap_csum_set(struct super_block *sb, ext4_group_t group,
				struct ext4_group_desc *gdp,
				struct buffer_head *bh, int sz);
int ext4_inode_bitmap_csum_verify(struct super_block *sb, ext4_group_t group,
				  struct ext4_group_desc *gdp,
				  struct buffer_head *bh, int sz);
void ext4_block_bitmap_csum_set(struct super_block *sb, ext4_group_t group,
				struct ext4_group_desc *gdp,
				struct buffer_head *bh, int sz);
int ext4_block_bitmap_csum_verify(struct super_block *sb, ext4_group_t group,
				  struct ext4_group_desc *gdp,
				  struct buffer_head *bh, int sz);


/* balloc.c */
/* balloc.c */
extern void ext4_validate_block_bitmap(struct super_block *sb,
				       struct ext4_group_desc *desc,
				       unsigned int block_group,
				       struct buffer_head *bh);
extern unsigned int ext4_block_group(struct super_block *sb,
extern unsigned int ext4_block_group(struct super_block *sb,
			ext4_fsblk_t blocknr);
			ext4_fsblk_t blocknr);
extern ext4_grpblk_t ext4_block_group_offset(struct super_block *sb,
extern ext4_grpblk_t ext4_block_group_offset(struct super_block *sb,
@@ -1864,7 +1949,7 @@ extern void ext4_end_bitmap_read(struct buffer_head *bh, int uptodate);
/* mballoc.c */
/* mballoc.c */
extern long ext4_mb_stats;
extern long ext4_mb_stats;
extern long ext4_mb_max_to_scan;
extern long ext4_mb_max_to_scan;
extern int ext4_mb_init(struct super_block *, int);
extern int ext4_mb_init(struct super_block *);
extern int ext4_mb_release(struct super_block *);
extern int ext4_mb_release(struct super_block *);
extern ext4_fsblk_t ext4_mb_new_blocks(handle_t *,
extern ext4_fsblk_t ext4_mb_new_blocks(handle_t *,
				struct ext4_allocation_request *, int *);
				struct ext4_allocation_request *, int *);
@@ -1936,6 +2021,8 @@ extern long ext4_compat_ioctl(struct file *, unsigned int, unsigned long);
extern int ext4_ext_migrate(struct inode *);
extern int ext4_ext_migrate(struct inode *);


/* namei.c */
/* namei.c */
extern int ext4_dirent_csum_verify(struct inode *inode,
				   struct ext4_dir_entry *dirent);
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,
@@ -1950,6 +2037,10 @@ extern int ext4_group_extend(struct super_block *sb,
extern int ext4_resize_fs(struct super_block *sb, ext4_fsblk_t n_blocks_count);
extern int ext4_resize_fs(struct super_block *sb, ext4_fsblk_t n_blocks_count);


/* super.c */
/* super.c */
extern int ext4_superblock_csum_verify(struct super_block *sb,
				       struct ext4_super_block *es);
extern void ext4_superblock_csum_set(struct super_block *sb,
				     struct ext4_super_block *es);
extern void *ext4_kvmalloc(size_t size, gfp_t flags);
extern void *ext4_kvmalloc(size_t size, gfp_t flags);
extern void *ext4_kvzalloc(size_t size, gfp_t flags);
extern void *ext4_kvzalloc(size_t size, gfp_t flags);
extern void ext4_kvfree(void *ptr);
extern void ext4_kvfree(void *ptr);
@@ -2025,11 +2116,18 @@ extern void ext4_used_dirs_set(struct super_block *sb,
				struct ext4_group_desc *bg, __u32 count);
				struct ext4_group_desc *bg, __u32 count);
extern void ext4_itable_unused_set(struct super_block *sb,
extern void ext4_itable_unused_set(struct super_block *sb,
				   struct ext4_group_desc *bg, __u32 count);
				   struct ext4_group_desc *bg, __u32 count);
extern __le16 ext4_group_desc_csum(struct ext4_sb_info *sbi, __u32 group,
extern int ext4_group_desc_csum_verify(struct super_block *sb, __u32 group,
				       struct ext4_group_desc *gdp);
				       struct ext4_group_desc *gdp);
extern int ext4_group_desc_csum_verify(struct ext4_sb_info *sbi, __u32 group,
extern void ext4_group_desc_csum_set(struct super_block *sb, __u32 group,
				     struct ext4_group_desc *gdp);
				     struct ext4_group_desc *gdp);


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);
}

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) |
@@ -2225,6 +2323,9 @@ static inline void ext4_unlock_group(struct super_block *sb,


static inline void ext4_mark_super_dirty(struct super_block *sb)
static inline void ext4_mark_super_dirty(struct super_block *sb)
{
{
	struct ext4_super_block *es = EXT4_SB(sb)->s_es;

	ext4_superblock_csum_set(sb, es);
	if (EXT4_SB(sb)->s_journal == NULL)
	if (EXT4_SB(sb)->s_journal == NULL)
		sb->s_dirt =1;
		sb->s_dirt =1;
}
}
@@ -2314,6 +2415,9 @@ extern int ext4_bio_write_page(struct ext4_io_submit *io,


/* mmp.c */
/* mmp.c */
extern int ext4_multi_mount_protect(struct super_block *, ext4_fsblk_t);
extern int ext4_multi_mount_protect(struct super_block *, ext4_fsblk_t);
extern void ext4_mmp_csum_set(struct super_block *sb, struct mmp_struct *mmp);
extern int ext4_mmp_csum_verify(struct super_block *sb,
				struct mmp_struct *mmp);


/* BH_Uninit flag: blocks are allocated but uninitialized on disk */
/* BH_Uninit flag: blocks are allocated but uninitialized on disk */
enum ext4_state_bits {
enum ext4_state_bits {
Loading