forked from mirrors/linux
		
	ext4: main fast-commit commit path
This patch adds main fast commit commit path handlers. The overall
patch can be divided into two inter-related parts:
(A) Metadata updates tracking
    This part consists of helper functions to track changes that need
    to be committed during a commit operation. These updates are
    maintained by Ext4 in different in-memory queues. Following are
    the APIs and their short description that are implemented in this
    patch:
    - ext4_fc_track_link/unlink/creat() - Track unlink. link and creat
      operations
    - ext4_fc_track_range() - Track changed logical block offsets
      inodes
    - ext4_fc_track_inode() - Track inodes
    - ext4_fc_mark_ineligible() - Mark file system fast commit
      ineligible()
    - ext4_fc_start_update() / ext4_fc_stop_update() /
      ext4_fc_start_ineligible() / ext4_fc_stop_ineligible() These
      functions are useful for co-ordinating inode updates with
      commits.
(B) Main commit Path
    This part consists of functions to convert updates tracked in
    in-memory data structures into on-disk commits. Function
    ext4_fc_commit() is the main entry point to commit path.
Reported-by: kernel test robot <lkp@intel.com>
Signed-off-by: Harshad Shirwadkar <harshadshirwadkar@gmail.com>
Link: https://lore.kernel.org/r/20201015203802.3597742-6-harshadshirwadkar@gmail.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
			
			
This commit is contained in:
		
							parent
							
								
									ff780b91ef
								
							
						
					
					
						commit
						aa75f4d3da
					
				
					 13 changed files with 1707 additions and 29 deletions
				
			
		|  | @ -242,6 +242,7 @@ ext4_set_acl(struct inode *inode, struct posix_acl *acl, int type) | |||
| 	handle = ext4_journal_start(inode, EXT4_HT_XATTR, credits); | ||||
| 	if (IS_ERR(handle)) | ||||
| 		return PTR_ERR(handle); | ||||
| 	ext4_fc_start_update(inode); | ||||
| 
 | ||||
| 	if ((type == ACL_TYPE_ACCESS) && acl) { | ||||
| 		error = posix_acl_update_mode(inode, &mode, &acl); | ||||
|  | @ -259,6 +260,7 @@ ext4_set_acl(struct inode *inode, struct posix_acl *acl, int type) | |||
| 	} | ||||
| out_stop: | ||||
| 	ext4_journal_stop(handle); | ||||
| 	ext4_fc_stop_update(inode); | ||||
| 	if (error == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries)) | ||||
| 		goto retry; | ||||
| 	return error; | ||||
|  |  | |||
|  | @ -1021,6 +1021,31 @@ struct ext4_inode_info { | |||
| 
 | ||||
| 	struct list_head i_orphan;	/* unlinked but open inodes */ | ||||
| 
 | ||||
| 	/* Fast commit related info */ | ||||
| 
 | ||||
| 	struct list_head i_fc_list;	/*
 | ||||
| 					 * inodes that need fast commit | ||||
| 					 * protected by sbi->s_fc_lock. | ||||
| 					 */ | ||||
| 
 | ||||
| 	/* Fast commit subtid when this inode was committed */ | ||||
| 	unsigned int i_fc_committed_subtid; | ||||
| 
 | ||||
| 	/* Start of lblk range that needs to be committed in this fast commit */ | ||||
| 	ext4_lblk_t i_fc_lblk_start; | ||||
| 
 | ||||
| 	/* End of lblk range that needs to be committed in this fast commit */ | ||||
| 	ext4_lblk_t i_fc_lblk_len; | ||||
| 
 | ||||
| 	/* Number of ongoing updates on this inode */ | ||||
| 	atomic_t  i_fc_updates; | ||||
| 
 | ||||
| 	/* Fast commit wait queue for this inode */ | ||||
| 	wait_queue_head_t i_fc_wait; | ||||
| 
 | ||||
| 	/* Protect concurrent accesses on i_fc_lblk_start, i_fc_lblk_len */ | ||||
| 	struct mutex i_fc_lock; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * i_disksize keeps track of what the inode size is ON DISK, not | ||||
| 	 * in memory.  During truncate, i_size is set to the new size by | ||||
|  | @ -1141,6 +1166,10 @@ struct ext4_inode_info { | |||
| #define	EXT4_VALID_FS			0x0001	/* Unmounted cleanly */ | ||||
| #define	EXT4_ERROR_FS			0x0002	/* Errors detected */ | ||||
| #define	EXT4_ORPHAN_FS			0x0004	/* Orphans being recovered */ | ||||
| #define EXT4_FC_INELIGIBLE		0x0008	/* Fast commit ineligible */ | ||||
| #define EXT4_FC_COMMITTING		0x0010	/* File system underoing a fast | ||||
| 						 * commit. | ||||
| 						 */ | ||||
| 
 | ||||
| /*
 | ||||
|  * Misc. filesystem flags | ||||
|  | @ -1613,6 +1642,30 @@ struct ext4_sb_info { | |||
| 	/* Record the errseq of the backing block device */ | ||||
| 	errseq_t s_bdev_wb_err; | ||||
| 	spinlock_t s_bdev_wb_lock; | ||||
| 
 | ||||
| 	/* Ext4 fast commit stuff */ | ||||
| 	atomic_t s_fc_subtid; | ||||
| 	atomic_t s_fc_ineligible_updates; | ||||
| 	/*
 | ||||
| 	 * After commit starts, the main queue gets locked, and the further | ||||
| 	 * updates get added in the staging queue. | ||||
| 	 */ | ||||
| #define FC_Q_MAIN	0 | ||||
| #define FC_Q_STAGING	1 | ||||
| 	struct list_head s_fc_q[2];	/* Inodes staged for fast commit
 | ||||
| 					 * that have data changes in them. | ||||
| 					 */ | ||||
| 	struct list_head s_fc_dentry_q[2];	/* directory entry updates */ | ||||
| 	unsigned int s_fc_bytes; | ||||
| 	/*
 | ||||
| 	 * Main fast commit lock. This lock protects accesses to the | ||||
| 	 * following fields: | ||||
| 	 * ei->i_fc_list, s_fc_dentry_q, s_fc_q, s_fc_bytes, s_fc_bh. | ||||
| 	 */ | ||||
| 	spinlock_t s_fc_lock; | ||||
| 	struct buffer_head *s_fc_bh; | ||||
| 	struct ext4_fc_stats s_fc_stats; | ||||
| 	u64 s_fc_avg_commit_time; | ||||
| }; | ||||
| 
 | ||||
| static inline struct ext4_sb_info *EXT4_SB(struct super_block *sb) | ||||
|  | @ -1723,6 +1776,7 @@ enum { | |||
| 	EXT4_STATE_EXT_PRECACHED,	/* extents have been precached */ | ||||
| 	EXT4_STATE_LUSTRE_EA_INODE,	/* Lustre-style ea_inode */ | ||||
| 	EXT4_STATE_VERITY_IN_PROGRESS,	/* building fs-verity Merkle tree */ | ||||
| 	EXT4_STATE_FC_COMMITTING,	/* Fast commit ongoing */ | ||||
| }; | ||||
| 
 | ||||
| #define EXT4_INODE_BIT_FNS(name, field, offset)				\ | ||||
|  | @ -2682,6 +2736,22 @@ extern void ext4_end_bitmap_read(struct buffer_head *bh, int uptodate); | |||
| /* fast_commit.c */ | ||||
| 
 | ||||
| void ext4_fc_init(struct super_block *sb, journal_t *journal); | ||||
| void ext4_fc_init_inode(struct inode *inode); | ||||
| void ext4_fc_track_range(struct inode *inode, ext4_lblk_t start, | ||||
| 			 ext4_lblk_t end); | ||||
| void ext4_fc_track_unlink(struct inode *inode, struct dentry *dentry); | ||||
| void ext4_fc_track_link(struct inode *inode, struct dentry *dentry); | ||||
| void ext4_fc_track_create(struct inode *inode, struct dentry *dentry); | ||||
| void ext4_fc_track_inode(struct inode *inode); | ||||
| void ext4_fc_mark_ineligible(struct super_block *sb, int reason); | ||||
| void ext4_fc_start_ineligible(struct super_block *sb, int reason); | ||||
| void ext4_fc_stop_ineligible(struct super_block *sb); | ||||
| void ext4_fc_start_update(struct inode *inode); | ||||
| void ext4_fc_stop_update(struct inode *inode); | ||||
| void ext4_fc_del(struct inode *inode); | ||||
| int ext4_fc_commit(journal_t *journal, tid_t commit_tid); | ||||
| int __init ext4_fc_init_dentry_cache(void); | ||||
| 
 | ||||
| /* mballoc.c */ | ||||
| extern const struct seq_operations ext4_mb_seq_groups_ops; | ||||
| extern long ext4_mb_stats; | ||||
|  |  | |||
|  | @ -3723,6 +3723,7 @@ static int ext4_convert_unwritten_extents_endio(handle_t *handle, | |||
| 	err = ext4_ext_dirty(handle, inode, path + path->p_depth); | ||||
| out: | ||||
| 	ext4_ext_show_leaf(inode, path); | ||||
| 	ext4_fc_track_range(inode, ee_block, ee_block + ee_len - 1); | ||||
| 	return err; | ||||
| } | ||||
| 
 | ||||
|  | @ -3794,6 +3795,7 @@ convert_initialized_extent(handle_t *handle, struct inode *inode, | |||
| 	if (*allocated > map->m_len) | ||||
| 		*allocated = map->m_len; | ||||
| 	map->m_len = *allocated; | ||||
| 	ext4_fc_track_range(inode, ee_block, ee_block + ee_len - 1); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
|  | @ -4327,7 +4329,7 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode, | |||
| 	map->m_len = ar.len; | ||||
| 	allocated = map->m_len; | ||||
| 	ext4_ext_show_leaf(inode, path); | ||||
| 
 | ||||
| 	ext4_fc_track_range(inode, map->m_lblk, map->m_lblk + map->m_len - 1); | ||||
| out: | ||||
| 	ext4_ext_drop_refs(path); | ||||
| 	kfree(path); | ||||
|  | @ -4600,7 +4602,8 @@ static long ext4_zero_range(struct file *file, loff_t offset, | |||
| 	ret = ext4_mark_inode_dirty(handle, inode); | ||||
| 	if (unlikely(ret)) | ||||
| 		goto out_handle; | ||||
| 
 | ||||
| 	ext4_fc_track_range(inode, offset >> inode->i_sb->s_blocksize_bits, | ||||
| 			(offset + len - 1) >> inode->i_sb->s_blocksize_bits); | ||||
| 	/* Zero out partial block at the edges of the range */ | ||||
| 	ret = ext4_zero_partial_blocks(handle, inode, offset, len); | ||||
| 	if (ret >= 0) | ||||
|  | @ -4648,23 +4651,34 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len) | |||
| 		     FALLOC_FL_COLLAPSE_RANGE | FALLOC_FL_ZERO_RANGE | | ||||
| 		     FALLOC_FL_INSERT_RANGE)) | ||||
| 		return -EOPNOTSUPP; | ||||
| 	ext4_fc_track_range(inode, offset >> blkbits, | ||||
| 			(offset + len - 1) >> blkbits); | ||||
| 
 | ||||
