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);
 | 
						handle = ext4_journal_start(inode, EXT4_HT_XATTR, credits);
 | 
				
			||||||
	if (IS_ERR(handle))
 | 
						if (IS_ERR(handle))
 | 
				
			||||||
		return PTR_ERR(handle);
 | 
							return PTR_ERR(handle);
 | 
				
			||||||
 | 
						ext4_fc_start_update(inode);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ((type == ACL_TYPE_ACCESS) && acl) {
 | 
						if ((type == ACL_TYPE_ACCESS) && acl) {
 | 
				
			||||||
		error = posix_acl_update_mode(inode, &mode, &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:
 | 
					out_stop:
 | 
				
			||||||
	ext4_journal_stop(handle);
 | 
						ext4_journal_stop(handle);
 | 
				
			||||||
 | 
						ext4_fc_stop_update(inode);
 | 
				
			||||||
	if (error == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries))
 | 
						if (error == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries))
 | 
				
			||||||
		goto retry;
 | 
							goto retry;
 | 
				
			||||||
	return error;
 | 
						return error;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1021,6 +1021,31 @@ struct ext4_inode_info {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct list_head i_orphan;	/* unlinked but open inodes */
 | 
						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
 | 
						 * 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
 | 
						 * 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_VALID_FS			0x0001	/* Unmounted cleanly */
 | 
				
			||||||
#define	EXT4_ERROR_FS			0x0002	/* Errors detected */
 | 
					#define	EXT4_ERROR_FS			0x0002	/* Errors detected */
 | 
				
			||||||
#define	EXT4_ORPHAN_FS			0x0004	/* Orphans being recovered */
 | 
					#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
 | 
					 * Misc. filesystem flags
 | 
				
			||||||
| 
						 | 
					@ -1613,6 +1642,30 @@ struct ext4_sb_info {
 | 
				
			||||||
	/* Record the errseq of the backing block device */
 | 
						/* Record the errseq of the backing block device */
 | 
				
			||||||
	errseq_t s_bdev_wb_err;
 | 
						errseq_t s_bdev_wb_err;
 | 
				
			||||||
	spinlock_t s_bdev_wb_lock;
 | 
						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)
 | 
					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_EXT_PRECACHED,	/* extents have been precached */
 | 
				
			||||||
	EXT4_STATE_LUSTRE_EA_INODE,	/* Lustre-style ea_inode */
 | 
						EXT4_STATE_LUSTRE_EA_INODE,	/* Lustre-style ea_inode */
 | 
				
			||||||
	EXT4_STATE_VERITY_IN_PROGRESS,	/* building fs-verity Merkle tree */
 | 
						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)				\
 | 
					#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 */
 | 
					/* fast_commit.c */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ext4_fc_init(struct super_block *sb, journal_t *journal);
 | 
					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 */
 | 
					/* mballoc.c */
 | 
				
			||||||
extern const struct seq_operations ext4_mb_seq_groups_ops;
 | 
					extern const struct seq_operations ext4_mb_seq_groups_ops;
 | 
				
			||||||
extern long ext4_mb_stats;
 | 
					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);
 | 
						err = ext4_ext_dirty(handle, inode, path + path->p_depth);
 | 
				
			||||||
