Add jbd2-abort-instead-of-waiting-for-nonexistent-transaction
[ext4-patch-queue.git] / defrag-07-add-free-blocks-info-ioctl
blobbc2a8662355356904aef55e4f75f91afcfde5baa
1 ext4: online defrag: Add the EXT4_IOC_FREE_BLOCKS_INFO ioctl.
3 From: Akira Fujita <a-fujita@rs.jp.nec.com>
5 The EXT4_IOC_FREE_BLOCKS_INFO ioctl gets free extents
6 information of the target block group.
7 This ioctl is used only in the force defrag (-f).
9 Defragger calculates the victim extents (which will be moved
10 into other block group in order to make contiguous free space for the target file)
11 based on used/unused extents information.
13 Signed-off-by: Akira Fujita <a-fujita@rs.jp.nec.com>
14 Signed-off-by: Takashi Sato <t-sato@yk.jp.nec.com>
15 ---
16  fs/ext4/balloc.c |    2 +-
17  fs/ext4/defrag.c |  112 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
18  fs/ext4/ext4.h   |   27 +++++++++++++
19  fs/ext4/ioctl.c  |    3 +-
20  4 files changed, 142 insertions(+), 2 deletions(-)
22 diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c
23 index 02068fa..64ec04c 100644
24 --- a/fs/ext4/balloc.c
25 +++ b/fs/ext4/balloc.c
26 @@ -919,7 +919,7 @@ static int ext4_test_allocatable(ext4_grpblk_t nr, struct buffer_head *bh)
27   * bitmap on disk and the last-committed copy in journal, until we find a
28   * bit free in both bitmaps.
29   */
30 -static ext4_grpblk_t
31 +ext4_grpblk_t
32  bitmap_search_next_usable_block(ext4_grpblk_t start, struct buffer_head *bh,
33                                         ext4_grpblk_t maxblocks)
34  {
35 diff --git a/fs/ext4/defrag.c b/fs/ext4/defrag.c
36 index cb7d237..941414b 100644
37 --- a/fs/ext4/defrag.c
38 +++ b/fs/ext4/defrag.c
39 @@ -90,6 +90,102 @@ err:
40         return -EIO;
41  }
43 +/**
44 + * ext4_defrag_fblocks_distribution - Search free blocks distribution
45 + *
46 + * @org_inode: original inode
47 + * @ext_info:  ext4_extents_info
48 + *
49 + * This function returns 0 if succeed, otherwise returns error value.
50 + */
51 +static int
52 +ext4_defrag_fblocks_distribution(struct inode *org_inode,
53 +                       struct ext4_extents_info *ext_info)
55 +       struct buffer_head *bitmap_bh = NULL;
56 +       struct super_block *sb = org_inode->i_sb;
57 +       handle_t *handle;
58 +       ext4_group_t group_no;
59 +       ext4_grpblk_t start, end;
60 +       ext4_fsblk_t start_block = 0;
61 +       int i, err;
62 +       int num = 0;
63 +       int len = 0;
64 +       int block_set = 0;
65 +       int extra_block = 0;
67 +       if (!sb) {
68 +               printk(KERN_ERR "ext4 defrag: Non-existent device\n");
69 +               return -ENOSPC;
70 +       }
72 +       group_no = (org_inode->i_ino - 1) / EXT4_INODES_PER_GROUP(sb);
73 +       start = ext_info->g_offset;
74 +       end = EXT4_BLOCKS_PER_GROUP(sb) - 1;
76 +       /* We consider about the boot block if bs = 1k */
77 +       if (sb->s_blocksize == 1024)
78 +               extra_block = 1;
80 +       handle = ext4_journal_start(org_inode, 1);
81 +       if (IS_ERR(handle)) {
82 +               err = PTR_ERR(handle);
83 +               return err;
84 +       }
86 +       bitmap_bh = ext4_read_block_bitmap(sb, group_no);
87 +       if (!bitmap_bh) {
88 +               err = -EIO;
89 +               goto out;
90 +       }
92 +       BUFFER_TRACE(bitmap_bh, "get undo access for new block");
93 +       err = ext4_journal_get_undo_access(handle, bitmap_bh);
94 +       if (err)
95 +               goto out;
97 +       for (i = start; i <= end ; i++) {
98 +               if (bitmap_search_next_usable_block(i, bitmap_bh, i + 1) >= 0) {
99 +                       len++;
100 +                       /*
101 +                        * Reset start_block if the free block is
102 +                        * the head of region.
103 +                        */
104 +                       if (!block_set) {
105 +                               start_block =
106 +                                i + group_no * EXT4_BLOCKS_PER_GROUP(sb) +
107 +                                extra_block;
108 +                               block_set = 1;
109 +                       }
110 +               } else if (len) {
111 +                       ext_info->ext[num].start = start_block;
112 +                       ext_info->ext[num].len = len;
113 +                       num++;
114 +                       len = 0;
115 +                       block_set = 0;
116 +                       if (num == ext_info->max_entries) {
117 +                               ext_info->g_offset = i + 1;
118 +                               break;
119 +                       }
120 +               }
121 +               if (i == end && len) {
122 +                       ext_info->ext[num].start = start_block;
123 +                       ext_info->ext[num].len = len;
124 +                       num++;
125 +               }
126 +       }
128 +       ext_info->entries = num;
129 +out:
130 +       ext4_journal_release_buffer(handle, bitmap_bh);
131 +       brelse(bitmap_bh);
133 +       if (handle)
134 +               ext4_journal_stop(handle);
136 +       return err;
139  int ext4_defrag_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
140                         unsigned long arg)
142 @@ -125,6 +221,22 @@ int ext4_defrag_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
143                 if (copy_to_user((struct ext4_group_data_info __user *)arg,
144                         &grp_data, sizeof(grp_data)))
145                         return -EFAULT;
146 +       } else if (cmd == EXT4_IOC_FREE_BLOCKS_INFO) {
147 +               struct ext4_extents_info ext_info;
149 +               if (copy_from_user(&ext_info,
150 +                       (struct ext4_extents_info __user *)arg,
151 +                       sizeof(ext_info)))
152 +                       return -EFAULT;
154 +               BUG_ON(ext_info.ino != inode->i_ino);
156 +               err = ext4_defrag_fblocks_distribution(inode, &ext_info);
158 +               if (!err)
159 +                       err = copy_to_user(
160 +                               (struct ext4_extents_info __user *)arg,
161 +                               &ext_info, sizeof(ext_info));
162         } else if (cmd == EXT4_IOC_DEFRAG) {
163                 struct ext4_ext_defrag_data defrag;
164                 struct ext4_super_block *es = EXT4_SB(inode->i_sb)->s_es;
165 diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
166 index a635a76..ffe687b 100644
167 --- a/fs/ext4/ext4.h
168 +++ b/fs/ext4/ext4.h
169 @@ -305,6 +305,7 @@ struct ext4_new_group_data {
170  #define EXT4_IOC_DEFRAG                        _IOW('f', 15, struct ext4_ext_defrag_data)
171  #define EXT4_IOC_FIBMAP                        _IOW('f', 16, ext4_fsblk_t)
172  #define EXT4_IOC_GROUP_INFO            _IOW('f', 17, struct ext4_group_data_info)
173 +#define EXT4_IOC_FREE_BLOCKS_INFO      _IOW('f', 18, struct ext4_extents_info)
175  /*
176   * ioctl commands in 32 bit emulation
177 @@ -322,6 +323,20 @@ struct ext4_new_group_data {
178  #define EXT4_IOC32_GETVERSION_OLD      FS_IOC32_GETVERSION
179  #define EXT4_IOC32_SETVERSION_OLD      FS_IOC32_SETVERSION
182 + * The following four macros are used for the defrag force mode.
183 + *
184 + * DEFRAG_MAX_ENT:     the maximum number of extents for exchanging between
185 + *                     kernel-space and user-space per an ioctl
186 + */
187 +#define DEFRAG_MAX_ENT         32
189 +struct ext4_extent_data {
190 +       ext4_lblk_t block;              /* start logical block number */
191 +       ext4_fsblk_t start;             /* start physical block number */
192 +       int len;                        /* blocks count */
195  struct ext4_ext_defrag_data {
196         ext4_lblk_t start_offset;       /* start offset to defrag in blocks */
197         ext4_lblk_t defrag_size;        /* size of defrag in blocks */
198 @@ -333,6 +348,16 @@ struct ext4_group_data_info {
199         int s_inodes_per_group;         /* inodes per group */
200  };
202 +struct ext4_extents_info {
203 +       unsigned long long ino;         /* inode number */
204 +       int max_entries;                /* maximum extents count */
205 +       int entries;                    /* extent number/count */
206 +       ext4_lblk_t f_offset;           /* file offset */
207 +       ext4_grpblk_t g_offset;         /* group offset */
208 +       ext4_fsblk_t goal;              /* block offset for allocation */
209 +       struct ext4_extent_data ext[DEFRAG_MAX_ENT];
212  #define EXT4_TRANS_META_BLOCKS 4 /* bitmap + group desc + sb + inode */
214  /*
215 @@ -1015,6 +1040,8 @@ extern struct ext4_group_desc * ext4_get_group_desc(struct super_block * sb,
216  extern int ext4_should_retry_alloc(struct super_block *sb, int *retries);
217  extern void ext4_init_block_alloc_info(struct inode *);
218  extern void ext4_rsv_window_add(struct super_block *sb, struct ext4_reserve_window_node *rsv);
219 +extern ext4_grpblk_t bitmap_search_next_usable_block(ext4_grpblk_t,
220 +                               struct buffer_head *, ext4_grpblk_t);
222  /* dir.c */
223  extern int ext4_check_dir_entry(const char *, struct inode *,
224 diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c
225 index c05502f..40bc2e1 100644
226 --- a/fs/ext4/ioctl.c
227 +++ b/fs/ext4/ioctl.c
228 @@ -258,7 +258,8 @@ setversion_out:
229         }
230         case EXT4_IOC_FIBMAP:
231         case EXT4_IOC_DEFRAG:
232 -       case EXT4_IOC_GROUP_INFO: {
233 +       case EXT4_IOC_GROUP_INFO:
234 +       case EXT4_IOC_FREE_BLOCKS_INFO: {
235                 return ext4_defrag_ioctl(inode, filp, cmd, arg);
236         }
237         case EXT4_IOC_GROUP_ADD: {
240 To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
241 the body of a message to majordomo@vger.kernel.org
242 More majordomo info at  http://vger.kernel.org/majordomo-info.html