| 	if (mode & FALLOC_FL_PUNCH_HOLE) | ||||
| 		return ext4_punch_hole(inode, offset, len); | ||||
| 	ext4_fc_start_update(inode); | ||||
| 
 | ||||
| 	if (mode & FALLOC_FL_PUNCH_HOLE) { | ||||
| 		ret = ext4_punch_hole(inode, offset, len); | ||||
| 		goto exit; | ||||
| 	} | ||||
| 
 | ||||
| 	ret = ext4_convert_inline_data(inode); | ||||
| 	if (ret) | ||||
| 		return ret; | ||||
| 		goto exit; | ||||
| 
 | ||||
| 	if (mode & FALLOC_FL_COLLAPSE_RANGE) | ||||
| 		return ext4_collapse_range(inode, offset, len); | ||||
| 	if (mode & FALLOC_FL_COLLAPSE_RANGE) { | ||||
| 		ret = ext4_collapse_range(inode, offset, len); | ||||
| 		goto exit; | ||||
| 	} | ||||
| 
 | ||||
| 	if (mode & FALLOC_FL_INSERT_RANGE) | ||||
| 		return ext4_insert_range(inode, offset, len); | ||||
| 
 | ||||
| 	if (mode & FALLOC_FL_ZERO_RANGE) | ||||
| 		return ext4_zero_range(file, offset, len, mode); | ||||
| 	if (mode & FALLOC_FL_INSERT_RANGE) { | ||||
| 		ret = ext4_insert_range(inode, offset, len); | ||||
| 		goto exit; | ||||
| 	} | ||||
| 
 | ||||
| 	if (mode & FALLOC_FL_ZERO_RANGE) { | ||||
| 		ret = ext4_zero_range(file, offset, len, mode); | ||||
| 		goto exit; | ||||
| 	} | ||||
| 	trace_ext4_fallocate_enter(inode, offset, len, mode); | ||||
| 	lblk = offset >> blkbits; | ||||
| 
 | ||||
|  | @ -4698,12 +4712,14 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len) | |||
| 		goto out; | ||||
| 
 | ||||
| 	if (file->f_flags & O_SYNC && EXT4_SB(inode->i_sb)->s_journal) { | ||||
| 		ret = jbd2_complete_transaction(EXT4_SB(inode->i_sb)->s_journal, | ||||
| 		ret = ext4_fc_commit(EXT4_SB(inode->i_sb)->s_journal, | ||||
| 					EXT4_I(inode)->i_sync_tid); | ||||
| 	} | ||||
| out: | ||||
| 	inode_unlock(inode); | ||||
| 	trace_ext4_fallocate_exit(inode, offset, max_blocks, ret); | ||||
| exit: | ||||
| 	ext4_fc_stop_update(inode); | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
|  | @ -5291,6 +5307,7 @@ static int ext4_collapse_range(struct inode *inode, loff_t offset, loff_t len) | |||
| 		ret = PTR_ERR(handle); | ||||
| 		goto out_mmap; | ||||
| 	} | ||||
| 	ext4_fc_start_ineligible(sb, EXT4_FC_REASON_FALLOC_RANGE); | ||||
| 
 | ||||
