Add fix to avoid WARN() messages if the USB device is yanked out.
[ext4-patch-queue.git] / generic-fiemap.patch
blob8d49cd0bf3afd68e60728820c88e93a0592a5420
1 generic block based fiemap implementation
3 From: Josef Bacik <jbacik@redhat.com>
5 Any block based fs (this patch includes ext3) just has to declare its own
6 fiemap() function and then call this generic function with its own
7 get_block_t. This works well for block based filesystems that will map
8 multiple contiguous blocks at one time, but will work for filesystems that
9 only map one block at a time, you will just end up with an "extent" for each
10 block. One gotcha is this will not play nicely where there is hole+data
11 after the EOF. This function will assume its hit the end of the data as soon
12 as it hits a hole after the EOF, so if there is any data past that it will
13 not pick that up. AFAIK no block based fs does this anyway, but its in the
14 comments of the function anyway just in case.
16 Signed-off-by: Josef Bacik <jbacik@redhat.com>
17 Signed-off-by: Mark Fasheh <mfasheh@suse.com>
18 ---
19 fs/ext2/ext2.h | 2 +
20 fs/ext2/file.c | 1 +
21 fs/ext2/inode.c | 8 +++
22 fs/ext3/file.c | 1 +
23 fs/ext3/inode.c | 8 +++
24 fs/ioctl.c | 118 +++++++++++++++++++++++++++++++++++++++++++++++
25 include/linux/ext3_fs.h | 2 +
26 include/linux/fs.h | 3 +
27 8 files changed, 143 insertions(+), 0 deletions(-)
29 diff --git a/fs/ext2/ext2.h b/fs/ext2/ext2.h
30 index 47d88da..bae998c 100644
31 --- a/fs/ext2/ext2.h
32 +++ b/fs/ext2/ext2.h
33 @@ -133,6 +133,8 @@ extern void ext2_truncate (struct inode *);
34 extern int ext2_setattr (struct dentry *, struct iattr *);
35 extern void ext2_set_inode_flags(struct inode *inode);
36 extern void ext2_get_inode_flags(struct ext2_inode_info *);
37 +extern int ext2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
38 + u64 start, u64 len);
39 int __ext2_write_begin(struct file *file, struct address_space *mapping,
40 loff_t pos, unsigned len, unsigned flags,
41 struct page **pagep, void **fsdata);
42 diff --git a/fs/ext2/file.c b/fs/ext2/file.c
43 index 5f2fa9c..45ed071 100644
44 --- a/fs/ext2/file.c
45 +++ b/fs/ext2/file.c
46 @@ -86,4 +86,5 @@ const struct inode_operations ext2_file_inode_operations = {
47 #endif
48 .setattr = ext2_setattr,
49 .permission = ext2_permission,
50 + .fiemap = ext2_fiemap,
52 diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
53 index 991d6df..7658b33 100644
54 --- a/fs/ext2/inode.c
55 +++ b/fs/ext2/inode.c
56 @@ -31,6 +31,7 @@
57 #include <linux/writeback.h>
58 #include <linux/buffer_head.h>
59 #include <linux/mpage.h>
60 +#include <linux/fiemap.h>
61 #include "ext2.h"
62 #include "acl.h"
63 #include "xip.h"
64 @@ -704,6 +705,13 @@ int ext2_get_block(struct inode *inode, sector_t iblock, struct buffer_head *bh_
68 +int ext2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
69 + u64 start, u64 len)
71 + return generic_block_fiemap(inode, fieinfo, start, len,
72 + ext2_get_block);
75 static int ext2_writepage(struct page *page, struct writeback_control *wbc)
77 return block_write_full_page(page, ext2_get_block, wbc);
78 diff --git a/fs/ext3/file.c b/fs/ext3/file.c
79 index acc4913..3be1e06 100644
80 --- a/fs/ext3/file.c
81 +++ b/fs/ext3/file.c
82 @@ -134,5 +134,6 @@ const struct inode_operations ext3_file_inode_operations = {
83 .removexattr = generic_removexattr,
84 #endif
85 .permission = ext3_permission,
86 + .fiemap = ext3_fiemap,
89 diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c
90 index 507d868..ebfec4d 100644
91 --- a/fs/ext3/inode.c
92 +++ b/fs/ext3/inode.c
93 @@ -36,6 +36,7 @@
94 #include <linux/mpage.h>
95 #include <linux/uio.h>
96 #include <linux/bio.h>
97 +#include <linux/fiemap.h>
98 #include "xattr.h"
99 #include "acl.h"
101 @@ -981,6 +982,13 @@ out:
102 return ret;
105 +int ext3_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
106 + u64 start, u64 len)
108 + return generic_block_fiemap(inode, fieinfo, start, len,
109 + ext3_get_block);
113 * `handle' can be NULL if create is zero
115 diff --git a/fs/ioctl.c b/fs/ioctl.c
116 index 274625a..682c252 100644
117 --- a/fs/ioctl.c
118 +++ b/fs/ioctl.c
119 @@ -13,6 +13,8 @@
120 #include <linux/security.h>
121 #include <linux/module.h>
122 #include <linux/uaccess.h>
123 +#include <linux/writeback.h>
124 +#include <linux/buffer_head.h>
126 #include <asm/ioctls.h>
128 @@ -223,6 +225,122 @@ static int ioctl_fiemap(struct file *filp, unsigned long arg)
129 return error;
132 +#define blk_to_logical(inode, blk) (blk << (inode)->i_blkbits)
133 +#define logical_to_blk(inode, offset) (offset >> (inode)->i_blkbits);
136 + * @inode - the inode to map
137 + * @arg - the pointer to userspace where we copy everything to
138 + * @get_block - the fs's get_block function
140 + * This does FIEMAP for block based inodes. Basically it will just loop
141 + * through get_block until we hit the number of extents we want to map, or we
142 + * go past the end of the file and hit a hole.
144 + * If it is possible to have data blocks beyond a hole past @inode->i_size, then
145 + * please do not use this function, it will stop at the first unmapped block
146 + * beyond i_size
147 + */
148 +int generic_block_fiemap(struct inode *inode,
149 + struct fiemap_extent_info *fieinfo, u64 start,
150 + u64 len, get_block_t *get_block)
152 + struct buffer_head tmp;
153 + unsigned int start_blk;
154 + long long length = 0, map_len = 0;
155 + u64 logical = 0, phys = 0, size = 0;
156 + u32 flags = FIEMAP_EXTENT_MERGED;
157 + int ret = 0;
159 + if ((ret = fiemap_check_flags(fieinfo, FIEMAP_FLAG_SYNC)))
160 + return ret;
162 + start_blk = logical_to_blk(inode, start);
164 + /* guard against change */
165 + mutex_lock(&inode->i_mutex);
167 + length = (long long)min_t(u64, len, i_size_read(inode));
168 + map_len = length;
170 + do {
171 + /*
172 + * we set b_size to the total size we want so it will map as
173 + * many contiguous blocks as possible at once
174 + */
175 + memset(&tmp, 0, sizeof(struct buffer_head));
176 + tmp.b_size = map_len;
178 + ret = get_block(inode, start_blk, &tmp, 0);
179 + if (ret)
180 + break;
182 + /* HOLE */
183 + if (!buffer_mapped(&tmp)) {
184 + /*
185 + * first hole after going past the EOF, this is our
186 + * last extent
187 + */
188 + if (length <= 0) {
189 + flags = FIEMAP_EXTENT_MERGED|FIEMAP_EXTENT_LAST;
190 + ret = fiemap_fill_next_extent(fieinfo, logical,
191 + phys, size,
192 + flags);
193 + break;
196 + length -= blk_to_logical(inode, 1);
198 + /* if we have holes up to/past EOF then we're done */
199 + if (length <= 0)
200 + break;
202 + start_blk++;
203 + } else {
204 + if (length <= 0 && size) {
205 + ret = fiemap_fill_next_extent(fieinfo, logical,
206 + phys, size,
207 + flags);
208 + if (ret)
209 + break;
212 + logical = blk_to_logical(inode, start_blk);
213 + phys = blk_to_logical(inode, tmp.b_blocknr);
214 + size = tmp.b_size;
215 + flags = FIEMAP_EXTENT_MERGED;
217 + length -= tmp.b_size;
218 + start_blk += logical_to_blk(inode, size);
220 + /*
221 + * if we are past the EOF we need to loop again to see
222 + * if there is a hole so we can mark this extent as the
223 + * last one, and if not keep mapping things until we
224 + * find a hole, or we run out of slots in the extent
225 + * array
226 + */
227 + if (length <= 0)
228 + continue;
230 + ret = fiemap_fill_next_extent(fieinfo, logical, phys,
231 + size, flags);
232 + if (ret)
233 + break;
235 + cond_resched();
236 + } while (1);
238 + mutex_unlock(&inode->i_mutex);
240 + /* if ret is 1 then we just hit the end of the extent array */
241 + if (ret == 1)
242 + ret = 0;
244 + return ret;
246 +EXPORT_SYMBOL(generic_block_fiemap);
248 static int file_ioctl(struct file *filp, unsigned int cmd,
249 unsigned long arg)
251 diff --git a/include/linux/ext3_fs.h b/include/linux/ext3_fs.h
252 index 80171ee..8120fa1 100644
253 --- a/include/linux/ext3_fs.h
254 +++ b/include/linux/ext3_fs.h
255 @@ -837,6 +837,8 @@ extern void ext3_truncate (struct inode *);
256 extern void ext3_set_inode_flags(struct inode *);
257 extern void ext3_get_inode_flags(struct ext3_inode_info *);
258 extern void ext3_set_aops(struct inode *inode);
259 +extern int ext3_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
260 + u64 start, u64 len);
262 /* ioctl.c */
263 extern int ext3_ioctl (struct inode *, struct file *, unsigned int,
264 diff --git a/include/linux/fs.h b/include/linux/fs.h
265 index 194fb23..385c9a1 100644
266 --- a/include/linux/fs.h
267 +++ b/include/linux/fs.h
268 @@ -1998,6 +1998,9 @@ extern int vfs_fstat(unsigned int, struct kstat *);
270 extern int do_vfs_ioctl(struct file *filp, unsigned int fd, unsigned int cmd,
271 unsigned long arg);
272 +extern int generic_block_fiemap(struct inode *inode,
273 + struct fiemap_extent_info *fieinfo, u64 start,
274 + u64 len, get_block_t *get_block);
276 extern void get_filesystem(struct file_system_type *fs);
277 extern void put_filesystem(struct file_system_type *fs);
279 1.5.6.1.205.ge2c7.dirty