Add journal checksum patches. Also move
[ext4-patch-queue.git] / ext4-online-defrag-alloc-contiguous-blks.patch
blobe0c56bb9f130323ad4a3813f626b02aa71c5fc73
1 ext4: online defrag-- Allocate new contiguous blocks with mballoc
3 From: Akira Fujita <a-fujita@rs.jp.nec.com>
5 Search contiguous free blocks with mutil-block allocation
6 and allocate them for the temporary inode.
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/defrag.c | 281 ++++++++++++++++++++++++++++++++++++++++++++++++-
12 fs/ext4/ext4.h | 4
13 fs/ext4/ext4_extents.h | 3
14 fs/ext4/extents.c | 6 -
15 4 files changed, 289 insertions(+), 5 deletions(-)
17 Index: linux-2.6.26-rc4/fs/ext4/defrag.c
18 ===================================================================
19 --- linux-2.6.26-rc4.orig/fs/ext4/defrag.c 2008-06-01 15:10:05.000000000 -0700
20 +++ linux-2.6.26-rc4/fs/ext4/defrag.c 2008-06-01 15:10:51.000000000 -0700
21 @@ -34,7 +34,60 @@ static int
22 ext4_defrag_next_extent(struct inode *inode, struct ext4_ext_path *path,
23 struct ext4_extent **extent)
25 - return 0;
26 + int ppos, leaf_ppos = path->p_depth;
28 + ppos = leaf_ppos;
29 + if (EXT_LAST_EXTENT(path[ppos].p_hdr) > path[ppos].p_ext) {
30 + /* leaf block */
31 + *extent = ++path[ppos].p_ext;
32 + return 0;
33 + }
35 + while (--ppos >= 0) {
36 + if (EXT_LAST_INDEX(path[ppos].p_hdr) >
37 + path[ppos].p_idx) {
38 + int cur_ppos = ppos;
40 + /* index block */
41 + path[ppos].p_idx++;
42 + path[ppos].p_block = idx_pblock(path[ppos].p_idx);
43 + if (path[ppos+1].p_bh)
44 + brelse(path[ppos+1].p_bh);
45 + path[ppos+1].p_bh =
46 + sb_bread(inode->i_sb, path[ppos].p_block);
47 + if (!path[ppos+1].p_bh)
48 + goto err;
49 + path[ppos+1].p_hdr =
50 + ext_block_hdr(path[ppos+1].p_bh);
52 + /* Halfway index block */
53 + while (++cur_ppos < leaf_ppos) {
54 + path[cur_ppos].p_idx =
55 + EXT_FIRST_INDEX(path[cur_ppos].p_hdr);
56 + path[cur_ppos].p_block =
57 + idx_pblock(path[cur_ppos].p_idx);
58 + if (path[cur_ppos+1].p_bh)
59 + brelse(path[cur_ppos+1].p_bh);
60 + path[cur_ppos+1].p_bh = sb_bread(inode->i_sb,
61 + path[cur_ppos].p_block);
62 + if (!path[cur_ppos+1].p_bh)
63 + goto err;
64 + path[cur_ppos+1].p_hdr =
65 + ext_block_hdr(path[cur_ppos+1].p_bh);
66 + }
68 + /* leaf block */
69 + path[leaf_ppos].p_ext = *extent =
70 + EXT_FIRST_EXTENT(path[leaf_ppos].p_hdr);
71 + return 0;
72 + }
73 + }
74 + /* We found the last extent */
75 + return 1;
76 +err:
77 + if (path)
78 + ext4_ext_drop_refs(path);
79 + return -EIO;
82 int ext4_defrag_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
83 @@ -81,6 +134,86 @@ int ext4_defrag_ioctl(struct inode *inod
86 /**
87 + * ext4_defrag_fill_ar - Prepare to multiple block allocate for tmp inode
88 + *
89 + * @org_inode: original inode
90 + * @dest_inode: temporary inode
91 + * @ar: allocation request for multiple block allocation
92 + * @org_path: indicating the original inode's extent
93 + * @dest_path: indicating the temporary inode's extent
94 + * @req_blocks: contiguous blocks count we need
95 + * @iblock: target file offset
96 + *
97 + */
98 +static void
99 +ext4_defrag_fill_ar(struct inode *org_inode, struct inode *dest_inode,
100 + struct ext4_allocation_request *ar,
101 + struct ext4_ext_path *org_path,
102 + struct ext4_ext_path *dest_path,
103 + ext4_fsblk_t req_blocks, ext4_lblk_t iblock)
105 + ar->inode = dest_inode;
106 + ar->len = req_blocks;
107 + ar->logical = iblock;
108 + ar->flags = EXT4_MB_HINT_DATA | EXT4_MB_HINT_RESERVED
109 + | EXT4_MB_HINT_NOPREALLOC;
110 + ar->lleft = 0;
111 + ar->pleft = 0;
112 + ar->lright = 0;
113 + ar->pright = 0;
115 + ar->goal = ext4_ext_find_goal(dest_inode, dest_path, iblock);
118 +/**
119 + * ext4_defrag_alloc_blocks - Allocate contiguous blocks to temporary inode
121 + * @handle: journal handle
122 + * @org_inode: original inode
123 + * @dest_inode: temporary inode for multiple block allocation
124 + * @ar: allocation request for multiple block allocation
125 + * @dest_path: indicating the temporary inode's extent
126 + * @newblock: start offset of contiguous blocks
128 + * This function returns 0 if succeeed, otherwise returns error value.
129 + */
130 +static int
131 +ext4_defrag_alloc_blocks(handle_t *handle, struct inode *org_inode,
132 + struct inode *dest_inode, struct ext4_allocation_request *ar,
133 + struct ext4_ext_path *dest_path, ext4_fsblk_t *newblock)
135 + struct super_block *sb = org_inode->i_sb;
136 + struct buffer_head *bh = NULL;
137 + int err, i, credits = 0;
139 + credits = ext4_ext_calc_credits_for_insert(dest_inode, dest_path);
140 + handle = ext4_ext_journal_restart(handle,
141 + credits + EXT4_TRANS_META_BLOCKS);
142 + if (IS_ERR(handle)) {
143 + err = PTR_ERR(handle);
144 + return err;
147 + *newblock = ext4_mb_new_blocks(handle, ar, &err);
148 + if (err)
149 + return err;
151 + /*
152 + * Dirty buffer_head causes the overwriting
153 + * if ext4_mb_new_blocks() allocates the block
154 + * which used to be the metadata block.
155 + * We should call unmap_underlying_metadata()
156 + * to clear the dirty flag.
157 + */
158 + for (i = 0; i < ar->len; i++) {
159 + bh = sb_find_get_block(sb, *newblock + i);
160 + unmap_underlying_metadata(sb->s_bdev, *newblock + i);
163 + return err;
166 +/**
167 * ext4_defrag_partial - Defrag a file per page
169 * @tmp_inode: temporary inode
170 @@ -99,6 +232,70 @@ ext4_defrag_partial(struct inode *tmp_in
174 + * ext4_defrag_comp_ext_count- Check whether fragments are improved or not
176 + * @org_inode: original inode
177 + * @path: the structure holding some info about
178 + * original extent tree
179 + * @tar_end: the last block number of the allocated blocks
180 + * @sum_tmp: the extents count in the allocated blocks
183 + * This function returns the values as below.
184 + * 0 (improved)
185 + * 1 (not improved)
186 + * negative value (error case)
187 + */
188 +static int
189 +ext4_defrag_comp_ext_count(struct inode *org_inode,
190 + struct ext4_ext_path *org_path, ext4_lblk_t tar_end,
191 + int sum_tmp)
193 + struct ext4_extent *ext = NULL;
194 + int depth = ext_depth(org_inode);
195 + int last_extent = 0;
196 + int sum_org = 0;
197 + int ret = 0;
199 + ext = org_path[depth].p_ext;
201 + /*
202 + * Compare the number of the newly allocated extents to
203 + * that of existing one.
204 + */
205 + while (1) {
206 + if (!last_extent)
207 + ++sum_org;
208 + if (tar_end <= (le32_to_cpu(ext->ee_block) +
209 + le16_to_cpu(ext->ee_len) - 1) ||
210 + last_extent) {
211 + /*
212 + * Fail if goal is not set and the fragmentation
213 + * is not improved.
214 + */
215 + if (sum_org == sum_tmp) {
216 + /* Not improved */
217 + ret = 1;
218 + } else if (sum_org < sum_tmp) {
219 + /* Fragment increased */
220 + ret = -ENOSPC;
221 + printk(KERN_ERR "ext4 defrag: "
222 + "Insufficient free blocks\n");
224 + break;
226 + last_extent =
227 + ext4_defrag_next_extent(org_inode, org_path, &ext);
228 + if (last_extent < 0) {
229 + ret = last_extent;
230 + break;
234 + return ret;
237 +/**
238 * ext4_defrag_new_extent_tree - Get contiguous blocks and build an extent tree
240 * @org_inode: original inode
241 @@ -119,7 +316,87 @@ ext4_defrag_new_extent_tree(struct inode
242 struct ext4_ext_path *org_path, ext4_lblk_t tar_start,
243 ext4_lblk_t tar_blocks, ext4_lblk_t iblock)
245 - return 0;
246 + handle_t *handle;
247 + struct ext4_extent_header *eh = NULL;
248 + struct ext4_allocation_request ar;
249 + struct ext4_ext_path *dest_path = NULL;
250 + struct ext4_extent newex;
251 + ext4_fsblk_t alloc_total = 0;
252 + ext4_fsblk_t newblock = 0;
253 + ext4_lblk_t tar_end = tar_start + tar_blocks - 1;
254 + int sum_tmp = 0;
255 + int metadata = 1;
256 + int ret, ret2;
258 + eh = ext_inode_hdr(tmp_inode);
259 + eh->eh_depth = 0;
261 + dest_path = ext4_ext_find_extent(tmp_inode, iblock, NULL);
262 + if (IS_ERR(dest_path)) {
263 + ret = PTR_ERR(dest_path);
264 + dest_path = NULL;
265 + goto out2;
268 + /* Fill struct ext4_allocation_request with necessary info */
269 + ext4_defrag_fill_ar(org_inode, tmp_inode, &ar, org_path,
270 + dest_path, tar_blocks, iblock);
272 + handle = ext4_journal_start(tmp_inode, 0);
273 + if (IS_ERR(handle)) {
274 + ret = PTR_ERR(handle);
275 + goto out2;
278 + while (alloc_total != tar_blocks) {
279 + /* Allocate blocks */
280 + ret = ext4_defrag_alloc_blocks(handle, org_inode, tmp_inode,
281 + &ar, dest_path, &newblock);
282 + if (ret < 0)
283 + goto out;
285 + alloc_total += ar.len;
287 + newex.ee_block = cpu_to_le32(alloc_total - ar.len);
288 + ext4_ext_store_pblock(&newex, newblock);
289 + newex.ee_len = cpu_to_le16(ar.len);
291 + ret = ext4_ext_insert_extent(handle, tmp_inode,
292 + dest_path, &newex);
293 + if (ret < 0)
294 + goto out;
296 + ar.goal = newblock + ar.len;
297 + ar.len = tar_blocks - alloc_total;
298 + sum_tmp++;
301 + ret = ext4_defrag_comp_ext_count(org_inode, org_path, tar_end,
302 + sum_tmp);
304 +out:
305 + if (ret < 0 || ret == 1) {
306 + if (ar.len)
307 + ext4_free_blocks(handle, tmp_inode, newblock, ar.len,
308 + metadata);
309 + /* Faild case: We have to remove halfway blocks */
310 + ret2 = ext4_ext_remove_space(tmp_inode, 0);
311 + if (ret2) {
312 + printk(KERN_ERR "ext4 defrag: "
313 + "Failed to remove temporary inode blocks\n");
314 + ret = ret2;
318 + ext4_journal_stop(handle);
320 +out2:
321 + if (dest_path) {
322 + ext4_ext_drop_refs(dest_path);
323 + kfree(dest_path);
326 + return ret;
330 Index: linux-2.6.26-rc4/fs/ext4/ext4.h
331 ===================================================================
332 --- linux-2.6.26-rc4.orig/fs/ext4/ext4.h 2008-06-01 15:10:05.000000000 -0700
333 +++ linux-2.6.26-rc4/fs/ext4/ext4.h 2008-06-01 15:11:30.000000000 -0700
334 @@ -331,6 +331,7 @@ struct ext4_ext_defrag_data {
335 ext4_fsblk_t goal; /* block offset for allocation */
338 +#define EXT4_TRANS_META_BLOCKS 4 /* bitmap + group desc + sb + inode */
341 * Mount options
342 @@ -1132,6 +1133,8 @@ extern void ext4_inode_bitmap_set(struct
343 struct ext4_group_desc *bg, ext4_fsblk_t blk);
344 extern void ext4_inode_table_set(struct super_block *sb,
345 struct ext4_group_desc *bg, ext4_fsblk_t blk);
346 +/* extents.c */
347 +extern handle_t *ext4_ext_journal_restart(handle_t *handle, int needed);
348 /* defrag.c */
349 extern int ext4_defrag(struct file *filp, ext4_lblk_t block_start,
350 ext4_lblk_t defrag_size);
351 @@ -1254,6 +1257,7 @@ extern int ext4_get_blocks_wrap(handle_t
352 sector_t block, unsigned long max_blocks,
353 struct buffer_head *bh, int create,
354 int extend_disksize, int flag);
355 +extern int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start);
356 #endif /* __KERNEL__ */
358 #endif /* _EXT4_H */
359 Index: linux-2.6.26-rc4/fs/ext4/ext4_extents.h
360 ===================================================================
361 --- linux-2.6.26-rc4.orig/fs/ext4/ext4_extents.h 2008-06-01 15:10:05.000000000 -0700
362 +++ linux-2.6.26-rc4/fs/ext4/ext4_extents.h 2008-06-01 15:10:51.000000000 -0700
363 @@ -231,5 +231,8 @@ extern int ext4_ext_search_right(struct
364 extern void ext4_ext_drop_refs(struct ext4_ext_path *);
365 extern ext4_fsblk_t ext_pblock(struct ext4_extent *ex);
366 extern void ext4_ext_drop_refs(struct ext4_ext_path *path);
367 +extern ext4_fsblk_t ext4_ext_find_goal(struct inode *inode,
368 + struct ext4_ext_path *path,
369 + ext4_lblk_t block);
370 #endif /* _EXT4_EXTENTS */
372 Index: linux-2.6.26-rc4/fs/ext4/extents.c
373 ===================================================================
374 --- linux-2.6.26-rc4.orig/fs/ext4/extents.c 2008-06-01 15:10:05.000000000 -0700
375 +++ linux-2.6.26-rc4/fs/ext4/extents.c 2008-06-01 15:10:51.000000000 -0700
376 @@ -92,7 +92,7 @@ static void ext4_idx_store_pblock(struct
377 ix->ei_leaf_hi = cpu_to_le16((unsigned long) ((pb >> 31) >> 1) & 0xffff);
380 -static handle_t *ext4_ext_journal_restart(handle_t *handle, int needed)
381 +handle_t *ext4_ext_journal_restart(handle_t *handle, int needed)
383 int err;
385 @@ -142,7 +142,7 @@ static int ext4_ext_dirty(handle_t *hand
386 return err;
389 -static ext4_fsblk_t ext4_ext_find_goal(struct inode *inode,
390 +ext4_fsblk_t ext4_ext_find_goal(struct inode *inode,
391 struct ext4_ext_path *path,
392 ext4_lblk_t block)
394 @@ -1986,7 +1986,7 @@ ext4_ext_more_to_rm(struct ext4_ext_path
395 return 1;
398 -static int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start)
399 +int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start)
401 struct super_block *sb = inode->i_sb;
402 int depth = ext_depth(inode);