| 	down_write(&EXT4_I(inode)->i_data_sem); | ||||
| 	ext4_discard_preallocations(inode, 0); | ||||
|  | @ -5329,6 +5346,7 @@ static int ext4_collapse_range(struct inode *inode, loff_t offset, loff_t len) | |||
| 
 | ||||
| out_stop: | ||||
| 	ext4_journal_stop(handle); | ||||
| 	ext4_fc_stop_ineligible(sb); | ||||
| out_mmap: | ||||
| 	up_write(&EXT4_I(inode)->i_mmap_sem); | ||||
| out_mutex: | ||||
|  | @ -5429,6 +5447,7 @@ static int ext4_insert_range(struct inode *inode, loff_t offset, loff_t len) | |||
| 		ret = PTR_ERR(handle); | ||||
| 		goto out_mmap; | ||||
| 	} | ||||
| 	ext4_fc_start_ineligible(sb, EXT4_FC_REASON_FALLOC_RANGE); | ||||
| 
 | ||||
| 	/* Expand file to avoid data loss if there is error while shifting */ | ||||
| 	inode->i_size += len; | ||||
|  | @ -5503,6 +5522,7 @@ static int ext4_insert_range(struct inode *inode, loff_t offset, loff_t len) | |||
| 
 | ||||
| out_stop: | ||||
| 	ext4_journal_stop(handle); | ||||
| 	ext4_fc_stop_ineligible(sb); | ||||
| out_mmap: | ||||
| 	up_write(&EXT4_I(inode)->i_mmap_sem); | ||||
| out_mutex: | ||||
|  |  | |||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							|  | @ -6,4 +6,114 @@ | |||
| /* Number of blocks in journal area to allocate for fast commits */ | ||||
| #define EXT4_NUM_FC_BLKS		256 | ||||
| 
 | ||||
| /* Fast commit tags */ | ||||
| #define EXT4_FC_TAG_ADD_RANGE		0x0001 | ||||
| #define EXT4_FC_TAG_DEL_RANGE		0x0002 | ||||
| #define EXT4_FC_TAG_CREAT		0x0003 | ||||
| #define EXT4_FC_TAG_LINK		0x0004 | ||||
| #define EXT4_FC_TAG_UNLINK		0x0005 | ||||
| #define EXT4_FC_TAG_INODE		0x0006 | ||||
| #define EXT4_FC_TAG_PAD			0x0007 | ||||
| #define EXT4_FC_TAG_TAIL		0x0008 | ||||
| #define EXT4_FC_TAG_HEAD		0x0009 | ||||
| 
 | ||||
| #define EXT4_FC_SUPPORTED_FEATURES	0x0 | ||||
| 
 | ||||
| /* On disk fast commit tlv value structures */ | ||||
| 
 | ||||
| /* Fast commit on disk tag length structure */ | ||||
| struct ext4_fc_tl { | ||||
| 	__le16 fc_tag; | ||||
| 	__le16 fc_len; | ||||
| }; | ||||
| 
 | ||||
| /* Value structure for tag EXT4_FC_TAG_HEAD. */ | ||||
| struct ext4_fc_head { | ||||
| 	__le32 fc_features; | ||||
| 	__le32 fc_tid; | ||||
| }; | ||||
| 
 | ||||
| /* Value structure for EXT4_FC_TAG_ADD_RANGE. */ | ||||
| struct ext4_fc_add_range { | ||||
| 	__le32 fc_ino; | ||||
| 	__u8 fc_ex[12]; | ||||
| }; | ||||
| 
 | ||||
| /* Value structure for tag EXT4_FC_TAG_DEL_RANGE. */ | ||||
| struct ext4_fc_del_range { | ||||
| 	__le32 fc_ino; | ||||
| 	__le32 fc_lblk; | ||||
| 	__le32 fc_len; | ||||
| }; | ||||
| 
 | ||||
| /*
 | ||||
|  * This is the value structure for tags EXT4_FC_TAG_CREAT, EXT4_FC_TAG_LINK | ||||
|  * and EXT4_FC_TAG_UNLINK. | ||||
|  */ | ||||
| struct ext4_fc_dentry_info { | ||||
| 	__le32 fc_parent_ino; | ||||
| 	__le32 fc_ino; | ||||
| 	u8 fc_dname[0]; | ||||
| }; | ||||
| 
 | ||||
| /* Value structure for EXT4_FC_TAG_INODE and EXT4_FC_TAG_INODE_PARTIAL. */ | ||||
| struct ext4_fc_inode { | ||||
| 	__le32 fc_ino; | ||||
| 	__u8 fc_raw_inode[0]; | ||||
| }; | ||||
| 
 | ||||
| /* Value structure for tag EXT4_FC_TAG_TAIL. */ | ||||
| struct ext4_fc_tail { | ||||
| 	__le32 fc_tid; | ||||
| 	__le32 fc_crc; | ||||
| }; | ||||
| 
 | ||||
| /*
 | ||||
|  * In memory list of dentry updates that are performed on the file | ||||
|  * system used by fast commit code. | ||||
|  */ | ||||
| struct ext4_fc_dentry_update { | ||||
| 	int fcd_op;		/* Type of update create / unlink / link */ | ||||
| 	int fcd_parent;		/* Parent inode number */ | ||||
| 	int fcd_ino;		/* Inode number */ | ||||
| 	struct qstr fcd_name;	/* Dirent name */ | ||||
| 	unsigned char fcd_iname[DNAME_INLINE_LEN];	/* Dirent name string */ | ||||
| 	struct list_head fcd_list; | ||||
| }; | ||||
| 
 | ||||
| /*
 | ||||
|  * Fast commit reason codes | ||||
|  */ | ||||
| enum { | ||||
| 	/*
 | ||||
| 	 * Commit status codes: | ||||
| 	 */ | ||||
| 	EXT4_FC_REASON_OK = 0, | ||||
| 	EXT4_FC_REASON_INELIGIBLE, | ||||
| 	EXT4_FC_REASON_ALREADY_COMMITTED, | ||||
| 	EXT4_FC_REASON_FC_START_FAILED, | ||||
| 	EXT4_FC_REASON_FC_FAILED, | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Fast commit ineligiblity reasons: | ||||
| 	 */ | ||||
| 	EXT4_FC_REASON_XATTR = 0, | ||||
| 	EXT4_FC_REASON_CROSS_RENAME, | ||||
| 	EXT4_FC_REASON_JOURNAL_FLAG_CHANGE, | ||||
| 	EXT4_FC_REASON_MEM, | ||||
| 	EXT4_FC_REASON_SWAP_BOOT, | ||||
| 	EXT4_FC_REASON_RESIZE, | ||||
| 	EXT4_FC_REASON_RENAME_DIR, | ||||
| 	EXT4_FC_REASON_FALLOC_RANGE, | ||||
| 	EXT4_FC_COMMIT_FAILED, | ||||
| 	EXT4_FC_REASON_MAX | ||||
| }; | ||||
| 
 | ||||
| struct ext4_fc_stats { | ||||
| 	unsigned int fc_ineligible_reason_count[EXT4_FC_REASON_MAX]; | ||||
| 	unsigned long fc_num_commits; | ||||
| 	unsigned long fc_ineligible_commits; | ||||
| 	unsigned long fc_numblks; | ||||
| }; | ||||
| 
 | ||||
