Add ext4-printk-throttling patch
[ext4-patch-queue.git] / ext4-online-defrag-check-for-freespace-fragmentation.patch
blobf9e6c5dfc2d8a616065f79e69b4220e62a368b80
1 ext4: online defrag-- Check the free space fragmentation (-f mode)
3 From: Akira Fujita <a-fujita@rs.jp.nec.com>
5 Check the free space fragmentation in the block group
6 where target file is located.
8 Signed-off-by: Akira Fujita <a-fujita@rs.jp.nec.com>
9 Signed-off-by: Takashi Sato <t-sato@yk.jp.nec.com>
10 ---
11 fs/ext4/balloc.c | 2
12 fs/ext4/defrag.c | 275 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
13 fs/ext4/ext4.h | 34 ++++++
14 fs/ext4/ioctl.c | 5 -
15 4 files changed, 312 insertions(+), 4 deletions(-)
17 Index: linux-2.6.26-rc9/fs/ext4/balloc.c
18 ===================================================================
19 --- linux-2.6.26-rc9.orig/fs/ext4/balloc.c 2008-07-11 16:05:13.000000000 -0700
20 +++ linux-2.6.26-rc9/fs/ext4/balloc.c 2008-07-11 16:05:20.000000000 -0700
21 @@ -914,7 +914,7 @@ static int ext4_test_allocatable(ext4_gr
22 * bitmap on disk and the last-committed copy in journal, until we find a
23 * bit free in both bitmaps.
25 -static ext4_grpblk_t
26 +ext4_grpblk_t
27 bitmap_search_next_usable_block(ext4_grpblk_t start, struct buffer_head *bh,
28 ext4_grpblk_t maxblocks)
30 Index: linux-2.6.26-rc9/fs/ext4/defrag.c
31 ===================================================================
32 --- linux-2.6.26-rc9.orig/fs/ext4/defrag.c 2008-07-11 16:05:19.000000000 -0700
33 +++ linux-2.6.26-rc9/fs/ext4/defrag.c 2008-07-11 16:05:20.000000000 -0700
34 @@ -20,6 +20,12 @@
35 #include "ext4_extents.h"
36 #include "group.h"
38 +#define EXT_SET_EXTENT_DATA(src, dest) do { \
39 + dest.block = le32_to_cpu(src->ee_block); \
40 + dest.start = ext_pblock(src); \
41 + dest.len = le16_to_cpu(src->ee_len); \
42 + } while (0)
44 /**
45 * ext4_defrag_next_extent - Search for the next extent and set it to "extent"
47 @@ -90,6 +96,223 @@ err:
48 return -EIO;
51 +/**
52 + * ext4_defrag_extents_info - Get extents information
53 + *
54 + * @sb: for ext4_iget()
55 + * @ext_info: pointer to ext4_extents_info
56 + * @ext_info->ino: describe an inode which is used to get
57 + * extent information
58 + * @ext_info->max_entries: defined by DEFRAG_MAX_ENT
59 + * @ext_info->entries: amount of extents (output)
60 + * @ext_info->ext[]: array of extent (output)
61 + * @ext_info->offset: starting block offset of targeted extent
62 + * (file relative)
63 + *
64 + * This function returns 0 if the next extent(s) exists,
65 + * or returns 1 if the next extent doesn't exist,
66 + * otherwise returns error value.
67 + */
68 +static int
69 +ext4_defrag_extents_info(struct super_block *sb,
70 + struct ext4_extents_info *ext_info)
72 + struct ext4_ext_path *path = NULL;
73 + struct ext4_extent *ext = NULL;
74 + struct inode *inode = NULL;
75 + ext4_lblk_t offset = ext_info->f_offset;
76 + int max_entries = ext_info->max_entries;
77 + int depth, entries = 0;
78 + int err = 0;
79 + int ret = 0;
81 + inode = ext4_iget(sb, ext_info->ino);
82 + if (IS_ERR(inode))
83 + return PTR_ERR(inode);
85 + down_write(&EXT4_I(inode)->i_data_sem);
87 + /* Return -ENOENT if a file does not exist */
88 + if (!inode->i_nlink || inode->i_ino < EXT4_GOOD_OLD_FIRST_INO ||
89 + !S_ISREG(inode->i_mode)) {
90 + ext_info->entries = 0;
91 + err = -ENOENT;
92 + goto out;
93 + }
95 + path = ext4_ext_find_extent(inode, offset, NULL);
96 + if (IS_ERR(path)) {
97 + err = PTR_ERR(path);
98 + path = NULL;
99 + goto out;
101 + depth = ext_depth(inode);
103 + /* Skip the 0 size file */
104 + if (path[depth].p_ext == NULL) {
105 + ext_info->entries = 0;
106 + goto out;
108 + ext = path[depth].p_ext;
109 + EXT_SET_EXTENT_DATA(ext, ext_info->ext[entries]);
110 + entries = 1;
112 + /*
113 + * The ioctl repeats this loop 'max_entries' times.
114 + * So we have to call this function again if @inode had
115 + * more the number of extents than 'max_entries'.
116 + */
117 + while (entries < max_entries) {
118 + ret = ext4_defrag_next_extent(inode, path, &ext);
119 + if (ret == 0) {
120 + /* Found the next extent (it means not the last one) */
121 + EXT_SET_EXTENT_DATA(ext, ext_info->ext[entries]);
122 + entries++;
124 + /*
125 + * In case @inode has > 'max_entries' extents,
126 + * we must call this function again and restart from
127 + * 'max_entries * n + 1'th extent.
128 + * 'n' is the number of calling this function
129 + * at the same @inode.
130 + */
131 + if (entries == max_entries) {
132 + ext_info->f_offset =
133 + le32_to_cpu(ext->ee_block) +
134 + le16_to_cpu(ext->ee_len);
135 + /* Check the extent is the last one or not */
136 + ret =
137 + ext4_defrag_next_extent(inode, path, &ext);
138 + if (ret == 1) {
139 + err = ret;
140 + } else if (ret < 0) {
141 + /* Failed to get the next extent */
142 + err = ret;
143 + goto out;
145 + break;
148 + } else if (ret == 1) {
149 + /* The extent is the last one */
150 + ext_info->f_offset = 0;
151 + err = ret;
152 + break;
153 + } else {
154 + /* Failed to get the next extent */
155 + err = ret;
156 + goto out;
160 + ext_info->entries = entries;
162 +out:
163 + if (path) {
164 + ext4_ext_drop_refs(path);
165 + kfree(path);
167 + up_write(&EXT4_I(inode)->i_data_sem);
168 + iput(inode);
169 + return err;
172 +/**
173 + * ext4_defrag_fblocks_distribution - Search free blocks distribution
175 + * @org_inode: original inode
176 + * @ext_info: ext4_extents_info
178 + * This function returns 0 if succeed, otherwise returns error value.
179 + */
180 +static int
181 +ext4_defrag_fblocks_distribution(struct inode *org_inode,
182 + struct ext4_extents_info *ext_info)
184 + struct buffer_head *bitmap_bh = NULL;
185 + struct super_block *sb = org_inode->i_sb;
186 + handle_t *handle;
187 + ext4_group_t group_no;
188 + ext4_grpblk_t start, end;
189 + ext4_fsblk_t start_block = 0;
190 + int i, err;
191 + int num = 0;
192 + int len = 0;
193 + int block_set = 0;
194 + int extra_block = 0;
196 + if (!sb) {
197 + printk(KERN_ERR "ext4 defrag: Non-existent device\n");
198 + return -ENOSPC;
201 + group_no = (org_inode->i_ino - 1) / EXT4_INODES_PER_GROUP(sb);
202 + start = ext_info->g_offset;
203 + end = EXT4_BLOCKS_PER_GROUP(sb) - 1;
205 + /* We consider about the boot block if bs = 1k */
206 + if (sb->s_blocksize == 1024)
207 + extra_block = 1;
209 + handle = ext4_journal_start(org_inode, 1);
210 + if (IS_ERR(handle)) {
211 + err = PTR_ERR(handle);
212 + return err;
215 + bitmap_bh = ext4_read_block_bitmap(sb, group_no);
216 + if (!bitmap_bh) {
217 + err = -EIO;
218 + goto out;
221 + BUFFER_TRACE(bitmap_bh, "get undo access for new block");
222 + err = ext4_journal_get_undo_access(handle, bitmap_bh);
223 + if (err)
224 + goto out;
226 + for (i = start; i <= end ; i++) {
227 + if (bitmap_search_next_usable_block(i, bitmap_bh, i + 1) >= 0) {
228 + len++;
229 + /*
230 + * Reset start_block if the free block is
231 + * the head of region.
232 + */
233 + if (!block_set) {
234 + start_block =
235 + i + group_no * EXT4_BLOCKS_PER_GROUP(sb) +
236 + extra_block;
237 + block_set = 1;
239 + } else if (len) {
240 + ext_info->ext[num].start = start_block;
241 + ext_info->ext[num].len = len;
242 + num++;
243 + len = 0;
244 + block_set = 0;
245 + if (num == ext_info->max_entries) {
246 + ext_info->g_offset = i + 1;
247 + break;
250 + if (i == end && len) {
251 + ext_info->ext[num].start = start_block;
252 + ext_info->ext[num].len = len;
253 + num++;
257 + ext_info->entries = num;
258 +out:
259 + ext4_journal_release_buffer(handle, bitmap_bh);
260 + brelse(bitmap_bh);
262 + if (handle)
263 + ext4_journal_stop(handle);
265 + return err;
268 int ext4_defrag_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
269 unsigned long arg)
271 @@ -114,6 +337,52 @@ int ext4_defrag_ioctl(struct inode *inod
272 block = ext4_bmap(mapping, block);
274 return put_user(block, p);
275 + } else if (cmd == EXT4_IOC_GROUP_INFO) {
276 + struct ext4_group_data_info grp_data;
278 + if (copy_from_user(&grp_data,
279 + (struct ext4_group_data_info __user *)arg,
280 + sizeof(grp_data)))
281 + return -EFAULT;
283 + grp_data.s_blocks_per_group =
284 + EXT4_BLOCKS_PER_GROUP(inode->i_sb);
285 + grp_data.s_inodes_per_group =
286 + EXT4_INODES_PER_GROUP(inode->i_sb);
288 + if (copy_to_user((struct ext4_group_data_info __user *)arg,
289 + &grp_data, sizeof(grp_data)))
290 + return -EFAULT;
291 + } else if (cmd == EXT4_IOC_FREE_BLOCKS_INFO) {
292 + struct ext4_extents_info ext_info;
294 + if (copy_from_user(&ext_info,
295 + (struct ext4_extents_info __user *)arg,
296 + sizeof(ext_info)))
297 + return -EFAULT;
299 + BUG_ON(ext_info.ino != inode->i_ino);
301 + err = ext4_defrag_fblocks_distribution(inode, &ext_info);
303 + if (!err)
304 + err = copy_to_user(
305 + (struct ext4_extents_info __user *)arg,
306 + &ext_info, sizeof(ext_info));
307 + } else if (cmd == EXT4_IOC_EXTENTS_INFO) {
308 + struct ext4_extents_info ext_info;
310 + if (copy_from_user(&ext_info,
311 + (struct ext4_extents_info __user *)arg,
312 + sizeof(ext_info)))
313 + return -EFAULT;
315 + err = ext4_defrag_extents_info(inode->i_sb, &ext_info);
316 + if (err >= 0) {
317 + if (copy_to_user((struct ext4_extents_info __user *)arg,
318 + &ext_info, sizeof(ext_info)))
319 + return -EFAULT;
321 } else if (cmd == EXT4_IOC_DEFRAG) {
322 struct ext4_ext_defrag_data defrag;
323 struct ext4_super_block *es = EXT4_SB(inode->i_sb)->s_es;
324 @@ -1125,11 +1394,13 @@ out2:
326 * @org_inode: original inode
327 * @defrag_size: size of defrag in blocks
328 + * @goal: poiter to block offset for allocation
330 * This function returns 0 if succeed, otherwise returns error value.
332 static int
333 -ext4_defrag_check(struct inode *org_inode, ext4_lblk_t defrag_size)
334 +ext4_defrag_check(struct inode *org_inode, ext4_lblk_t defrag_size,
335 + ext4_fsblk_t *goal)
338 /* ext4 online defrag supports only 4KB block size */
339 @@ -1240,7 +1511,7 @@ ext4_defrag(struct file *filp, ext4_lblk
340 int ret, depth, seq_extents, last_extent = 0;
342 /* Check the filesystem enviroment whether defrag can be done */
343 - ret = ext4_defrag_check(org_inode, defrag_size);
344 + ret = ext4_defrag_check(org_inode, defrag_size, &goal);
345 if (ret < 0)
346 return ret;
348 Index: linux-2.6.26-rc9/fs/ext4/ext4.h
349 ===================================================================
350 --- linux-2.6.26-rc9.orig/fs/ext4/ext4.h 2008-07-11 16:05:19.000000000 -0700
351 +++ linux-2.6.26-rc9/fs/ext4/ext4.h 2008-07-11 16:05:20.000000000 -0700
352 @@ -303,6 +303,9 @@ struct ext4_new_group_data {
353 #define EXT4_IOC_MIGRATE _IO('f', 7)
354 #define EXT4_IOC_FIBMAP _IOW('f', 9, ext4_fsblk_t)
355 #define EXT4_IOC_DEFRAG _IOW('f', 10, struct ext4_ext_defrag_data)
356 +#define EXT4_IOC_GROUP_INFO _IOW('f', 11, struct ext4_group_data_info)
357 +#define EXT4_IOC_FREE_BLOCKS_INFO _IOW('f', 12, struct ext4_extents_info)
358 +#define EXT4_IOC_EXTENTS_INFO _IOW('f', 13, struct ext4_extents_info)
361 * ioctl commands in 32 bit emulation
362 @@ -326,12 +329,41 @@ struct ext4_new_group_data {
364 #define DEFRAG_BLOCK_SIZE 4096
367 + * The following four macros are used for the defrag force mode.
369 + * DEFRAG_MAX_ENT: the maximum number of extents for exchanging between
370 + * kernel-space and user-space per an ioctl
371 + */
372 +#define DEFRAG_MAX_ENT 32
374 +struct ext4_extent_data {
375 + ext4_lblk_t block; /* start logical block number */
376 + ext4_fsblk_t start; /* start physical block number */
377 + int len; /* blocks count */
380 struct ext4_ext_defrag_data {
381 ext4_lblk_t start_offset; /* start offset to defrag in blocks */
382 ext4_lblk_t defrag_size; /* size of defrag in blocks */
383 ext4_fsblk_t goal; /* block offset for allocation */
386 +struct ext4_group_data_info {
387 + int s_blocks_per_group; /* blocks per group */
388 + int s_inodes_per_group; /* inodes per group */
391 +struct ext4_extents_info {
392 + unsigned long long ino; /* inode number */
393 + int max_entries; /* maximum extents count */
394 + int entries; /* extent number/count */
395 + ext4_lblk_t f_offset; /* file offset */
396 + ext4_grpblk_t g_offset; /* group offset */
397 + ext4_fsblk_t goal; /* block offset for allocation */
398 + struct ext4_extent_data ext[DEFRAG_MAX_ENT];
401 #define EXT4_TRANS_META_BLOCKS 4 /* bitmap + group desc + sb + inode */
404 @@ -1013,6 +1045,8 @@ extern struct ext4_group_desc * ext4_get
405 extern int ext4_should_retry_alloc(struct super_block *sb, int *retries);
406 extern void ext4_init_block_alloc_info(struct inode *);
407 extern void ext4_rsv_window_add(struct super_block *sb, struct ext4_reserve_window_node *rsv);
408 +extern ext4_grpblk_t bitmap_search_next_usable_block(ext4_grpblk_t,
409 + struct buffer_head *, ext4_grpblk_t);
411 /* dir.c */
412 extern int ext4_check_dir_entry(const char *, struct inode *,
413 Index: linux-2.6.26-rc9/fs/ext4/ioctl.c
414 ===================================================================
415 --- linux-2.6.26-rc9.orig/fs/ext4/ioctl.c 2008-07-11 16:05:19.000000000 -0700
416 +++ linux-2.6.26-rc9/fs/ext4/ioctl.c 2008-07-11 16:05:20.000000000 -0700
417 @@ -242,7 +242,10 @@ setversion_out:
418 return err;
420 case EXT4_IOC_FIBMAP:
421 - case EXT4_IOC_DEFRAG: {
422 + case EXT4_IOC_DEFRAG:
423 + case EXT4_IOC_GROUP_INFO:
424 + case EXT4_IOC_FREE_BLOCKS_INFO:
425 + case EXT4_IOC_EXTENTS_INFO: {
426 return ext4_defrag_ioctl(inode, filp, cmd, arg);
428 case EXT4_IOC_GROUP_ADD: {