ext4: defragmentation for the relevant files (-r mode)
Subsystems (2)
RFC PATCH 5/8 ext4: defragmentation for the relevant files (-r mode)
ext4: online defrag-- Defragmentation for the relevant files (-r mode)
From: Akira Fujita <[email protected]>
Relevant file fragmentation could be solved by moving the files under the specified directory close together with the block containing the directory data.
Signed-off-by Akira Fujita <[email protected]>
Signed-off-by Takashi Sato <[email protected]>
--- fs/ext4/defrag.c | 48 +++++++++++++++++++++++++++++++++++------------- fs/ext4/ext4.h | 4 +++- fs/ext4/inode.c | 2 +- fs/ext4/ioctl.c | 1 + 4 files changed, 40 insertions(+), 15 deletions(-)
fs/ext4/defrag.c +35 -13
@@ -95,13 +95,26 @@ int ext4_defrag_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, {int err =0 ; -if (!(EXT4_I (inode)->i_flags &EXT4_EXTENTS_FL )) { +if (!(EXT4_I (inode)->i_flags &EXT4_EXTENTS_FL || + cmd ==EXT4_IOC_FIBMAP )) {printk (KERN_ERR "ext4 defrag: ino[%lu] is not extents " "based file\n" , inode->i_ino);return -EOPNOTSUPP ; } -if (cmd ==EXT4_IOC_DEFRAG ) { +if (cmd ==EXT4_IOC_FIBMAP ) { +ext4_fsblk_t __user *p = (ext4_fsblk_t __user *)arg; +ext4_fsblk_t block =0 ; +struct address_space *mapping = filp->f_mapping; + +if (copy_from_user (&block, (ext4_fsblk_t __user *)arg, +sizeof (block))) +return -EFAULT ; + + block =ext4_bmap (mapping, block); + +return put_user (block, p); + }else if (cmd ==EXT4_IOC_DEFRAG ) {struct ext4_ext_defrag_data defrag;struct ext4_super_block *es =EXT4_SB (inode->i_sb)->s_es;
@@ -127,7 +140,7 @@ int ext4_defrag_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, } err =ext4_defrag (filp, defrag.start_offset, - defrag.defrag_size); + defrag.defrag_size, defrag.goal); }return err;
@@ -745,6 +758,7 @@ out:* @dest_path: indicating the temporary inode's extent * @req_blocks: contiguous blocks count we need * @iblock: target file offset +* @goal: goal offset * */ static void
@@ -752,7 +766,8 @@ ext4_defrag_fill_ar(struct inode *org_inode, struct inode *dest_inode,struct ext4_allocation_request *ar, struct ext4_ext_path *org_path, struct ext4_ext_path *dest_path, - ext4_fsblk_t req_blocks, ext4_lblk_t iblock) + ext4_fsblk_t req_blocks, ext4_lblk_t iblock, + ext4_fsblk_t goal) { ar->inode = dest_inode; ar->len = req_blocks;
@@ -764,7 +779,10 @@ ext4_defrag_fill_ar(struct inode *org_inode, struct inode *dest_inode, ar->lright =0 ; ar->pright =0 ; - ar->goal =ext4_ext_find_goal (dest_inode, dest_path, iblock); +if (goal) + ar->goal = goal; +else + ar->goal =ext4_ext_find_goal (dest_inode, dest_path, iblock); }/**
@@ -941,6 +959,7 @@ out:* original extent tree * @tar_end: the last block number of the allocated blocks * @sum_tmp: the extents count in the allocated blocks +* @goal: block offset for allocaton * * * This function returns the values as below.
@@ -951,7 +970,7 @@ out:static int ext4_defrag_comp_ext_count (struct inode *org_inode,struct ext4_ext_path *org_path,ext4_lblk_t tar_end, -int sum_tmp) +int sum_tmp,ext4_fsblk_t goal) {struct ext4_extent *ext =NULL ;int depth =ext_depth (org_inode);
@@ -975,7 +994,7 @@ ext4_defrag_comp_ext_count(struct inode *org_inode,* Fail if goal is not set and the fragmentation * is not improved. */ -if (sum_org == sum_tmp) { +if (sum_org == sum_tmp && !goal) {/* Not improved */ ret =1 ; }else if (sum_org < sum_tmp) {
@@ -1006,6 +1025,7 @@ ext4_defrag_comp_ext_count(struct inode *org_inode,* @tar_start: starting offset to allocate in blocks * @tar_blocks: the number of blocks to allocate * @iblock: file related offset +* @goal: block offset for allocaton * * * This function returns the value as below:
@@ -1016,7 +1036,8 @@ ext4_defrag_comp_ext_count(struct inode *org_inode,static int ext4_defrag_new_extent_tree (struct inode *org_inode,struct inode *tmp_inode,struct ext4_ext_path *org_path,ext4_lblk_t tar_start, -ext4_lblk_t tar_blocks,ext4_lblk_t iblock) +ext4_lblk_t tar_blocks,ext4_lblk_t iblock, +ext4_fsblk_t goal) {handle_t *handle;struct ext4_extent_header *eh =NULL ;
@@ -1042,7 +1063,7 @@ ext4_defrag_new_extent_tree(struct inode *org_inode, struct inode *tmp_inode,/* Fill struct ext4_allocation_request with necessary info */ ext4_defrag_fill_ar (org_inode, tmp_inode, &ar, org_path, - dest_path, tar_blocks, iblock); + dest_path, tar_blocks, iblock, goal); handle =ext4_journal_start (tmp_inode,0 );if (IS_ERR (handle)) {
@@ -1074,7 +1095,7 @@ ext4_defrag_new_extent_tree(struct inode *org_inode, struct inode *tmp_inode, } ret =ext4_defrag_comp_ext_count (org_inode, org_path, tar_end, - sum_tmp); + sum_tmp, goal); out:if (ret <0 || ret ==1 ) {
@@ -1204,13 +1225,14 @@ out:* @filp: pointer to file * @block_start: starting offset to defrag in blocks * @defrag_size: size of defrag in blocks +* @goal: block offset for allocation * * This function returns the number of blocks if succeed, otherwise * returns error value. */ int ext4_defrag (struct file *filp,ext4_lblk_t block_start, -ext4_lblk_t defrag_size) +ext4_lblk_t defrag_size,ext4_fsblk_t goal) {struct inode *org_inode = filp->f_dentry->d_inode, *tmp_inode =NULL ;struct ext4_ext_path *org_path =NULL , *holecheck_path =NULL ;
@@ -1329,14 +1351,14 @@ ext4_defrag(struct file *filp, ext4_lblk_t block_start, }/* Found an isolated block */ -if (seq_extents ==1 ) { +if (seq_extents ==1 && !goal) { seq_start =le32_to_cpu (ext_cur->ee_block); goto CLEANUP; } ret =ext4_defrag_new_extent_tree (org_inode, tmp_inode, org_path, seq_start, seq_blocks, - block_start); + block_start, goal);if (ret <0 ) {break ;
fs/ext4/ext4.h +3 -1
@@ -298,6 +298,7 @@ struct ext4_new_group_data {#define EXT4_IOC_GETRSVSZ _IOR('f', 5, long)#define EXT4_IOC_SETRSVSZ _IOW('f', 6, long)#define EXT4_IOC_MIGRATE _IO('f', 7) +#define EXT4_IOC_FIBMAP _IOW('f', 9, ext4_fsblk_t)#define EXT4_IOC_DEFRAG _IOW('f', 10, struct ext4_ext_defrag_data)/*
@@ -1018,6 +1019,7 @@ extern int ext4_htree_store_dirent(struct file *dir_file, __u32 hash,__u32 minor_hash, struct ext4_dir_entry_2 *dirent);extern void ext4_htree_free_dir_info (struct dir_private_info *p); +extern sector_t ext4_bmap (struct address_space *mapping,sector_t block);/* fsync.c */ extern int ext4_sync_file (struct file *,struct dentry *,int );
@@ -1133,7 +1135,7 @@ extern void ext4_inode_table_set(struct super_block *sb,extern handle_t *ext4_ext_journal_restart (handle_t *handle,int needed);/* defrag.c */ extern int ext4_defrag (struct file *filp,ext4_lblk_t block_start, -ext4_lblk_t defrag_size); +ext4_lblk_t defrag_size,ext4_fsblk_t goal);extern int ext4_defrag_ioctl (struct inode *,struct file *,unsigned int ,unsigned long );
fs/ext4/inode.c +1 -1
@@ -1648,7 +1648,7 @@ out:* So, if we see any bmap calls here on a modified, data-journaled file, * take extra steps to flush any blocks which might be in the cache. */ -static sector_t ext4_bmap (struct address_space *mapping,sector_t block) +sector_t ext4_bmap (struct address_space *mapping,sector_t block) {struct inode *inode = mapping->host;journal_t *journal;
fs/ext4/ioctl.c +1 -0
@@ -241,6 +241,7 @@ setversion_out:return err; } +case EXT4_IOC_FIBMAP :case EXT4_IOC_DEFRAG : {return ext4_defrag_ioctl (inode, filp, cmd, arg); }