| #endif /* __FAST_COMMIT_H__ */ | ||||
|  |  | |||
|  | @ -260,6 +260,7 @@ static ssize_t ext4_buffered_write_iter(struct kiocb *iocb, | |||
| 	if (iocb->ki_flags & IOCB_NOWAIT) | ||||
| 		return -EOPNOTSUPP; | ||||
| 
 | ||||
| 	ext4_fc_start_update(inode); | ||||
| 	inode_lock(inode); | ||||
| 	ret = ext4_write_checks(iocb, from); | ||||
| 	if (ret <= 0) | ||||
|  | @ -271,6 +272,7 @@ static ssize_t ext4_buffered_write_iter(struct kiocb *iocb, | |||
| 
 | ||||
| out: | ||||
| 	inode_unlock(inode); | ||||
| 	ext4_fc_stop_update(inode); | ||||
| 	if (likely(ret > 0)) { | ||||
| 		iocb->ki_pos += ret; | ||||
| 		ret = generic_write_sync(iocb, ret); | ||||
|  | @ -534,7 +536,9 @@ static ssize_t ext4_dio_write_iter(struct kiocb *iocb, struct iov_iter *from) | |||
| 			goto out; | ||||
| 		} | ||||
| 
 | ||||
| 		ext4_fc_start_update(inode); | ||||
| 		ret = ext4_orphan_add(handle, inode); | ||||
| 		ext4_fc_stop_update(inode); | ||||
| 		if (ret) { | ||||
| 			ext4_journal_stop(handle); | ||||
| 			goto out; | ||||
|  | @ -656,7 +660,7 @@ ext4_file_write_iter(struct kiocb *iocb, struct iov_iter *from) | |||
| #endif | ||||
| 	if (iocb->ki_flags & IOCB_DIRECT) | ||||
| 		return ext4_dio_write_iter(iocb, from); | ||||
| 
 | ||||
| 	else | ||||
| 		return ext4_buffered_write_iter(iocb, from); | ||||
| } | ||||
| 
 | ||||
|  | @ -757,6 +761,7 @@ static int ext4_file_mmap(struct file *file, struct vm_area_struct *vma) | |||
| 	if (!daxdev_mapping_supported(vma, dax_dev)) | ||||
| 		return -EOPNOTSUPP; | ||||
| 
 | ||||
| 	ext4_fc_start_update(inode); | ||||
| 	file_accessed(file); | ||||
| 	if (IS_DAX(file_inode(file))) { | ||||
| 		vma->vm_ops = &ext4_dax_vm_ops; | ||||
|  | @ -764,6 +769,7 @@ static int ext4_file_mmap(struct file *file, struct vm_area_struct *vma) | |||
| 	} else { | ||||
| 		vma->vm_ops = &ext4_file_vm_ops; | ||||
| 	} | ||||
| 	ext4_fc_stop_update(inode); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -112,7 +112,7 @@ static int ext4_fsync_journal(struct inode *inode, bool datasync, | |||
| 	    !jbd2_trans_will_send_data_barrier(journal, commit_tid)) | ||||
| 		*needs_barrier = true; | ||||
| 
 | ||||
| 	return jbd2_complete_transaction(journal, commit_tid); | ||||
| 	return ext4_fc_commit(journal, commit_tid); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  |  | |||
|  | @ -729,6 +729,8 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode, | |||
| 			if (ret) | ||||
| 				return ret; | ||||
| 		} | ||||
| 		ext4_fc_track_range(inode, map->m_lblk, | ||||
| 			    map->m_lblk + map->m_len - 1); | ||||
| 	} | ||||
| 
 | ||||