out:
 | 
					out:
 | 
				
			||||||
	ext4_ext_show_leaf(inode, path);
 | 
						ext4_ext_show_leaf(inode, path);
 | 
				
			||||||
 | 
						ext4_fc_track_range(inode, ee_block, ee_block + ee_len - 1);
 | 
				
			||||||
	return err;
 | 
						return err;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3794,6 +3795,7 @@ convert_initialized_extent(handle_t *handle, struct inode *inode,
 | 
				
			||||||
	if (*allocated > map->m_len)
 | 
						if (*allocated > map->m_len)
 | 
				
			||||||
		*allocated = map->m_len;
 | 
							*allocated = map->m_len;
 | 
				
			||||||
	map->m_len = *allocated;
 | 
						map->m_len = *allocated;
 | 
				
			||||||
 | 
						ext4_fc_track_range(inode, ee_block, ee_block + ee_len - 1);
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4327,7 +4329,7 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
 | 
				
			||||||
	map->m_len = ar.len;
 | 
						map->m_len = ar.len;
 | 
				
			||||||
	allocated = map->m_len;
 | 
						allocated = map->m_len;
 | 
				
			||||||
	ext4_ext_show_leaf(inode, path);
 | 
						ext4_ext_show_leaf(inode, path);
 | 
				
			||||||
 | 
						ext4_fc_track_range(inode, map->m_lblk, map->m_lblk + map->m_len - 1);
 | 
				
			||||||
out:
 | 
					out:
 | 
				
			||||||
	ext4_ext_drop_refs(path);
 | 
						ext4_ext_drop_refs(path);
 | 
				
			||||||
	kfree(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);
 | 
						ret = ext4_mark_inode_dirty(handle, inode);
 | 
				
			||||||
	if (unlikely(ret))
 | 
						if (unlikely(ret))
 | 
				
			||||||
		goto out_handle;
 | 
							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 */
 | 
						/* Zero out partial block at the edges of the range */
 | 
				
			||||||
	ret = ext4_zero_partial_blocks(handle, inode, offset, len);
 | 
						ret = ext4_zero_partial_blocks(handle, inode, offset, len);
 | 
				
			||||||
	if (ret >= 0)
 | 
						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_COLLAPSE_RANGE | FALLOC_FL_ZERO_RANGE |
 | 
				
			||||||
		     FALLOC_FL_INSERT_RANGE))
 | 
							     FALLOC_FL_INSERT_RANGE))
 | 
				
			||||||
		return -EOPNOTSUPP;
 | 
							return -EOPNOTSUPP;
 | 
				
			||||||
 | 
						ext4_fc_track_range(inode, offset >> blkbits,
 | 
				
			||||||
 | 
								(offset + len - 1) >> blkbits);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (mode & FALLOC_FL_PUNCH_HOLE)
 | 
						ext4_fc_start_update(inode);
 | 
				
			||||||
		return ext4_punch_hole(inode, offset, len);
 | 
					
 | 
				
			||||||
 | 
						if (mode & FALLOC_FL_PUNCH_HOLE) {
 | 
				
			||||||
 | 
							ret = ext4_punch_hole(inode, offset, len);
 | 
				
			||||||
 | 
							goto exit;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret = ext4_convert_inline_data(inode);
 | 
						ret = ext4_convert_inline_data(inode);
 | 
				
			||||||
	if (ret)
 | 
						if (ret)
 | 
				
			||||||
		return ret;
 | 
							goto exit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (mode & FALLOC_FL_COLLAPSE_RANGE)
 | 
						if (mode & FALLOC_FL_COLLAPSE_RANGE) {
 | 
				
			||||||
		return ext4_collapse_range(inode, offset, len);
 | 
							ret = ext4_collapse_range(inode, offset, len);
 | 
				
			||||||
 | 
							goto exit;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (mode & FALLOC_FL_INSERT_RANGE)
 | 
						if (mode & FALLOC_FL_INSERT_RANGE) {
 | 
				
			||||||
		return ext4_insert_range(inode, offset, len);
 | 
							ret = ext4_insert_range(inode, offset, len);
 | 
				
			||||||
 | 
							goto exit;
 | 
				
			||||||
	if (mode & FALLOC_FL_ZERO_RANGE)
 | 
						}
 | 
				
			||||||
		return ext4_zero_range(file, offset, len, mode);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (mode & FALLOC_FL_ZERO_RANGE) {
 | 
				
			||||||
 | 
							ret = ext4_zero_range(file, offset, len, mode);
 | 
				
			||||||
 | 
							goto exit;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	trace_ext4_fallocate_enter(inode, offset, len, mode);
 | 
						trace_ext4_fallocate_enter(inode, offset, len, mode);
 | 
				
			||||||
	lblk = offset >> blkbits;
 | 
						lblk = offset >> blkbits;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4698,12 +4712,14 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
 | 
				
			||||||
		goto out;
 | 
							goto out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (file->f_flags & O_SYNC && EXT4_SB(inode->i_sb)->s_journal) {
 | 
						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);
 | 
										EXT4_I(inode)->i_sync_tid);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
out:
 | 
					out:
 | 
				
			||||||
	inode_unlock(inode);
 | 
						inode_unlock(inode);
 | 
				
			||||||
	trace_ext4_fallocate_exit(inode, offset, max_blocks, ret);
 | 
						trace_ext4_fallocate_exit(inode, offset, max_blocks, ret);
 | 
				
			||||||
 | 
					exit:
 | 
				
			||||||
 | 
						ext4_fc_stop_update(inode);
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5291,6 +5307,7 @@ static int ext4_collapse_range(struct inode *inode, loff_t offset, loff_t len)
 | 
				
			||||||
		ret = PTR_ERR(handle);
 | 
							ret = PTR_ERR(handle);
 | 
				
			||||||
		goto out_mmap;
 | 
							goto out_mmap;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						ext4_fc_start_ineligible(sb, EXT4_FC_REASON_FALLOC_RANGE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	down_write(&EXT4_I(inode)->i_data_sem);
 | 
						down_write(&EXT4_I(inode)->i_data_sem);
 | 
				
			||||||
	ext4_discard_preallocations(inode, 0);
 | 
						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:
 | 
					out_stop:
 | 
				
			||||||
	ext4_journal_stop(handle);
 | 
						ext4_journal_stop(handle);
 | 
				
			||||||
 | 
						ext4_fc_stop_ineligible(sb);
 | 
				
			||||||
out_mmap:
 | 
					out_mmap:
 | 
				
			||||||
	up_write(&EXT4_I(inode)->i_mmap_sem);
 | 
						up_write(&EXT4_I(inode)->i_mmap_sem);
 | 
				
			||||||
out_mutex:
 | 
					out_mutex:
 | 
				
			||||||
| 
						 | 
					@ -5429,6 +5447,7 @@ static int ext4_insert_range(struct inode *inode, loff_t offset, loff_t len)
 | 
				
			||||||
		ret = PTR_ERR(handle);
 | 
							ret = PTR_ERR(handle);
 | 
				
			||||||
		goto out_mmap;
 | 
							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 */
 | 
						/* Expand file to avoid data loss if there is error while shifting */
 | 
				
			||||||
	inode->i_size += len;
 | 
						inode->i_size += len;
 | 
				
			||||||
| 
						 | 
					@ -5503,6 +5522,7 @@ static int ext4_insert_range(struct inode *inode, loff_t offset, loff_t len)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
out_stop:
 | 
					out_stop:
 | 
				
			||||||
	ext4_journal_stop(handle);
 | 
						ext4_journal_stop(handle);
 | 
				
			||||||
 | 
						ext4_fc_stop_ineligible(sb);
 | 
				
			||||||
out_mmap:
 | 
					out_mmap:
 | 
				
			||||||
	up_write(&EXT4_I(inode)->i_mmap_sem);
 | 
						up_write(&EXT4_I(inode)->i_mmap_sem);
 | 
				
			||||||
out_mutex:
 | 
					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 */
 | 
					/* Number of blocks in journal area to allocate for fast commits */
 | 
				
			||||||
#define EXT4_NUM_FC_BLKS		256
 | 
					#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__ */
 | 
					#endif /* __FAST_COMMIT_H__ */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -260,6 +260,7 @@ static ssize_t ext4_buffered_write_iter(struct kiocb *iocb,
 | 
				
			||||||
	if (iocb->ki_flags & IOCB_NOWAIT)
 | 
						if (iocb->ki_flags & IOCB_NOWAIT)
 | 
				
			||||||
		return -EOPNOTSUPP;
 | 
							return -EOPNOTSUPP;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ext4_fc_start_update(inode);
 | 
				
			||||||
	inode_lock(inode);
 | 
						inode_lock(inode);
 | 
				
			||||||
	ret = ext4_write_checks(iocb, from);
 | 
						ret = ext4_write_checks(iocb, from);
 | 
				
			||||||
	if (ret <= 0)
 | 
						if (ret <= 0)
 | 
				
			||||||
| 
						 | 
					@ -271,6 +272,7 @@ static ssize_t ext4_buffered_write_iter(struct kiocb *iocb,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
out:
 | 
					out:
 | 
				
			||||||
	inode_unlock(inode);
 | 
						inode_unlock(inode);
 | 
				
			||||||
 | 
						ext4_fc_stop_update(inode);
 | 
				
			||||||
	if (likely(ret > 0)) {
 | 
						if (likely(ret > 0)) {
 | 
				
			||||||
		iocb->ki_pos += ret;
 | 
							iocb->ki_pos += ret;
 | 
				
			||||||
		ret = generic_write_sync(iocb, 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;
 | 
								goto out;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ext4_fc_start_update(inode);
 | 
				
			||||||
		ret = ext4_orphan_add(handle, inode);
 | 
							ret = ext4_orphan_add(handle, inode);
 | 
				
			||||||
 | 
							ext4_fc_stop_update(inode);
 | 
				
			||||||
		if (ret) {
 | 
							if (ret) {
 | 
				
			||||||
			ext4_journal_stop(handle);
 | 
								ext4_journal_stop(handle);
 | 
				
			||||||
			goto out;
 | 
								goto out;
 | 
				
			||||||
| 
						 | 
					@ -656,7 +660,7 @@ ext4_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
	if (iocb->ki_flags & IOCB_DIRECT)
 | 
						if (iocb->ki_flags & IOCB_DIRECT)
 | 
				
			||||||
		return ext4_dio_write_iter(iocb, from);
 | 
							return ext4_dio_write_iter(iocb, from);
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
		return ext4_buffered_write_iter(iocb, from);
 | 
							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))
 | 
						if (!daxdev_mapping_supported(vma, dax_dev))
 | 
				
			||||||
		return -EOPNOTSUPP;
 | 
							return -EOPNOTSUPP;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ext4_fc_start_update(inode);
 | 
				
			||||||
	file_accessed(file);
 | 
						file_accessed(file);
 | 
				
			||||||
	if (IS_DAX(file_inode(file))) {
 | 
						if (IS_DAX(file_inode(file))) {
 | 
				
			||||||
		vma->vm_ops = &ext4_dax_vm_ops;
 | 
							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 {
 | 
						} else {
 | 
				
			||||||
		vma->vm_ops = &ext4_file_vm_ops;
 | 
							vma->vm_ops = &ext4_file_vm_ops;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						ext4_fc_stop_update(inode);
 | 
				
			||||||
	return 0;
 | 
						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))
 | 
						    !jbd2_trans_will_send_data_barrier(journal, commit_tid))
 | 
				
			||||||
		*needs_barrier = true;
 | 
							*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)
 | 
								if (ret)
 | 
				
			||||||
				return ret;
 | 
									return ret;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							ext4_fc_track_range(inode, map->m_lblk,
 | 
				
			||||||
 | 
								    map->m_lblk + map->m_len - 1);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (retval < 0)
 | 
						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;
 | 
						journal_t *journal = EXT4_SB(inode->i_sb)->s_journal;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (journal)
 | 
						if (journal) {
 | 
				
			||||||
		return !jbd2_transaction_committed(journal,
 | 
							if (jbd2_transaction_committed(journal,
 | 
				
			||||||
					EXT4_I(inode)->i_datasync_tid);
 | 
										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? */
 | 
						/* Any metadata buffers to write? */
 | 
				
			||||||
	if (!list_empty(&inode->i_mapping->private_list))
 | 
						if (!list_empty(&inode->i_mapping->private_list))
 | 
				
			||||||
		return true;
 | 
							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);
 | 
							up_write(&EXT4_I(inode)->i_data_sem);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						ext4_fc_track_range(inode, first_block, stop_block);
 | 
				
			||||||
	if (IS_SYNC(inode))
 | 
						if (IS_SYNC(inode))
 | 
				
			||||||
		ext4_handle_sync(handle);
 | 
							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++)
 | 
						for (block = 0; block < EXT4_N_BLOCKS; block++)
 | 
				
			||||||
		ei->i_data[block] = raw_inode->i_block[block];
 | 
							ei->i_data[block] = raw_inode->i_block[block];
 | 
				
			||||||
	INIT_LIST_HEAD(&ei->i_orphan);
 | 
						INIT_LIST_HEAD(&ei->i_orphan);
 | 
				
			||||||
 | 
						ext4_fc_init_inode(&ei->vfs_inode);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * Set transaction id's of transactions that have to be committed
 | 
						 * 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)
 | 
							if (wbc->sync_mode != WB_SYNC_ALL || wbc->for_sync)
 | 
				
			||||||
			return 0;
 | 
								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);
 | 
											EXT4_I(inode)->i_sync_tid);
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		struct ext4_iloc iloc;
 | 
							struct ext4_iloc iloc;
 | 
				
			||||||
| 
						 | 
					@ -5291,6 +5300,7 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr)
 | 
				
			||||||
		if (error)
 | 
							if (error)
 | 
				
			||||||
			return error;
 | 
								return error;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						ext4_fc_start_update(inode);
 | 
				
			||||||
	if ((ia_valid & ATTR_UID && !uid_eq(attr->ia_uid, inode->i_uid)) ||
 | 
						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))) {
 | 
						    (ia_valid & ATTR_GID && !gid_eq(attr->ia_gid, inode->i_gid))) {
 | 
				
			||||||
		handle_t *handle;
 | 
							handle_t *handle;
 | 
				
			||||||
| 
						 | 
					@ -5314,6 +5324,7 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (error) {
 | 
							if (error) {
 | 
				
			||||||
			ext4_journal_stop(handle);
 | 
								ext4_journal_stop(handle);
 | 
				
			||||||
 | 
								ext4_fc_stop_update(inode);
 | 
				
			||||||
			return error;
 | 
								return error;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		/* Update corresponding info in inode so that everything is in
 | 
							/* 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))) {
 | 
							if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))) {
 | 
				
			||||||
			struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
 | 
								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;
 | 
									return -EFBIG;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		if (!S_ISREG(inode->i_mode))
 | 
							}
 | 
				
			||||||
 | 
							if (!S_ISREG(inode->i_mode)) {
 | 
				
			||||||
 | 
								ext4_fc_stop_update(inode);
 | 
				
			||||||
			return -EINVAL;
 | 
								return -EINVAL;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (IS_I_VERSION(inode) && attr->ia_size != inode->i_size)
 | 
							if (IS_I_VERSION(inode) && attr->ia_size != inode->i_size)
 | 
				
			||||||
			inode_inc_iversion(inode);
 | 
								inode_inc_iversion(inode);
 | 
				
			||||||
| 
						 | 
					@ -5364,7 +5379,7 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr)
 | 
				
			||||||
		rc = ext4_break_layouts(inode);
 | 
							rc = ext4_break_layouts(inode);
 | 
				
			||||||
		if (rc) {
 | 
							if (rc) {
 | 
				
			||||||
			up_write(&EXT4_I(inode)->i_mmap_sem);
 | 
								up_write(&EXT4_I(inode)->i_mmap_sem);
 | 
				
			||||||
			return rc;
 | 
								goto err_out;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (attr->ia_size != inode->i_size) {
 | 
							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_mtime = current_time(inode);
 | 
				
			||||||
				inode->i_ctime = inode->i_mtime;
 | 
									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);
 | 
								down_write(&EXT4_I(inode)->i_data_sem);
 | 
				
			||||||
			EXT4_I(inode)->i_disksize = attr->ia_size;
 | 
								EXT4_I(inode)->i_disksize = attr->ia_size;
 | 
				
			||||||
			rc = ext4_mark_inode_dirty(handle, inode);
 | 
								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);
 | 
							rc = posix_acl_chmod(inode, inode->i_mode);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
err_out:
 | 
					err_out:
 | 
				
			||||||
 | 
						if  (error)
 | 
				
			||||||
		ext4_std_error(inode->i_sb, error);
 | 
							ext4_std_error(inode->i_sb, error);
 | 
				
			||||||
	if (!error)
 | 
						if (!error)
 | 
				
			||||||
		error = rc;
 | 
							error = rc;
 | 
				
			||||||
 | 
						ext4_fc_stop_update(inode);
 | 
				
			||||||
	return error;
 | 
						return error;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5627,6 +5659,8 @@ int ext4_mark_iloc_dirty(handle_t *handle,
 | 
				
			||||||
		put_bh(iloc->bh);
 | 
							put_bh(iloc->bh);
 | 
				
			||||||
		return -EIO;
 | 
							return -EIO;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						ext4_fc_track_inode(inode);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (IS_I_VERSION(inode))
 | 
						if (IS_I_VERSION(inode))
 | 
				
			||||||
		inode_inc_iversion(inode);
 | 
							inode_inc_iversion(inode);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5950,6 +5984,8 @@ int ext4_change_inode_journal_flag(struct inode *inode, int val)
 | 
				
			||||||
	if (IS_ERR(handle))
 | 
						if (IS_ERR(handle))
 | 
				
			||||||
		return PTR_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);
 | 
						err = ext4_mark_inode_dirty(handle, inode);
 | 
				
			||||||
	ext4_handle_sync(handle);
 | 
						ext4_handle_sync(handle);
 | 
				
			||||||
	ext4_journal_stop(handle);
 | 
						ext4_journal_stop(handle);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -165,6 +165,7 @@ static long swap_inode_boot_loader(struct super_block *sb,
 | 
				
			||||||
		err = -EINVAL;
 | 
							err = -EINVAL;
 | 
				
			||||||
		goto err_out;
 | 
							goto err_out;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						ext4_fc_start_ineligible(sb, EXT4_FC_REASON_SWAP_BOOT);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Protect extent tree against block allocations via delalloc */
 | 
						/* Protect extent tree against block allocations via delalloc */
 | 
				
			||||||
	ext4_double_down_write_data_sem(inode, inode_bl);
 | 
						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:
 | 
					err_out1:
 | 
				
			||||||
	ext4_journal_stop(handle);
 | 
						ext4_journal_stop(handle);
 | 
				
			||||||
 | 
						ext4_fc_stop_ineligible(sb);
 | 
				
			||||||
	ext4_double_up_write_data_sem(inode, inode_bl);
 | 
						ext4_double_up_write_data_sem(inode, inode_bl);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
err_out:
 | 
					err_out:
 | 
				
			||||||
| 
						 | 
					@ -807,7 +809,7 @@ static int ext4_ioctl_get_es_cache(struct file *filp, unsigned long arg)
 | 
				
			||||||
	return error;
 | 
						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 inode *inode = file_inode(filp);
 | 
				
			||||||
	struct super_block *sb = inode->i_sb;
 | 
						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);
 | 
							err = ext4_resize_fs(sb, n_blocks_count);
 | 
				
			||||||
		if (EXT4_SB(sb)->s_journal) {
 | 
							if (EXT4_SB(sb)->s_journal) {
 | 
				
			||||||
 | 
								ext4_fc_mark_ineligible(sb, EXT4_FC_REASON_RESIZE);
 | 
				
			||||||
			jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal);
 | 
								jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal);
 | 
				
			||||||
			err2 = jbd2_journal_flush(EXT4_SB(sb)->s_journal);
 | 
								err2 = jbd2_journal_flush(EXT4_SB(sb)->s_journal);
 | 
				
			||||||
			jbd2_journal_unlock_updates(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
 | 
					#ifdef CONFIG_COMPAT
 | 
				
			||||||
long ext4_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 | 
					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)
 | 
							       bool excl)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	handle_t *handle;
 | 
						handle_t *handle;
 | 
				
			||||||
	struct inode *inode;
 | 
						struct inode *inode, *inode_save;
 | 
				
			||||||
	int err, credits, retries = 0;
 | 
						int err, credits, retries = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = dquot_initialize(dir);
 | 
						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_op = &ext4_file_inode_operations;
 | 
				
			||||||
		inode->i_fop = &ext4_file_operations;
 | 
							inode->i_fop = &ext4_file_operations;
 | 
				
			||||||
		ext4_set_aops(inode);
 | 
							ext4_set_aops(inode);
 | 
				
			||||||
 | 
							inode_save = inode;
 | 
				
			||||||
 | 
							ihold(inode_save);
 | 
				
			||||||
		err = ext4_add_nondir(handle, dentry, &inode);
 | 
							err = ext4_add_nondir(handle, dentry, &inode);
 | 
				
			||||||
 | 
							ext4_fc_track_create(inode_save, dentry);
 | 
				
			||||||
 | 
							iput(inode_save);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (handle)
 | 
						if (handle)
 | 
				
			||||||
		ext4_journal_stop(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)
 | 
							      umode_t mode, dev_t rdev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	handle_t *handle;
 | 
						handle_t *handle;
 | 
				
			||||||
	struct inode *inode;
 | 
						struct inode *inode, *inode_save;
 | 
				
			||||||
	int err, credits, retries = 0;
 | 
						int err, credits, retries = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = dquot_initialize(dir);
 | 
						err = dquot_initialize(dir);
 | 
				
			||||||
| 
						 | 
					@ -2661,7 +2665,12 @@ static int ext4_mknod(struct inode *dir, struct dentry *dentry,
 | 
				
			||||||
	if (!IS_ERR(inode)) {
 | 
						if (!IS_ERR(inode)) {
 | 
				
			||||||
		init_special_inode(inode, inode->i_mode, rdev);
 | 
							init_special_inode(inode, inode->i_mode, rdev);
 | 
				
			||||||
		inode->i_op = &ext4_special_inode_operations;
 | 
							inode->i_op = &ext4_special_inode_operations;
 | 
				
			||||||
 | 
							inode_save = inode;
 | 
				
			||||||
 | 
							ihold(inode_save);
 | 
				
			||||||
		err = ext4_add_nondir(handle, dentry, &inode);
 | 
							err = ext4_add_nondir(handle, dentry, &inode);
 | 
				
			||||||
 | 
							if (!err)
 | 
				
			||||||
 | 
								ext4_fc_track_create(inode_save, dentry);
 | 
				
			||||||
 | 
							iput(inode_save);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (handle)
 | 
						if (handle)
 | 
				
			||||||
		ext4_journal_stop(handle);
 | 
							ext4_journal_stop(handle);
 | 
				
			||||||
| 
						 | 
					@ -2825,7 +2834,9 @@ static int ext4_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
 | 
				
			||||||
		iput(inode);
 | 
							iput(inode);
 | 
				
			||||||
		goto out_retry;
 | 
							goto out_retry;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						ext4_fc_track_create(inode, dentry);
 | 
				
			||||||
	ext4_inc_count(dir);
 | 
						ext4_inc_count(dir);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ext4_update_dx_flag(dir);
 | 
						ext4_update_dx_flag(dir);
 | 
				
			||||||
	err = ext4_mark_inode_dirty(handle, dir);
 | 
						err = ext4_mark_inode_dirty(handle, dir);
 | 
				
			||||||
	if (err)
 | 
						if (err)
 | 
				
			||||||
| 
						 | 
					@ -3165,6 +3176,7 @@ static int ext4_rmdir(struct inode *dir, struct dentry *dentry)
 | 
				
			||||||
		goto end_rmdir;
 | 
							goto end_rmdir;
 | 
				
			||||||
	ext4_dec_count(dir);
 | 
						ext4_dec_count(dir);
 | 
				
			||||||
	ext4_update_dx_flag(dir);
 | 
						ext4_update_dx_flag(dir);
 | 
				
			||||||
 | 
						ext4_fc_track_unlink(inode, dentry);
 | 
				
			||||||
	retval = ext4_mark_inode_dirty(handle, dir);
 | 
						retval = ext4_mark_inode_dirty(handle, dir);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_UNICODE
 | 
					#ifdef CONFIG_UNICODE
 | 
				
			||||||
| 
						 | 
					@ -3251,6 +3263,8 @@ static int ext4_unlink(struct inode *dir, struct dentry *dentry)
 | 
				
			||||||
	inode->i_ctime = current_time(inode);
 | 
						inode->i_ctime = current_time(inode);
 | 
				
			||||||
	retval = ext4_mark_inode_dirty(handle, inode);
 | 
						retval = ext4_mark_inode_dirty(handle, inode);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!retval)
 | 
				
			||||||
 | 
							ext4_fc_track_unlink(d_inode(dentry), dentry);
 | 
				
			||||||
#ifdef CONFIG_UNICODE
 | 
					#ifdef CONFIG_UNICODE
 | 
				
			||||||
	/* VFS negative dentries are incompatible with Encoding and
 | 
						/* VFS negative dentries are incompatible with Encoding and
 | 
				
			||||||
	 * Case-insensitiveness. Eventually we'll want avoid
 | 
						 * 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);
 | 
						retval = ext4_mark_inode_dirty(handle, old.dir);
 | 
				
			||||||
	if (unlikely(retval))
 | 
						if (unlikely(retval))
 | 
				
			||||||
		goto end_rename;
 | 
							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) {
 | 
						if (new.inode) {
 | 
				
			||||||
		retval = ext4_mark_inode_dirty(handle, new.inode);
 | 
							retval = ext4_mark_inode_dirty(handle, new.inode);
 | 
				
			||||||
		if (unlikely(retval))
 | 
							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);
 | 
						retval = ext4_mark_inode_dirty(handle, new.inode);
 | 
				
			||||||
	if (unlikely(retval))
 | 
						if (unlikely(retval))
 | 
				
			||||||
		goto end_rename;
 | 
							goto end_rename;
 | 
				
			||||||
 | 
						ext4_fc_mark_ineligible(new.inode->i_sb,
 | 
				
			||||||
 | 
									EXT4_FC_REASON_CROSS_RENAME);
 | 
				
			||||||
	if (old.dir_bh) {
 | 
						if (old.dir_bh) {
 | 
				
			||||||
		retval = ext4_rename_dir_finish(handle, &old, new.dir->i_ino);
 | 
							retval = ext4_rename_dir_finish(handle, &old, new.dir->i_ino);
 | 
				
			||||||
		if (retval)
 | 
							if (retval)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1331,6 +1331,8 @@ static struct inode *ext4_alloc_inode(struct super_block *sb)
 | 
				
			||||||
	ei->i_datasync_tid = 0;
 | 
						ei->i_datasync_tid = 0;
 | 
				
			||||||
	atomic_set(&ei->i_unwritten, 0);
 | 
						atomic_set(&ei->i_unwritten, 0);
 | 
				
			||||||
	INIT_WORK(&ei->i_rsv_conversion_work, ext4_end_io_rsv_work);
 | 
						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;
 | 
						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)
 | 
					static void ext4_free_in_core_inode(struct inode *inode)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	fscrypt_free_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));
 | 
						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_data_sem);
 | 
				
			||||||
	init_rwsem(&ei->i_mmap_sem);
 | 
						init_rwsem(&ei->i_mmap_sem);
 | 
				
			||||||
	inode_init_once(&ei->vfs_inode);
 | 
						inode_init_once(&ei->vfs_inode);
 | 
				
			||||||
 | 
						ext4_fc_init_inode(&ei->vfs_inode);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int __init init_inodecache(void)
 | 
					static int __init init_inodecache(void)
 | 
				
			||||||
| 
						 | 
					@ -1401,6 +1408,7 @@ static void destroy_inodecache(void)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ext4_clear_inode(struct inode *inode)
 | 
					void ext4_clear_inode(struct inode *inode)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						ext4_fc_del(inode);
 | 
				
			||||||
	invalidate_inode_buffers(inode);
 | 
						invalidate_inode_buffers(inode);
 | 
				
			||||||
	clear_inode(inode);
 | 
						clear_inode(inode);
 | 
				
			||||||
	ext4_discard_preallocations(inode, 0);
 | 
						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 */
 | 
						INIT_LIST_HEAD(&sbi->s_orphan); /* unlinked but open files */
 | 
				
			||||||
	mutex_init(&sbi->s_orphan_lock);
 | 
						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;
 | 
						sb->s_root = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	needs_recovery = (es->s_last_orphan != 0 ||
 | 
						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);
 | 
						brelse(bh);
 | 
				
			||||||
out:
 | 
					out:
 | 
				
			||||||
	if (inode->i_size < off + len) {
 | 
						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);
 | 
							i_size_write(inode, off + len);
 | 
				
			||||||
		EXT4_I(inode)->i_disksize = inode->i_size;
 | 
							EXT4_I(inode)->i_disksize = inode->i_size;
 | 
				
			||||||
		err2 = ext4_mark_inode_dirty(handle, inode);
 | 
							err2 = ext4_mark_inode_dirty(handle, inode);
 | 
				
			||||||
| 
						 | 
					@ -6643,6 +6668,11 @@ static int __init ext4_init_fs(void)
 | 
				
			||||||
	err = init_inodecache();
 | 
						err = init_inodecache();
 | 
				
			||||||
	if (err)
 | 
						if (err)
 | 
				
			||||||
		goto out1;
 | 
							goto out1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = ext4_fc_init_dentry_cache();
 | 
				
			||||||
 | 
						if (err)
 | 
				
			||||||
 | 
							goto out05;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	register_as_ext3();
 | 
						register_as_ext3();
 | 
				
			||||||
	register_as_ext2();
 | 
						register_as_ext2();
 | 
				
			||||||
	err = register_filesystem(&ext4_fs_type);
 | 
						err = register_filesystem(&ext4_fs_type);
 | 
				
			||||||
| 
						 | 
					@ -6653,6 +6683,7 @@ static int __init ext4_init_fs(void)
 | 
				
			||||||
out:
 | 
					out:
 | 
				
			||||||
	unregister_as_ext2();
 | 
						unregister_as_ext2();
 | 
				
			||||||
	unregister_as_ext3();
 | 
						unregister_as_ext3();
 | 
				
			||||||
 | 
					out05:
 | 
				
			||||||
	destroy_inodecache();
 | 
						destroy_inodecache();
 | 
				
			||||||
out1:
 | 
					out1:
 | 
				
			||||||
	ext4_exit_mballoc();
 | 
						ext4_exit_mballoc();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2419,6 +2419,7 @@ ext4_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index,
 | 
				
			||||||
		if (IS_SYNC(inode))
 | 
							if (IS_SYNC(inode))
 | 
				
			||||||
			ext4_handle_sync(handle);
 | 
								ext4_handle_sync(handle);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						ext4_fc_mark_ineligible(inode->i_sb, EXT4_FC_REASON_XATTR);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
cleanup:
 | 
					cleanup:
 | 
				
			||||||
	brelse(is.iloc.bh);
 | 
						brelse(is.iloc.bh);
 | 
				
			||||||
| 
						 | 
					@ -2496,6 +2497,7 @@ ext4_xattr_set(struct inode *inode, int name_index, const char *name,
 | 
				
			||||||
		if (error == 0)
 | 
							if (error == 0)
 | 
				
			||||||
			error = error2;
 | 
								error = error2;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						ext4_fc_mark_ineligible(inode->i_sb, EXT4_FC_REASON_XATTR);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return error;
 | 
						return error;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -2928,6 +2930,7 @@ int ext4_xattr_delete_inode(handle_t *handle, struct inode *inode,
 | 
				
			||||||
					 error);
 | 
										 error);
 | 
				
			||||||
			goto cleanup;
 | 
								goto cleanup;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							ext4_fc_mark_ineligible(inode->i_sb, EXT4_FC_REASON_XATTR);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	error = 0;
 | 
						error = 0;
 | 
				
			||||||
cleanup:
 | 
					cleanup:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -95,6 +95,16 @@ TRACE_DEFINE_ENUM(ES_REFERENCED_B);
 | 
				
			||||||
	{ FALLOC_FL_COLLAPSE_RANGE,	"COLLAPSE_RANGE"},	\
 | 
						{ FALLOC_FL_COLLAPSE_RANGE,	"COLLAPSE_RANGE"},	\
 | 
				
			||||||
	{ FALLOC_FL_ZERO_RANGE,		"ZERO_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,
 | 
					TRACE_EVENT(ext4_other_inode_update_time,
 | 
				
			||||||
	TP_PROTO(struct inode *inode, ino_t orig_ino),
 | 
						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)
 | 
							  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 */
 | 
					#endif /* _TRACE_EXT4_H */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* This part must be outside protection */
 | 
					/* This part must be outside protection */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue