Add missing patches (centralize-proc-functions and make-proc-generic)
[ext4-patch-queue.git] / ext4-fiemap.patch
blob185265e56ce356eef8b79c8e7065f8ea739aa6f0
1 From: Eric Sandeen <sandeen@redhat.com>
3 Hook ext4 to the vfs fiemap interface.
5 ext4_ext_walk_space() was reinstated to be used for iterating over file
6 extents with a callback; it is used by the ext4 fiemap implementation.
8 Signed-off-by: Eric Sandeen <sandeen@redhat.com>
9 Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
10 ---
11 fs/ext4/ext4.h | 2 +
12 fs/ext4/ext4_extents.h | 15 +++
13 fs/ext4/extents.c | 248 ++++++++++++++++++++++++++++++++++++++++++++++++
14 fs/ext4/file.c | 4 +
15 fs/ext4/inode.c | 2 +-
16 5 files changed, 270 insertions(+), 1 deletions(-)
18 Index: linux-2.6/fs/ext4/ext4.h
19 ===================================================================
20 --- linux-2.6.orig/fs/ext4/ext4.h 2008-07-14 16:51:40.000000000 -0500
21 +++ linux-2.6/fs/ext4/ext4.h 2008-07-14 16:56:12.038353463 -0500
22 @@ -1127,6 +1127,8 @@ struct buffer_head *ext4_getblk(handle_t
23 ext4_lblk_t, int, int *);
24 struct buffer_head *ext4_bread(handle_t *, struct inode *,
25 ext4_lblk_t, int, int *);
26 +int ext4_get_block(struct inode *inode, sector_t iblock,
27 + struct buffer_head *bh_result, int create);
28 int ext4_get_blocks_handle(handle_t *handle, struct inode *inode,
29 ext4_lblk_t iblock, unsigned long maxblocks,
30 struct buffer_head *bh_result,
31 Index: linux-2.6/fs/ext4/ext4_extents.h
32 ===================================================================
33 --- linux-2.6.orig/fs/ext4/ext4_extents.h 2008-07-14 16:51:41.000000000 -0500
34 +++ linux-2.6/fs/ext4/ext4_extents.h 2008-07-14 16:56:12.040354241 -0500
35 @@ -124,6 +124,19 @@ struct ext4_ext_path {
36 #define EXT4_EXT_CACHE_GAP 1
37 #define EXT4_EXT_CACHE_EXTENT 2
39 +/*
40 + * to be called by ext4_ext_walk_space()
41 + * negative retcode - error
42 + * positive retcode - signal for ext4_ext_walk_space(), see below
43 + * callback must return valid extent (passed or newly created)
44 + */
45 +typedef int (*ext_prepare_callback)(struct inode *, struct ext4_ext_path *,
46 + struct ext4_ext_cache *,
47 + struct ext4_extent *, void *);
49 +#define EXT_CONTINUE 0
50 +#define EXT_BREAK 1
51 +#define EXT_REPEAT 2
53 #define EXT_MAX_BLOCK 0xffffffff
55 @@ -222,6 +235,8 @@ extern int ext4_ext_try_to_merge(struct
56 struct ext4_extent *);
57 extern unsigned int ext4_ext_check_overlap(struct inode *, struct ext4_extent *, struct ext4_ext_path *);
58 extern int ext4_ext_insert_extent(handle_t *, struct inode *, struct ext4_ext_path *, struct ext4_extent *);
59 +extern int ext4_ext_walk_space(struct inode *, ext4_lblk_t, ext4_lblk_t,
60 + ext_prepare_callback, void *);
61 extern struct ext4_ext_path *ext4_ext_find_extent(struct inode *, ext4_lblk_t,
62 struct ext4_ext_path *);
63 extern int ext4_ext_search_left(struct inode *, struct ext4_ext_path *,
64 Index: linux-2.6/fs/ext4/extents.c
65 ===================================================================
66 --- linux-2.6.orig/fs/ext4/extents.c 2008-07-14 16:51:41.000000000 -0500
67 +++ linux-2.6/fs/ext4/extents.c 2008-07-14 16:56:12.044353533 -0500
68 @@ -40,6 +40,7 @@
69 #include <linux/slab.h>
70 #include <linux/falloc.h>
71 #include <asm/uaccess.h>
72 +#include <linux/fiemap.h>
73 #include "ext4_jbd2.h"
74 #include "ext4_extents.h"
76 @@ -1656,6 +1657,113 @@ cleanup:
77 return err;
80 +int ext4_ext_walk_space(struct inode *inode, ext4_lblk_t block,
81 + ext4_lblk_t num, ext_prepare_callback func,
82 + void *cbdata)
84 + struct ext4_ext_path *path = NULL;
85 + struct ext4_ext_cache cbex;
86 + struct ext4_extent *ex;
87 + ext4_lblk_t next, start = 0, end = 0;
88 + ext4_lblk_t last = block + num;
89 + int depth, exists, err = 0;
91 + BUG_ON(func == NULL);
92 + BUG_ON(inode == NULL);
94 + while (block < last && block != EXT_MAX_BLOCK) {
95 + num = last - block;
96 + /* find extent for this block */
97 + path = ext4_ext_find_extent(inode, block, path);
98 + if (IS_ERR(path)) {
99 + err = PTR_ERR(path);
100 + path = NULL;
101 + break;
104 + depth = ext_depth(inode);
105 + BUG_ON(path[depth].p_hdr == NULL);
106 + ex = path[depth].p_ext;
107 + next = ext4_ext_next_allocated_block(path);
109 + exists = 0;
110 + if (!ex) {
111 + /* there is no extent yet, so try to allocate
112 + * all requested space */
113 + start = block;
114 + end = block + num;
115 + } else if (le32_to_cpu(ex->ee_block) > block) {
116 + /* need to allocate space before found extent */
117 + start = block;
118 + end = le32_to_cpu(ex->ee_block);
119 + if (block + num < end)
120 + end = block + num;
121 + } else if (block >= le32_to_cpu(ex->ee_block)
122 + + ext4_ext_get_actual_len(ex)) {
123 + /* need to allocate space after found extent */
124 + start = block;
125 + end = block + num;
126 + if (end >= next)
127 + end = next;
128 + } else if (block >= le32_to_cpu(ex->ee_block)) {
129 + /*
130 + * some part of requested space is covered
131 + * by found extent
132 + */
133 + start = block;
134 + end = le32_to_cpu(ex->ee_block)
135 + + ext4_ext_get_actual_len(ex);
136 + if (block + num < end)
137 + end = block + num;
138 + exists = 1;
139 + } else {
140 + BUG();
142 + BUG_ON(end <= start);
144 + if (!exists) {
145 + cbex.ec_block = start;
146 + cbex.ec_len = end - start;
147 + cbex.ec_start = 0;
148 + cbex.ec_type = EXT4_EXT_CACHE_GAP;
149 + } else {
150 + cbex.ec_block = le32_to_cpu(ex->ee_block);
151 + cbex.ec_len = ext4_ext_get_actual_len(ex);
152 + cbex.ec_start = ext_pblock(ex);
153 + cbex.ec_type = EXT4_EXT_CACHE_EXTENT;
156 + BUG_ON(cbex.ec_len == 0);
157 + err = func(inode, path, &cbex, ex, cbdata);
158 + ext4_ext_drop_refs(path);
160 + if (err < 0)
161 + break;
163 + if (err == EXT_REPEAT)
164 + continue;
165 + else if (err == EXT_BREAK) {
166 + err = 0;
167 + break;
170 + if (ext_depth(inode) != depth) {
171 + /* depth was changed. we have to realloc path */
172 + kfree(path);
173 + path = NULL;
176 + block = cbex.ec_block + cbex.ec_len;
179 + if (path) {
180 + ext4_ext_drop_refs(path);
181 + kfree(path);
184 + return err;
187 static void
188 ext4_ext_put_in_cache(struct inode *inode, ext4_lblk_t block,
189 __u32 len, ext4_fsblk_t start, int type)
190 @@ -3011,3 +3119,143 @@ retry:
191 mutex_unlock(&inode->i_mutex);
192 return ret > 0 ? ret2 : ret;
196 + * Callback function called for each extent to gather FIEMAP information.
197 + */
198 +int ext4_ext_fiemap_cb(struct inode *inode, struct ext4_ext_path *path,
199 + struct ext4_ext_cache *newex, struct ext4_extent *ex,
200 + void *data)
202 + struct fiemap_extent_info *fieinfo = data;
203 + unsigned long blksize_bits = inode->i_sb->s_blocksize_bits;
204 + __u64 logical;
205 + __u64 physical;
206 + __u64 length;
207 + __u32 flags = 0;
208 + int error;
210 + logical = (__u64)newex->ec_block << blksize_bits;
212 + if (newex->ec_type == EXT4_EXT_CACHE_GAP) {
213 + pgoff_t offset;
214 + struct page *page;
215 + struct buffer_head *bh = NULL;
217 + offset = logical >> PAGE_SHIFT;
218 + page = find_get_page(inode->i_mapping, offset);
219 + if (!page || !page_has_buffers(page))
220 + return EXT_CONTINUE;
222 + bh = page_buffers(page);
224 + if (!bh)
225 + return EXT_CONTINUE;
227 + if (buffer_delay(bh)) {
228 + flags |= FIEMAP_EXTENT_DELALLOC;
229 + page_cache_release(page);
230 + } else {
231 + page_cache_release(page);
232 + return EXT_CONTINUE;
236 + physical = (__u64)newex->ec_start << blksize_bits;
237 + length = (__u64)newex->ec_len << blksize_bits;
239 + if (ex && ext4_ext_is_uninitialized(ex))
240 + flags |= FIEMAP_EXTENT_UNWRITTEN;
242 + /*
243 + * If this extent reaches EXT_MAX_BLOCK, it must be last.
245 + * Or if ext4_ext_next_allocated_block is EXT_MAX_BLOCK,
246 + * this also indicates no more allocated blocks.
248 + * XXX this might miss a single-block extent at EXT_MAX_BLOCK
249 + */
250 + if (logical + length - 1 == EXT_MAX_BLOCK ||
251 + ext4_ext_next_allocated_block(path) == EXT_MAX_BLOCK)
252 + flags |= FIEMAP_EXTENT_LAST;
254 + error = fiemap_fill_next_extent(fieinfo, logical, physical,
255 + length, flags);
256 + if (error < 0)
257 + return error;
258 + if (error == 1)
259 + return EXT_BREAK;
261 + return EXT_CONTINUE;
264 +/* fiemap flags we can handle specified here */
265 +#define EXT4_FIEMAP_FLAGS (FIEMAP_FLAG_SYNC|FIEMAP_FLAG_XATTR)
267 +int ext4_xattr_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo)
269 + __u64 physical = 0;
270 + __u64 length;
271 + __u32 flags = FIEMAP_EXTENT_LAST;
272 + int blockbits = inode->i_sb->s_blocksize_bits;
273 + int error = 0;
275 + /* in-inode? */
276 + if (EXT4_I(inode)->i_state & EXT4_STATE_XATTR) {
277 + struct ext4_iloc iloc;
278 + int offset; /* offset of xattr in inode */
280 + error = ext4_get_inode_loc(inode, &iloc);
281 + if (error)
282 + return error;
283 + physical = iloc.bh->b_blocknr << blockbits;
284 + offset = EXT4_GOOD_OLD_INODE_SIZE +
285 + EXT4_I(inode)->i_extra_isize;
286 + physical += offset;
287 + length = EXT4_SB(inode->i_sb)->s_inode_size - offset;
288 + flags |= FIEMAP_EXTENT_DATA_INLINE;
289 + } else { /* external block */
290 + physical = EXT4_I(inode)->i_file_acl << blockbits;
291 + length = inode->i_sb->s_blocksize;
294 + if (physical)
295 + error = fiemap_fill_next_extent(fieinfo, 0, physical,
296 + length, flags);
297 + return (error < 0 ? error : 0);
300 +int ext4_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
301 + __u64 start, __u64 len)
303 + ext4_lblk_t start_blk;
304 + ext4_lblk_t len_blks;
305 + int error = 0;
307 + /* fallback to generic here if not in extents fmt */
308 + if (!(EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL))
309 + return generic_block_fiemap(inode, fieinfo, start, len,
310 + ext4_get_block);
312 + if (fiemap_check_flags(fieinfo, EXT4_FIEMAP_FLAGS))
313 + return -EBADR;
315 + if (fieinfo->fi_flags & FIEMAP_FLAG_XATTR) {
316 + error = ext4_xattr_fiemap(inode, fieinfo);
317 + } else {
318 + start_blk = start >> inode->i_sb->s_blocksize_bits;
319 + len_blks = len >> inode->i_sb->s_blocksize_bits;
321 + /*
322 + * Walk the extent tree gathering extent information.
323 + * ext4_ext_fiemap_cb will push extents back to user.
324 + */
325 + down_write(&EXT4_I(inode)->i_data_sem);
326 + error = ext4_ext_walk_space(inode, start_blk, len_blks,
327 + ext4_ext_fiemap_cb, fieinfo);
328 + up_write(&EXT4_I(inode)->i_data_sem);
331 + return error;
334 Index: linux-2.6/fs/ext4/file.c
335 ===================================================================
336 --- linux-2.6.orig/fs/ext4/file.c 2008-07-14 16:51:40.000000000 -0500
337 +++ linux-2.6/fs/ext4/file.c 2008-07-14 16:56:12.066353577 -0500
338 @@ -140,6 +140,9 @@ static int ext4_file_mmap(struct file *f
339 return 0;
342 +extern int ext4_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
343 + __u64 start, __u64 len);
345 const struct file_operations ext4_file_operations = {
346 .llseek = generic_file_llseek,
347 .read = do_sync_read,
348 @@ -170,5 +173,6 @@ const struct inode_operations ext4_file_
349 #endif
350 .permission = ext4_permission,
351 .fallocate = ext4_fallocate,
352 + .fiemap = ext4_fiemap,