| 	if (retval < 0) | ||||
|  | @ -3300,9 +3302,14 @@ static bool ext4_inode_datasync_dirty(struct inode *inode) | |||
| { | ||||
| 	journal_t *journal = EXT4_SB(inode->i_sb)->s_journal; | ||||
| 
 | ||||
| 	if (journal) | ||||
| 		return !jbd2_transaction_committed(journal, | ||||
| 					EXT4_I(inode)->i_datasync_tid); | ||||
| 	if (journal) { | ||||
| 		if (jbd2_transaction_committed(journal, | ||||
| 					EXT4_I(inode)->i_datasync_tid)) | ||||
| 			return true; | ||||
| 		return atomic_read(&EXT4_SB(inode->i_sb)->s_fc_subtid) >= | ||||
| 			EXT4_I(inode)->i_fc_committed_subtid; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Any metadata buffers to write? */ | ||||
| 	if (!list_empty(&inode->i_mapping->private_list)) | ||||
| 		return true; | ||||
|  | @ -4097,6 +4104,7 @@ int ext4_punch_hole(struct inode *inode, loff_t offset, loff_t length) | |||
| 
 | ||||
| 		up_write(&EXT4_I(inode)->i_data_sem); | ||||
| 	} | ||||
| 	ext4_fc_track_range(inode, first_block, stop_block); | ||||
| 	if (IS_SYNC(inode)) | ||||
| 		ext4_handle_sync(handle); | ||||
| 
 | ||||
|  | @ -4716,6 +4724,7 @@ struct inode *__ext4_iget(struct super_block *sb, unsigned long ino, | |||
| 	for (block = 0; block < EXT4_N_BLOCKS; block++) | ||||
| 		ei->i_data[block] = raw_inode->i_block[block]; | ||||
| 	INIT_LIST_HEAD(&ei->i_orphan); | ||||
| 	ext4_fc_init_inode(&ei->vfs_inode); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Set transaction id's of transactions that have to be committed | ||||
|  | @ -5162,7 +5171,7 @@ int ext4_write_inode(struct inode *inode, struct writeback_control *wbc) | |||
| 		if (wbc->sync_mode != WB_SYNC_ALL || wbc->for_sync) | ||||
| 			return 0; | ||||
| 
 | ||||
| 		err = jbd2_complete_transaction(EXT4_SB(inode->i_sb)->s_journal, | ||||
| 		err = ext4_fc_commit(EXT4_SB(inode->i_sb)->s_journal, | ||||
| 						EXT4_I(inode)->i_sync_tid); | ||||
| 	} else { | ||||
| 		struct ext4_iloc iloc; | ||||
|  | @ -5291,6 +5300,7 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr) | |||
| 		if (error) | ||||
| 			return error; | ||||
| 	} | ||||
| 	ext4_fc_start_update(inode); | ||||
| 	if ((ia_valid & ATTR_UID && !uid_eq(attr->ia_uid, inode->i_uid)) || | ||||
| 	    (ia_valid & ATTR_GID && !gid_eq(attr->ia_gid, inode->i_gid))) { | ||||
| 		handle_t *handle; | ||||
|  | @ -5314,6 +5324,7 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr) | |||
| 
 | ||||
| 		if (error) { | ||||
| 			ext4_journal_stop(handle); | ||||
| 			ext4_fc_stop_update(inode); | ||||
| 			return error; | ||||
| 		} | ||||
| 		/* Update corresponding info in inode so that everything is in
 | ||||
|  | @ -5336,11 +5347,15 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr) | |||
| 		if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))) { | ||||
| 			struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); | ||||
| 
 | ||||
| 			if (attr->ia_size > sbi->s_bitmap_maxbytes) | ||||
| 			if (attr->ia_size > sbi->s_bitmap_maxbytes) { | ||||
| 				ext4_fc_stop_update(inode); | ||||
| 				return -EFBIG; | ||||
| 			} | ||||
| 		if (!S_ISREG(inode->i_mode)) | ||||
| 		} | ||||
| 		if (!S_ISREG(inode->i_mode)) { | ||||
| 			ext4_fc_stop_update(inode); | ||||
| 			return -EINVAL; | ||||
| 		} | ||||
| 
 | ||||
| 		if (IS_I_VERSION(inode) && attr->ia_size != inode->i_size) | ||||
| 			inode_inc_iversion(inode); | ||||
|  | @ -5364,7 +5379,7 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr) | |||
| 		rc = ext4_break_layouts(inode); | ||||
| 		if (rc) { | ||||
| 			up_write(&EXT4_I(inode)->i_mmap_sem); | ||||
| 			return rc; | ||||
| 			goto err_out; | ||||
| 		} | ||||
| 
 | ||||
| 		if (attr->ia_size != inode->i_size) { | ||||
|  | @ -5385,6 +5400,21 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr) | |||
| 				inode->i_mtime = current_time(inode); | ||||
| 				inode->i_ctime = inode->i_mtime; | ||||
| 			} | ||||
| 
 | ||||
| 			if (shrink) | ||||
| 				ext4_fc_track_range(inode, | ||||
| 					(attr->ia_size > 0 ? attr->ia_size - 1 : 0) >> | ||||
| 					inode->i_sb->s_blocksize_bits, | ||||
| 					(oldsize > 0 ? oldsize - 1 : 0) >> | ||||
| 					inode->i_sb->s_blocksize_bits); | ||||
| 			else | ||||
| 				ext4_fc_track_range( | ||||
| 					inode, | ||||
| 					(oldsize > 0 ? oldsize - 1 : oldsize) >> | ||||
| 					inode->i_sb->s_blocksize_bits, | ||||
| 					(attr->ia_size > 0 ? attr->ia_size - 1 : 0) >> | ||||
| 					inode->i_sb->s_blocksize_bits); | ||||
| 
 | ||||
| 			down_write(&EXT4_I(inode)->i_data_sem); | ||||
| 			EXT4_I(inode)->i_disksize = attr->ia_size; | ||||
| 			rc = ext4_mark_inode_dirty(handle, inode); | ||||
|  | @ -5443,9 +5473,11 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr) | |||
| 		rc = posix_acl_chmod(inode, inode->i_mode); | ||||
| 
 | ||||
| err_out: | ||||
| 	if  (error) | ||||
| 		ext4_std_error(inode->i_sb, error); | ||||
| 	if (!error) | ||||
| 		error = rc; | ||||
| 	ext4_fc_stop_update(inode); | ||||
| 	return error; | ||||
| } | ||||
| 
 | ||||
|  | @ -5627,6 +5659,8 @@ int ext4_mark_iloc_dirty(handle_t *handle, | |||
| 		put_bh(iloc->bh); | ||||
| 		return -EIO; | ||||
| 	} | ||||
| 	ext4_fc_track_inode(inode); | ||||
| 
 | ||||
| 	if (IS_I_VERSION(inode)) | ||||
| 		inode_inc_iversion(inode); | ||||
| 
 | ||||
|  | @ -5950,6 +5984,8 @@ int ext4_change_inode_journal_flag(struct inode *inode, int val) | |||
| 	if (IS_ERR(handle)) | ||||
| 		return PTR_ERR(handle); | ||||
| 
 | ||||
| 	ext4_fc_mark_ineligible(inode->i_sb, | ||||
| 		EXT4_FC_REASON_JOURNAL_FLAG_CHANGE); | ||||
| 	err = ext4_mark_inode_dirty(handle, inode); | ||||
| 	ext4_handle_sync(handle); | ||||
| 	ext4_journal_stop(handle); | ||||
|  |  | |||
|  | @ -165,6 +165,7 @@ static long swap_inode_boot_loader(struct super_block *sb, | |||
| 		err = -EINVAL; | ||||
| 		goto err_out; | ||||
| 	} | ||||
| 	ext4_fc_start_ineligible(sb, EXT4_FC_REASON_SWAP_BOOT); | ||||
| 
 | ||||
| 	/* Protect extent tree against block allocations via delalloc */ | ||||
| 	ext4_double_down_write_data_sem(inode, inode_bl); | ||||
|  | @ -247,6 +248,7 @@ static long swap_inode_boot_loader(struct super_block *sb, | |||
| 
 | ||||
| err_out1: | ||||
| 	ext4_journal_stop(handle); | ||||
| 	ext4_fc_stop_ineligible(sb); | ||||
| 	ext4_double_up_write_data_sem(inode, inode_bl); | ||||
| 
 | ||||
| err_out: | ||||
|  | @ -807,7 +809,7 @@ static int ext4_ioctl_get_es_cache(struct file *filp, unsigned long arg) | |||
| 	return error; | ||||
| } | ||||
| 
 | ||||
| long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) | ||||
| static long __ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) | ||||
| { | ||||
| 	struct inode *inode = file_inode(filp); | ||||
| 	struct super_block *sb = inode->i_sb; | ||||
|  | @ -1074,6 +1076,7 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) | |||
| 
 | ||||
