diff options
Diffstat (limited to 'fs/ext4/ext4.h')
| -rw-r--r-- | fs/ext4/ext4.h | 221 | 
1 files changed, 181 insertions, 40 deletions
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index c3411d4ce2d..8462eb3c33a 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -57,6 +57,16 @@  #define ext4_debug(fmt, ...)	no_printk(fmt, ##__VA_ARGS__)  #endif +/* + * Turn on EXT_DEBUG to get lots of info about extents operations. + */ +#define EXT_DEBUG__ +#ifdef EXT_DEBUG +#define ext_debug(fmt, ...)	printk(fmt, ##__VA_ARGS__) +#else +#define ext_debug(fmt, ...)	no_printk(fmt, ##__VA_ARGS__) +#endif +  #define EXT4_ERROR_INODE(inode, fmt, a...) \  	ext4_error_inode((inode), __func__, __LINE__, 0, (fmt), ## a) @@ -186,7 +196,6 @@ struct mpage_da_data {  #define EXT4_IO_END_ERROR	0x0002  #define EXT4_IO_END_QUEUED	0x0004  #define EXT4_IO_END_DIRECT	0x0008 -#define EXT4_IO_END_IN_FSYNC	0x0010  struct ext4_io_page {  	struct page	*p_page; @@ -393,6 +402,7 @@ struct flex_groups {  #define EXT4_EXTENTS_FL			0x00080000 /* Inode uses extents */  #define EXT4_EA_INODE_FL	        0x00200000 /* Inode used for large EA */  #define EXT4_EOFBLOCKS_FL		0x00400000 /* Blocks allocated beyond EOF */ +#define EXT4_INLINE_DATA_FL		0x10000000 /* Inode has inline data. */  #define EXT4_RESERVED_FL		0x80000000 /* reserved for ext4 lib */  #define EXT4_FL_USER_VISIBLE		0x004BDFFF /* User visible flags */ @@ -449,28 +459,26 @@ enum {  	EXT4_INODE_EXTENTS	= 19,	/* Inode uses extents */  	EXT4_INODE_EA_INODE	= 21,	/* Inode used for large EA */  	EXT4_INODE_EOFBLOCKS	= 22,	/* Blocks allocated beyond EOF */ +	EXT4_INODE_INLINE_DATA	= 28,	/* Data in inode. */  	EXT4_INODE_RESERVED	= 31,	/* reserved for ext4 lib */  }; -#define TEST_FLAG_VALUE(FLAG) (EXT4_##FLAG##_FL == (1 << EXT4_INODE_##FLAG)) -#define CHECK_FLAG_VALUE(FLAG) if (!TEST_FLAG_VALUE(FLAG)) { \ -	printk(KERN_EMERG "EXT4 flag fail: " #FLAG ": %d %d\n", \ -		EXT4_##FLAG##_FL, EXT4_INODE_##FLAG); BUG_ON(1); } -  /* - * Since it's pretty easy to mix up bit numbers and hex values, and we - * can't do a compile-time test for ENUM values, we use a run-time - * test to make sure that EXT4_XXX_FL is consistent with respect to - * EXT4_INODE_XXX.  If all is well the printk and BUG_ON will all drop - * out so it won't cost any extra space in the compiled kernel image. - * But it's important that these values are the same, since we are - * using EXT4_INODE_XXX to test for the flag values, but EXT4_XX_FL - * must be consistent with the values of FS_XXX_FL defined in - * include/linux/fs.h and the on-disk values found in ext2, ext3, and - * ext4 filesystems, and of course the values defined in e2fsprogs. + * Since it's pretty easy to mix up bit numbers and hex values, we use a + * build-time check to make sure that EXT4_XXX_FL is consistent with respect to + * EXT4_INODE_XXX. If all is well, the macros will be dropped, so, it won't cost + * any extra space in the compiled kernel image, otherwise, the build will fail. + * It's important that these values are the same, since we are using + * EXT4_INODE_XXX to test for flag values, but EXT4_XXX_FL must be consistent + * with the values of FS_XXX_FL defined in include/linux/fs.h and the on-disk + * values found in ext2, ext3 and ext4 filesystems, and of course the values + * defined in e2fsprogs.   *   * It's not paranoia if the Murphy's Law really *is* out to get you.  :-)   */ +#define TEST_FLAG_VALUE(FLAG) (EXT4_##FLAG##_FL == (1 << EXT4_INODE_##FLAG)) +#define CHECK_FLAG_VALUE(FLAG) BUILD_BUG_ON(!TEST_FLAG_VALUE(FLAG)) +  static inline void ext4_check_flag_values(void)  {  	CHECK_FLAG_VALUE(SECRM); @@ -495,6 +503,7 @@ static inline void ext4_check_flag_values(void)  	CHECK_FLAG_VALUE(EXTENTS);  	CHECK_FLAG_VALUE(EA_INODE);  	CHECK_FLAG_VALUE(EOFBLOCKS); +	CHECK_FLAG_VALUE(INLINE_DATA);  	CHECK_FLAG_VALUE(RESERVED);  } @@ -812,6 +821,8 @@ struct ext4_ext_cache {  	__u32		ec_len; /* must be 32bit to return holes */  }; +#include "extents_status.h" +  /*   * fourth extended file system inode data in memory   */ @@ -834,7 +845,6 @@ struct ext4_inode_info {  #endif  	unsigned long	i_flags; -#ifdef CONFIG_EXT4_FS_XATTR  	/*  	 * Extended attributes can be read independently of the main file  	 * data. Taking i_mutex even when reading would cause contention @@ -843,7 +853,6 @@ struct ext4_inode_info {  	 * EAs.  	 */  	struct rw_semaphore xattr_sem; -#endif  	struct list_head i_orphan;	/* unlinked but open inodes */ @@ -889,6 +898,10 @@ struct ext4_inode_info {  	struct list_head i_prealloc_list;  	spinlock_t i_prealloc_lock; +	/* extents status tree */ +	struct ext4_es_tree i_es_tree; +	rwlock_t i_es_lock; +  	/* ialloc */  	ext4_group_t	i_last_alloc_group; @@ -903,6 +916,10 @@ struct ext4_inode_info {  	/* on-disk additional length */  	__u16 i_extra_isize; +	/* Indicate the inline data space. */ +	u16 i_inline_off; +	u16 i_inline_size; +  #ifdef CONFIG_QUOTA  	/* quota space reservation, managed internally by quota code */  	qsize_t i_reserved_quota; @@ -912,9 +929,7 @@ struct ext4_inode_info {  	struct list_head i_completed_io_list;  	spinlock_t i_completed_io_lock;  	atomic_t i_ioend_count;	/* Number of outstanding io_end structs */ -	/* current io_end structure for async DIO write*/ -	ext4_io_end_t *cur_aio_dio; -	atomic_t i_aiodio_unwritten; /* Nr. of inflight conversions pending */ +	atomic_t i_unwritten; /* Nr. of inflight conversions pending */  	spinlock_t i_block_reservation_lock; @@ -1233,6 +1248,7 @@ struct ext4_sb_info {  	spinlock_t s_md_lock;  	unsigned short *s_mb_offsets;  	unsigned int *s_mb_maxs; +	unsigned int s_group_info_size;  	/* tunables */  	unsigned long s_stripe; @@ -1243,6 +1259,7 @@ struct ext4_sb_info {  	unsigned int s_mb_order2_reqs;  	unsigned int s_mb_group_prealloc;  	unsigned int s_max_writeback_mb_bump; +	unsigned int s_max_dir_size_kb;  	/* where last allocation was done - for stream allocation */  	unsigned long s_mb_last_group;  	unsigned long s_mb_last_start; @@ -1270,8 +1287,12 @@ struct ext4_sb_info {  	unsigned long s_sectors_written_start;  	u64 s_kbytes_written; +	/* the size of zero-out chunk */ +	unsigned int s_extent_max_zeroout_kb; +  	unsigned int s_log_groups_per_flex;  	struct flex_groups *s_flex_groups; +	ext4_group_t s_flex_groups_allocated;  	/* workqueue for dio unwritten */  	struct workqueue_struct *dio_unwritten_wq; @@ -1328,10 +1349,20 @@ static inline void ext4_set_io_unwritten_flag(struct inode *inode,  {  	if (!(io_end->flag & EXT4_IO_END_UNWRITTEN)) {  		io_end->flag |= EXT4_IO_END_UNWRITTEN; -		atomic_inc(&EXT4_I(inode)->i_aiodio_unwritten); +		atomic_inc(&EXT4_I(inode)->i_unwritten);  	}  } +static inline ext4_io_end_t *ext4_inode_aio(struct inode *inode) +{ +	return inode->i_private; +} + +static inline void ext4_inode_aio_set(struct inode *inode, ext4_io_end_t *io) +{ +	inode->i_private = io; +} +  /*   * Inode dynamic state flags   */ @@ -1345,6 +1376,9 @@ enum {  	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 */  };  #define EXT4_INODE_BIT_FNS(name, field, offset)				\ @@ -1466,7 +1500,7 @@ static inline void ext4_clear_state_flags(struct ext4_inode_info *ei)  #define EXT4_FEATURE_INCOMPAT_DIRDATA		0x1000 /* data in dirent */  #define EXT4_FEATURE_INCOMPAT_BG_USE_META_CSUM	0x2000 /* use crc32c for bg */  #define EXT4_FEATURE_INCOMPAT_LARGEDIR		0x4000 /* >2GB or 3-lvl htree */ -#define EXT4_FEATURE_INCOMPAT_INLINEDATA	0x8000 /* data in inode */ +#define EXT4_FEATURE_INCOMPAT_INLINE_DATA	0x8000 /* data in inode */  #define EXT2_FEATURE_COMPAT_SUPP	EXT4_FEATURE_COMPAT_EXT_ATTR  #define EXT2_FEATURE_INCOMPAT_SUPP	(EXT4_FEATURE_INCOMPAT_FILETYPE| \ @@ -1490,7 +1524,8 @@ static inline void ext4_clear_state_flags(struct ext4_inode_info *ei)  					 EXT4_FEATURE_INCOMPAT_EXTENTS| \  					 EXT4_FEATURE_INCOMPAT_64BIT| \  					 EXT4_FEATURE_INCOMPAT_FLEX_BG| \ -					 EXT4_FEATURE_INCOMPAT_MMP) +					 EXT4_FEATURE_INCOMPAT_MMP |	\ +					 EXT4_FEATURE_INCOMPAT_INLINE_DATA)  #define EXT4_FEATURE_RO_COMPAT_SUPP	(EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER| \  					 EXT4_FEATURE_RO_COMPAT_LARGE_FILE| \  					 EXT4_FEATURE_RO_COMPAT_GDT_CSUM| \ @@ -1577,6 +1612,11 @@ struct ext4_dir_entry_tail {  	__le32	det_checksum;		/* crc32c(uuid+inum+dirblock) */  }; +#define EXT4_DIRENT_TAIL(block, blocksize) \ +	((struct ext4_dir_entry_tail *)(((void *)(block)) + \ +					((blocksize) - \ +					 sizeof(struct ext4_dir_entry_tail)))) +  /*   * Ext4 directory file types.  Only the low 3 bits are used.  The   * other bits are reserved for now. @@ -1867,10 +1907,10 @@ int ext4_inode_bitmap_csum_verify(struct super_block *sb, ext4_group_t group,  				  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); +				struct buffer_head *bh);  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); +				  struct buffer_head *bh);  /* balloc.c */  extern void ext4_validate_block_bitmap(struct super_block *sb, @@ -1921,18 +1961,46 @@ ext4_fsblk_t ext4_inode_to_goal_block(struct inode *);  extern int __ext4_check_dir_entry(const char *, unsigned int, struct inode *,  				  struct file *,  				  struct ext4_dir_entry_2 *, -				  struct buffer_head *, unsigned int); -#define ext4_check_dir_entry(dir, filp, de, bh, offset)			\ +				  struct buffer_head *, char *, int, +				  unsigned int); +#define ext4_check_dir_entry(dir, filp, de, bh, buf, size, offset)	\  	unlikely(__ext4_check_dir_entry(__func__, __LINE__, (dir), (filp), \ -					(de), (bh), (offset))) +					(de), (bh), (buf), (size), (offset)))  extern int ext4_htree_store_dirent(struct file *dir_file, __u32 hash,  				    __u32 minor_hash,  				    struct ext4_dir_entry_2 *dirent);  extern void ext4_htree_free_dir_info(struct dir_private_info *p); +extern int ext4_find_dest_de(struct inode *dir, struct inode *inode, +			     struct buffer_head *bh, +			     void *buf, int buf_size, +			     const char *name, int namelen, +			     struct ext4_dir_entry_2 **dest_de); +void ext4_insert_dentry(struct inode *inode, +			struct ext4_dir_entry_2 *de, +			int buf_size, +			const char *name, int namelen); +static inline void ext4_update_dx_flag(struct inode *inode) +{ +	if (!EXT4_HAS_COMPAT_FEATURE(inode->i_sb, +				     EXT4_FEATURE_COMPAT_DIR_INDEX)) +		ext4_clear_inode_flag(inode, EXT4_INODE_INDEX); +} +static unsigned char ext4_filetype_table[] = { +	DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, DT_BLK, DT_FIFO, DT_SOCK, DT_LNK +}; + +static inline  unsigned char get_dtype(struct super_block *sb, int filetype) +{ +	if (!EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FILETYPE) || +	    (filetype >= EXT4_FT_MAX)) +		return DT_UNKNOWN; + +	return ext4_filetype_table[filetype]; +}  /* fsync.c */  extern int ext4_sync_file(struct file *, loff_t, loff_t, int); -extern int ext4_flush_completed_IO(struct inode *); +extern int ext4_flush_unwritten_io(struct inode *);  /* hash.c */  extern int ext4fs_dirhash(const char *name, int len, struct @@ -1966,6 +2034,8 @@ extern void ext4_exit_mballoc(void);  extern void ext4_free_blocks(handle_t *handle, struct inode *inode,  			     struct buffer_head *bh, ext4_fsblk_t block,  			     unsigned long count, int flags); +extern int ext4_mb_alloc_groupinfo(struct super_block *sb, +				   ext4_group_t ngroups);  extern int ext4_mb_add_groupinfo(struct super_block *sb,  		ext4_group_t i, struct ext4_group_desc *desc);  extern int ext4_group_add_blocks(handle_t *handle, struct super_block *sb, @@ -1977,8 +2047,23 @@ 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 *); +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,  				struct buffer_head *bh_result, int create); +int ext4_da_get_block_prep(struct inode *inode, sector_t iblock, +			   struct buffer_head *bh, int create); +int ext4_walk_page_buffers(handle_t *handle, +			   struct buffer_head *head, +			   unsigned from, +			   unsigned to, +			   int *partial, +			   int (*fn)(handle_t *handle, +				     struct buffer_head *bh)); +int do_journal_get_write_access(handle_t *handle, +				struct buffer_head *bh); +#define FALL_BACK_TO_NONDELALLOC 1 +#define CONVERT_INLINE_DATA	 2  extern struct inode *ext4_iget(struct super_block *, unsigned long);  extern int  ext4_write_inode(struct inode *, struct writeback_control *); @@ -2033,6 +2118,20 @@ extern int ext4_orphan_add(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,  				__u32 start_minor_hash, __u32 *next_hash); +extern int search_dir(struct buffer_head *bh, +		      char *search_buf, +		      int buf_size, +		      struct inode *dir, +		      const struct qstr *d_name, +		      unsigned int offset, +		      struct ext4_dir_entry_2 **res_dir); +extern int ext4_generic_delete_entry(handle_t *handle, +				     struct inode *dir, +				     struct ext4_dir_entry_2 *de_del, +				     struct buffer_head *bh, +				     void *entry_buf, +				     int buf_size, +				     int csum_size);  /* resize.c */  extern int ext4_group_add(struct super_block *sb, @@ -2046,11 +2145,12 @@ extern int ext4_resize_fs(struct super_block *sb, ext4_fsblk_t n_blocks_count);  extern int ext4_calculate_overhead(struct super_block *sb);  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_superblock_csum_set(struct super_block *sb);  extern void *ext4_kvmalloc(size_t size, gfp_t flags);  extern void *ext4_kvzalloc(size_t size, gfp_t flags);  extern void ext4_kvfree(void *ptr); +extern int ext4_alloc_flex_bg_array(struct super_block *sb, +				    ext4_group_t ngroup);  extern __printf(4, 5)  void __ext4_error(struct super_block *, const char *, unsigned int,  		  const char *, ...); @@ -2352,11 +2452,21 @@ extern const struct file_operations ext4_dir_operations;  extern const struct inode_operations ext4_file_inode_operations;  extern const struct file_operations ext4_file_operations;  extern loff_t ext4_llseek(struct file *file, loff_t offset, int origin); +extern void ext4_unwritten_wait(struct inode *inode);  /* namei.c */  extern const struct inode_operations ext4_dir_inode_operations;  extern const struct inode_operations ext4_special_inode_operations;  extern struct dentry *ext4_get_parent(struct dentry *child); +extern struct ext4_dir_entry_2 *ext4_init_dot_dotdot(struct inode *inode, +				 struct ext4_dir_entry_2 *de, +				 int blocksize, int csum_size, +				 unsigned int parent_ino, int dotdot_real_len); +extern void initialize_dirent_tail(struct ext4_dir_entry_tail *t, +				   unsigned int blocksize); +extern int ext4_handle_dirty_dirent_node(handle_t *handle, +					 struct inode *inode, +					 struct buffer_head *bh);  /* symlink.c */  extern const struct inode_operations ext4_symlink_inode_operations; @@ -2374,6 +2484,9 @@ extern int ext4_check_blockref(const char *, unsigned int,  			       struct inode *, __le32 *, unsigned int);  /* extents.c */ +struct ext4_ext_path; +struct ext4_extent; +  extern int ext4_ext_tree_init(handle_t *handle, struct inode *);  extern int ext4_ext_writepage_trans_blocks(struct inode *, int);  extern int ext4_ext_index_trans_blocks(struct inode *inode, int nrblocks, @@ -2391,8 +2504,27 @@ extern int ext4_convert_unwritten_extents(struct inode *inode, loff_t offset,  			  ssize_t len);  extern int ext4_map_blocks(handle_t *handle, struct inode *inode,  			   struct ext4_map_blocks *map, int flags); +extern int ext4_ext_calc_metadata_amount(struct inode *inode, +					 ext4_lblk_t lblocks); +extern int ext4_extent_tree_init(handle_t *, struct inode *); +extern int ext4_ext_calc_credits_for_single_extent(struct inode *inode, +						   int num, +						   struct ext4_ext_path *path); +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_extent *, int); +extern struct ext4_ext_path *ext4_ext_find_extent(struct inode *, ext4_lblk_t, +						  struct ext4_ext_path *); +extern void ext4_ext_drop_refs(struct ext4_ext_path *); +extern int ext4_ext_check_inode(struct inode *inode); +extern int ext4_find_delalloc_cluster(struct inode *inode, ext4_lblk_t lblk);  extern int ext4_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,  			__u64 start, __u64 len); + +  /* move_extent.c */  extern int ext4_move_extents(struct file *o_filp, struct file *d_filp,  			     __u64 start_orig, __u64 start_donor, @@ -2400,11 +2532,11 @@ extern int ext4_move_extents(struct file *o_filp, struct file *d_filp,  /* page-io.c */  extern int __init ext4_init_pageio(void); +extern void ext4_add_complete_io(ext4_io_end_t *io_end);  extern void ext4_exit_pageio(void);  extern void ext4_ioend_wait(struct inode *);  extern void ext4_free_io_end(ext4_io_end_t *io);  extern ext4_io_end_t *ext4_init_io_end(struct inode *inode, gfp_t flags); -extern int ext4_end_io_nolock(ext4_io_end_t *io);  extern void ext4_io_submit(struct ext4_io_submit *io);  extern int ext4_bio_write_page(struct ext4_io_submit *io,  			       struct page *page, @@ -2426,17 +2558,13 @@ enum ext4_state_bits {  				 * never, ever appear in a buffer_head's state  				 * flag. See EXT4_MAP_FROM_CLUSTER to see where  				 * this is used. */ -	BH_Da_Mapped,	/* Delayed allocated block that now has a mapping. This -			 * flag is set when ext4_map_blocks is called on a -			 * delayed allocated block to get its real mapping. */  };  BUFFER_FNS(Uninit, uninit)  TAS_BUFFER_FNS(Uninit, uninit) -BUFFER_FNS(Da_Mapped, da_mapped)  /* - * Add new method to test wether block and inode bitmaps are properly + * Add new method to test whether block and inode bitmaps are properly   * initialized. With uninit_bg reading the block from disk is not enough   * to mark the bitmap uptodate. We need to also zero-out the bitmap   */ @@ -2452,6 +2580,21 @@ static inline void set_bitmap_uptodate(struct buffer_head *bh)  	set_bit(BH_BITMAP_UPTODATE, &(bh)->b_state);  } +/* + * Disable DIO read nolock optimization, so new dioreaders will be forced + * to grab i_mutex + */ +static inline void ext4_inode_block_unlocked_dio(struct inode *inode) +{ +	ext4_set_inode_state(inode, EXT4_STATE_DIOREAD_LOCK); +	smp_mb(); +} +static inline void ext4_inode_resume_unlocked_dio(struct inode *inode) +{ +	smp_mb(); +	ext4_clear_inode_state(inode, EXT4_STATE_DIOREAD_LOCK); +} +  #define in_range(b, first, len)	((b) >= (first) && (b) <= (first) + (len) - 1)  /* For ioend & aio unwritten conversion wait queues */ @@ -2469,6 +2612,4 @@ extern void ext4_resize_end(struct super_block *sb);  #endif	/* __KERNEL__ */ -#include "ext4_extents.h" -  #endif	/* _EXT4_H */  |