| 		err = ext4_resize_fs(sb, n_blocks_count); | ||||
| 		if (EXT4_SB(sb)->s_journal) { | ||||
| 			ext4_fc_mark_ineligible(sb, EXT4_FC_REASON_RESIZE); | ||||
| 			jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal); | ||||
| 			err2 = jbd2_journal_flush(EXT4_SB(sb)->s_journal); | ||||
| 			jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal); | ||||
|  | @ -1308,6 +1311,17 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) | ||||
| { | ||||
| 	long ret; | ||||
| 
 | ||||
| 	ext4_fc_start_update(file_inode(filp)); | ||||
| 	ret = __ext4_ioctl(filp, cmd, arg); | ||||
| 	ext4_fc_stop_update(file_inode(filp)); | ||||
| 
 | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| #ifdef CONFIG_COMPAT | ||||
| long ext4_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | ||||
| { | ||||
|  |  | |||
|  | @ -2611,7 +2611,7 @@ static int ext4_create(struct inode *dir, struct dentry *dentry, umode_t mode, | |||
| 		       bool excl) | ||||
| { | ||||
| 	handle_t *handle; | ||||
| 	struct inode *inode; | ||||
| 	struct inode *inode, *inode_save; | ||||
| 	int err, credits, retries = 0; | ||||
| 
 | ||||
| 	err = dquot_initialize(dir); | ||||
|  | @ -2629,7 +2629,11 @@ static int ext4_create(struct inode *dir, struct dentry *dentry, umode_t mode, | |||
| 		inode->i_op = &ext4_file_inode_operations; | ||||
| 		inode->i_fop = &ext4_file_operations; | ||||
| 		ext4_set_aops(inode); | ||||
| 		inode_save = inode; | ||||
| 		ihold(inode_save); | ||||
| 		err = ext4_add_nondir(handle, dentry, &inode); | ||||
| 		ext4_fc_track_create(inode_save, dentry); | ||||
| 		iput(inode_save); | ||||
| 	} | ||||
| 	if (handle) | ||||
| 		ext4_journal_stop(handle); | ||||
|  | @ -2644,7 +2648,7 @@ static int ext4_mknod(struct inode *dir, struct dentry *dentry, | |||
| 		      umode_t mode, dev_t rdev) | ||||
| { | ||||
| 	handle_t *handle; | ||||
| 	struct inode *inode; | ||||
| 	struct inode *inode, *inode_save; | ||||
| 	int err, credits, retries = 0; | ||||
| 
 | ||||
| 	err = dquot_initialize(dir); | ||||
|  | @ -2661,7 +2665,12 @@ static int ext4_mknod(struct inode *dir, struct dentry *dentry, | |||
| 	if (!IS_ERR(inode)) { | ||||
| 		init_special_inode(inode, inode->i_mode, rdev); | ||||
| 		inode->i_op = &ext4_special_inode_operations; | ||||
| 		inode_save = inode; | ||||
| 		ihold(inode_save); | ||||
| 		err = ext4_add_nondir(handle, dentry, &inode); | ||||
| 		if (!err) | ||||
| 			ext4_fc_track_create(inode_save, dentry); | ||||
| 		iput(inode_save); | ||||
| 	} | ||||
| 	if (handle) | ||||
| 		ext4_journal_stop(handle); | ||||
|  | @ -2825,7 +2834,9 @@ static int ext4_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) | |||
| 		iput(inode); | ||||
| 		goto out_retry; | ||||
| 	} | ||||
| 	ext4_fc_track_create(inode, dentry); | ||||
| 	ext4_inc_count(dir); | ||||
| 
 | ||||
| 	ext4_update_dx_flag(dir); | ||||
| 	err = ext4_mark_inode_dirty(handle, dir); | ||||
| 	if (err) | ||||
|  | @ -3165,6 +3176,7 @@ static int ext4_rmdir(struct inode *dir, struct dentry *dentry) | |||
| 		goto end_rmdir; | ||||
| 	ext4_dec_count(dir); | ||||
| 	ext4_update_dx_flag(dir); | ||||
| 	ext4_fc_track_unlink(inode, dentry); | ||||
| 	retval = ext4_mark_inode_dirty(handle, dir); | ||||
| 
 | ||||
| #ifdef CONFIG_UNICODE | ||||
|  | @ -3251,6 +3263,8 @@ static int ext4_unlink(struct inode *dir, struct dentry *dentry) | |||
| 	inode->i_ctime = current_time(inode); | ||||
| 	retval = ext4_mark_inode_dirty(handle, inode); | ||||
| 
 | ||||
| 	if (!retval) | ||||
| 		ext4_fc_track_unlink(d_inode(dentry), dentry); | ||||
| #ifdef CONFIG_UNICODE | ||||
| 	/* VFS negative dentries are incompatible with Encoding and
 | ||||
| 	 * Case-insensitiveness. Eventually we'll want avoid | ||||
|  | @ -3872,6 +3886,22 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
| 	retval = ext4_mark_inode_dirty(handle, old.dir); | ||||
| 	if (unlikely(retval)) | ||||
| 		goto end_rename; | ||||
| 
 | ||||
| 	if (S_ISDIR(old.inode->i_mode)) { | ||||
| 		/*
 | ||||
| 		 * We disable fast commits here that's because the | ||||
| 		 * replay code is not yet capable of changing dot dot | ||||
| 		 * dirents in directories. | ||||
| 		 */ | ||||
| 		ext4_fc_mark_ineligible(old.inode->i_sb, | ||||
| 			EXT4_FC_REASON_RENAME_DIR); | ||||
| 	} else { | ||||
| 		if (new.inode) | ||||
| 			ext4_fc_track_unlink(new.inode, new.dentry); | ||||
| 		ext4_fc_track_link(old.inode, new.dentry); | ||||
| 		ext4_fc_track_unlink(old.inode, old.dentry); | ||||
| 	} | ||||
| 
 | ||||
| 	if (new.inode) { | ||||
| 		retval = ext4_mark_inode_dirty(handle, new.inode); | ||||
| 		if (unlikely(retval)) | ||||
|  | @ -4015,7 +4045,8 @@ static int ext4_cross_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
| 	retval = ext4_mark_inode_dirty(handle, new.inode); | ||||
| 	if (unlikely(retval)) | ||||
| 		goto end_rename; | ||||
| 
 | ||||
| 	ext4_fc_mark_ineligible(new.inode->i_sb, | ||||
| 				EXT4_FC_REASON_CROSS_RENAME); | ||||
| 	if (old.dir_bh) { | ||||
| 		retval = ext4_rename_dir_finish(handle, &old, new.dir->i_ino); | ||||
| 		if (retval) | ||||
|  |  | |||
|  | @ -1331,6 +1331,8 @@ static struct inode *ext4_alloc_inode(struct super_block *sb) | |||
| 	ei->i_datasync_tid = 0; | ||||
| 	atomic_set(&ei->i_unwritten, 0); | ||||
| 	INIT_WORK(&ei->i_rsv_conversion_work, ext4_end_io_rsv_work); | ||||
| 	ext4_fc_init_inode(&ei->vfs_inode); | ||||
| 	mutex_init(&ei->i_fc_lock); | ||||
| 	return &ei->vfs_inode; | ||||
| } | ||||
| 
 | ||||
|  | @ -1348,6 +1350,10 @@ static int ext4_drop_inode(struct inode *inode) | |||
| static void ext4_free_in_core_inode(struct inode *inode) | ||||
| { | ||||
| 	fscrypt_free_inode(inode); | ||||
| 	if (!list_empty(&(EXT4_I(inode)->i_fc_list))) { | ||||
| 		pr_warn("%s: inode %ld still in fc list", | ||||
| 			__func__, inode->i_ino); | ||||
| 	} | ||||
| 	kmem_cache_free(ext4_inode_cachep, EXT4_I(inode)); | ||||
| } | ||||
| 
 | ||||
|  | @ -1373,6 +1379,7 @@ static void init_once(void *foo) | |||
| 	init_rwsem(&ei->i_data_sem); | ||||
| 	init_rwsem(&ei->i_mmap_sem); | ||||
| 	inode_init_once(&ei->vfs_inode); | ||||
| 	ext4_fc_init_inode(&ei->vfs_inode); | ||||
| } | ||||
| 
 | ||||
| static int __init init_inodecache(void) | ||||
|  | @ -1401,6 +1408,7 @@ static void destroy_inodecache(void) | |||
| 
 | ||||
| void ext4_clear_inode(struct inode *inode) | ||||
| { | ||||
| 	ext4_fc_del(inode); | ||||
| 	invalidate_inode_buffers(inode); | ||||
| 	clear_inode(inode); | ||||
| 	ext4_discard_preallocations(inode, 0); | ||||
|  | @ -4744,6 +4752,19 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) | |||
| 	INIT_LIST_HEAD(&sbi->s_orphan); /* unlinked but open files */ | ||||
| 	mutex_init(&sbi->s_orphan_lock); | ||||
| 
 | ||||
| 	/* Initialize fast commit stuff */ | ||||
| 	atomic_set(&sbi->s_fc_subtid, 0); | ||||
| 	atomic_set(&sbi->s_fc_ineligible_updates, 0); | ||||
| 	INIT_LIST_HEAD(&sbi->s_fc_q[FC_Q_MAIN]); | ||||
| 	INIT_LIST_HEAD(&sbi->s_fc_q[FC_Q_STAGING]); | ||||
| 	INIT_LIST_HEAD(&sbi->s_fc_dentry_q[FC_Q_MAIN]); | ||||
| 	INIT_LIST_HEAD(&sbi->s_fc_dentry_q[FC_Q_STAGING]); | ||||
| 	sbi->s_fc_bytes = 0; | ||||
| 	sbi->s_mount_state &= ~EXT4_FC_INELIGIBLE; | ||||
| 	sbi->s_mount_state &= ~EXT4_FC_COMMITTING; | ||||
| 	spin_lock_init(&sbi->s_fc_lock); | ||||
| 	memset(&sbi->s_fc_stats, 0, sizeof(sbi->s_fc_stats)); | ||||
| 
 | ||||
| 	sb->s_root = NULL; | ||||
| 
 | ||||
| 	needs_recovery = (es->s_last_orphan != 0 || | ||||
|  | @ -6515,6 +6536,10 @@ static ssize_t ext4_quota_write(struct super_block *sb, int type, | |||
| 	brelse(bh); | ||||
| out: | ||||
| 	if (inode->i_size < off + len) { | ||||
| 		ext4_fc_track_range(inode, | ||||
| 			(inode->i_size > 0 ? inode->i_size - 1 : 0) | ||||
| 				>> inode->i_sb->s_blocksize_bits, | ||||
| 			(off + len) >> inode->i_sb->s_blocksize_bits); | ||||
| 		i_size_write(inode, off + len); | ||||
| 		EXT4_I(inode)->i_disksize = inode->i_size; | ||||
| 		err2 = ext4_mark_inode_dirty(handle, inode); | ||||
|  | @ -6643,6 +6668,11 @@ static int __init ext4_init_fs(void) | |||
| 	err = init_inodecache(); | ||||
| 	if (err) | ||||
| 		goto out1; | ||||
| 
 | ||||
| 	err = ext4_fc_init_dentry_cache(); | ||||
| 	if (err) | ||||
| 		goto out05; | ||||
| 
 | ||||
| 	register_as_ext3(); | ||||
| 	register_as_ext2(); | ||||
| 	err = register_filesystem(&ext4_fs_type); | ||||
|  | @ -6653,6 +6683,7 @@ static int __init ext4_init_fs(void) | |||
| out: | ||||
| 	unregister_as_ext2(); | ||||
| 	unregister_as_ext3(); | ||||
| out05: | ||||
| 	destroy_inodecache(); | ||||
| out1: | ||||
| 	ext4_exit_mballoc(); | ||||
|  |  | |||
|  | @ -2419,6 +2419,7 @@ ext4_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index, | |||
| 		if (IS_SYNC(inode)) | ||||
| 			ext4_handle_sync(handle); | ||||
| 	} | ||||
| 	ext4_fc_mark_ineligible(inode->i_sb, EXT4_FC_REASON_XATTR); | ||||
| 
 | ||||
| cleanup: | ||||
| 	brelse(is.iloc.bh); | ||||
|  | @ -2496,6 +2497,7 @@ ext4_xattr_set(struct inode *inode, int name_index, const char *name, | |||
| 		if (error == 0) | ||||
| 			error = error2; | ||||
| 	} | ||||
| 	ext4_fc_mark_ineligible(inode->i_sb, EXT4_FC_REASON_XATTR); | ||||
| 
 | ||||
| 	return error; | ||||
| } | ||||
|  | @ -2928,6 +2930,7 @@ int ext4_xattr_delete_inode(handle_t *handle, struct inode *inode, | |||
| 					 error); | ||||
| 			goto cleanup; | ||||
| 		} | ||||
| 		ext4_fc_mark_ineligible(inode->i_sb, EXT4_FC_REASON_XATTR); | ||||
| 	} | ||||
| 	error = 0; | ||||
| cleanup: | ||||
|  |  | |||
|  | @ -95,6 +95,16 @@ TRACE_DEFINE_ENUM(ES_REFERENCED_B); | |||
| 	{ FALLOC_FL_COLLAPSE_RANGE,	"COLLAPSE_RANGE"},	\ | ||||
| 	{ FALLOC_FL_ZERO_RANGE,		"ZERO_RANGE"}) | ||||
| 
 | ||||
| #define show_fc_reason(reason)						\ | ||||
| 	__print_symbolic(reason,					\ | ||||
| 		{ EXT4_FC_REASON_XATTR,		"XATTR"},		\ | ||||
| 		{ EXT4_FC_REASON_CROSS_RENAME,	"CROSS_RENAME"},	\ | ||||
| 		{ EXT4_FC_REASON_JOURNAL_FLAG_CHANGE, "JOURNAL_FLAG_CHANGE"}, \ | ||||
| 		{ EXT4_FC_REASON_MEM,	"NO_MEM"},			\ | ||||
| 		{ EXT4_FC_REASON_SWAP_BOOT,	"SWAP_BOOT"},		\ | ||||
| 		{ EXT4_FC_REASON_RESIZE,	"RESIZE"},		\ | ||||
| 		{ EXT4_FC_REASON_RENAME_DIR,	"RENAME_DIR"},		\ | ||||
| 		{ EXT4_FC_REASON_FALLOC_RANGE,	"FALLOC_RANGE"}) | ||||
| 
 | ||||
| TRACE_EVENT(ext4_other_inode_update_time, | ||||
| 	TP_PROTO(struct inode *inode, ino_t orig_ino), | ||||
|  | @ -2791,6 +2801,168 @@ TRACE_EVENT(ext4_lazy_itable_init, | |||
| 		  MAJOR(__entry->dev), MINOR(__entry->dev), __entry->group) | ||||
| ); | ||||
| 
 | ||||
| TRACE_EVENT(ext4_fc_commit_start, | ||||
| 	TP_PROTO(struct super_block *sb), | ||||
| 
 | ||||
| 	TP_ARGS(sb), | ||||
| 
 | ||||
| 	TP_STRUCT__entry( | ||||
| 		__field(dev_t, dev) | ||||
| 	), | ||||
| 
 | ||||
| 	TP_fast_assign( | ||||
| 		__entry->dev = sb->s_dev; | ||||
| 	), | ||||
| 
 | ||||
| 	TP_printk("fast_commit started on dev %d,%d", | ||||
| 		  MAJOR(__entry->dev), MINOR(__entry->dev)) | ||||
| ); | ||||
| 
 | ||||
| TRACE_EVENT(ext4_fc_commit_stop, | ||||
| 	    TP_PROTO(struct super_block *sb, int nblks, int reason), | ||||
| 
 | ||||
| 	TP_ARGS(sb, nblks, reason), | ||||
| 
 | ||||
| 	TP_STRUCT__entry( | ||||
| 		__field(dev_t, dev) | ||||
| 		__field(int, nblks) | ||||
| 		__field(int, reason) | ||||
| 		__field(int, num_fc) | ||||
| 		__field(int, num_fc_ineligible) | ||||
| 		__field(int, nblks_agg) | ||||
| 	), | ||||
| 
 | ||||
| 	TP_fast_assign( | ||||
| 		__entry->dev = sb->s_dev; | ||||
| 		__entry->nblks = nblks; | ||||
| 		__entry->reason = reason; | ||||
| 		__entry->num_fc = EXT4_SB(sb)->s_fc_stats.fc_num_commits; | ||||
| 		__entry->num_fc_ineligible = | ||||
| 			EXT4_SB(sb)->s_fc_stats.fc_ineligible_commits; | ||||
| 		__entry->nblks_agg = EXT4_SB(sb)->s_fc_stats.fc_numblks; | ||||
| 	), | ||||
| 
 | ||||
| 	TP_printk("fc on [%d,%d] nblks %d, reason %d, fc = %d, ineligible = %d, agg_nblks %d", | ||||
| 		  MAJOR(__entry->dev), MINOR(__entry->dev), | ||||
| 		  __entry->nblks, __entry->reason, __entry->num_fc, | ||||
| 		  __entry->num_fc_ineligible, __entry->nblks_agg) | ||||
| ); | ||||
| 
 | ||||
| #define FC_REASON_NAME_STAT(reason)					\ | ||||
| 	show_fc_reason(reason),						\ | ||||
| 	__entry->sbi->s_fc_stats.fc_ineligible_reason_count[reason] | ||||
| 
 | ||||
| TRACE_EVENT(ext4_fc_stats, | ||||
| 	    TP_PROTO(struct super_block *sb), | ||||
| 
 | ||||
| 	    TP_ARGS(sb), | ||||
| 
 | ||||
| 	    TP_STRUCT__entry( | ||||
| 		    __field(dev_t, dev) | ||||
| 		    __field(struct ext4_sb_info *, sbi) | ||||
| 		    __field(int, count) | ||||
| 		    ), | ||||
| 
 | ||||
| 	    TP_fast_assign( | ||||
| 		    __entry->dev = sb->s_dev; | ||||
| 		    __entry->sbi = EXT4_SB(sb); | ||||
| 		    ), | ||||
| 
 | ||||
| 	    TP_printk("dev %d:%d fc ineligible reasons:\n" | ||||
| 		      "%s:%d, %s:%d, %s:%d, %s:%d, %s:%d, %s:%d, %s:%d, %s,%d; " | ||||
| 		      "num_commits:%ld, ineligible: %ld, numblks: %ld", | ||||
| 		      MAJOR(__entry->dev), MINOR(__entry->dev), | ||||
| 		      FC_REASON_NAME_STAT(EXT4_FC_REASON_XATTR), | ||||
| 		      FC_REASON_NAME_STAT(EXT4_FC_REASON_CROSS_RENAME), | ||||
| 		      FC_REASON_NAME_STAT(EXT4_FC_REASON_JOURNAL_FLAG_CHANGE), | ||||
| 		      FC_REASON_NAME_STAT(EXT4_FC_REASON_MEM), | ||||
| 		      FC_REASON_NAME_STAT(EXT4_FC_REASON_SWAP_BOOT), | ||||
| 		      FC_REASON_NAME_STAT(EXT4_FC_REASON_RESIZE), | ||||
| 		      FC_REASON_NAME_STAT(EXT4_FC_REASON_RENAME_DIR), | ||||
| 		      FC_REASON_NAME_STAT(EXT4_FC_REASON_FALLOC_RANGE), | ||||
| 		      __entry->sbi->s_fc_stats.fc_num_commits, | ||||
| 		      __entry->sbi->s_fc_stats.fc_ineligible_commits, | ||||
| 		      __entry->sbi->s_fc_stats.fc_numblks) | ||||
| 
 | ||||
| ); | ||||
| 
 | ||||
| #define DEFINE_TRACE_DENTRY_EVENT(__type)				\ | ||||
| 	TRACE_EVENT(ext4_fc_track_##__type,				\ | ||||
| 	    TP_PROTO(struct inode *inode, struct dentry *dentry, int ret), \ | ||||
| 									\ | ||||
| 	    TP_ARGS(inode, dentry, ret),				\ | ||||
| 									\ | ||||
| 	    TP_STRUCT__entry(						\ | ||||
| 		    __field(dev_t, dev)					\ | ||||
| 		    __field(int, ino)					\ | ||||
| 		    __field(int, error)					\ | ||||
| 		    ),							\ | ||||
| 									\ | ||||
| 	    TP_fast_assign(						\ | ||||
| 		    __entry->dev = inode->i_sb->s_dev;			\ | ||||
| 		    __entry->ino = inode->i_ino;			\ | ||||
| 		    __entry->error = ret;				\ | ||||
| 		    ),							\ | ||||
| 									\ | ||||
| 	    TP_printk("dev %d:%d, inode %d, error %d, fc_%s",		\ | ||||
| 		      MAJOR(__entry->dev), MINOR(__entry->dev),		\ | ||||
| 		      __entry->ino, __entry->error,			\ | ||||
| 		      #__type)						\ | ||||
| 	) | ||||
| 
 | ||||
| DEFINE_TRACE_DENTRY_EVENT(create); | ||||
| DEFINE_TRACE_DENTRY_EVENT(link); | ||||
| DEFINE_TRACE_DENTRY_EVENT(unlink); | ||||
| 
 | ||||
| TRACE_EVENT(ext4_fc_track_inode, | ||||
| 	    TP_PROTO(struct inode *inode, int ret), | ||||
| 
 | ||||
| 	    TP_ARGS(inode, ret), | ||||
| 
 | ||||
| 	    TP_STRUCT__entry( | ||||
| 		    __field(dev_t, dev) | ||||
| 		    __field(int, ino) | ||||
| 		    __field(int, error) | ||||
| 		    ), | ||||
| 
 | ||||
| 	    TP_fast_assign( | ||||
| 		    __entry->dev = inode->i_sb->s_dev; | ||||
| 		    __entry->ino = inode->i_ino; | ||||
| 		    __entry->error = ret; | ||||
| 		    ), | ||||
| 
 | ||||
| 	    TP_printk("dev %d:%d, inode %d, error %d", | ||||
| 		      MAJOR(__entry->dev), MINOR(__entry->dev), | ||||
| 		      __entry->ino, __entry->error) | ||||
| 	); | ||||
| 
 | ||||
| TRACE_EVENT(ext4_fc_track_range, | ||||
| 	    TP_PROTO(struct inode *inode, long start, long end, int ret), | ||||
| 
 | ||||
| 	    TP_ARGS(inode, start, end, ret), | ||||
| 
 | ||||
| 	    TP_STRUCT__entry( | ||||
| 		    __field(dev_t, dev) | ||||
| 		    __field(int, ino) | ||||
| 		    __field(long, start) | ||||
| 		    __field(long, end) | ||||
| 		    __field(int, error) | ||||
| 		    ), | ||||
| 
 | ||||
| 	    TP_fast_assign( | ||||
| 		    __entry->dev = inode->i_sb->s_dev; | ||||
| 		    __entry->ino = inode->i_ino; | ||||
| 		    __entry->start = start; | ||||
| 		    __entry->end = end; | ||||
| 		    __entry->error = ret; | ||||
| 		    ), | ||||
| 
 | ||||
| 	    TP_printk("dev %d:%d, inode %d, error %d, start %ld, end %ld", | ||||
| 		      MAJOR(__entry->dev), MINOR(__entry->dev), | ||||
| 		      __entry->ino, __entry->error, __entry->start, | ||||
| 		      __entry->end) | ||||
| 	); | ||||
| 
 | ||||
| #endif /* _TRACE_EXT4_H */ | ||||
| 
 | ||||
| /* This part must be outside protection */ | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Harshad Shirwadkar
						Harshad Shirwadkar