diff options
-rw-r--r-- | fs/ext2/ext2.h | 2 | ||||
-rw-r--r-- | fs/ext2/file.c | 1 | ||||
-rw-r--r-- | fs/ext2/inode.c | 8 | ||||
-rw-r--r-- | fs/ext3/file.c | 1 | ||||
-rw-r--r-- | fs/ext3/inode.c | 8 | ||||
-rw-r--r-- | fs/ioctl.c | 118 | ||||
-rw-r--r-- | include/linux/ext3_fs.h | 2 | ||||
-rw-r--r-- | include/linux/fs.h | 3 |
8 files changed, 143 insertions, 0 deletions
diff --git a/fs/ext2/ext2.h b/fs/ext2/ext2.h index 47d88da2d33b..bae998c1e44e 100644 --- a/fs/ext2/ext2.h +++ b/fs/ext2/ext2.h | |||
@@ -133,6 +133,8 @@ extern void ext2_truncate (struct inode *); | |||
133 | extern int ext2_setattr (struct dentry *, struct iattr *); | 133 | extern int ext2_setattr (struct dentry *, struct iattr *); |
134 | extern void ext2_set_inode_flags(struct inode *inode); | 134 | extern void ext2_set_inode_flags(struct inode *inode); |
135 | extern void ext2_get_inode_flags(struct ext2_inode_info *); | 135 | extern void ext2_get_inode_flags(struct ext2_inode_info *); |
136 | extern int ext2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, | ||
137 | u64 start, u64 len); | ||
136 | int __ext2_write_begin(struct file *file, struct address_space *mapping, | 138 | int __ext2_write_begin(struct file *file, struct address_space *mapping, |
137 | loff_t pos, unsigned len, unsigned flags, | 139 | loff_t pos, unsigned len, unsigned flags, |
138 | struct page **pagep, void **fsdata); | 140 | struct page **pagep, void **fsdata); |
diff --git a/fs/ext2/file.c b/fs/ext2/file.c index 5f2fa9c36293..45ed07122182 100644 --- a/fs/ext2/file.c +++ b/fs/ext2/file.c | |||
@@ -86,4 +86,5 @@ const struct inode_operations ext2_file_inode_operations = { | |||
86 | #endif | 86 | #endif |
87 | .setattr = ext2_setattr, | 87 | .setattr = ext2_setattr, |
88 | .permission = ext2_permission, | 88 | .permission = ext2_permission, |
89 | .fiemap = ext2_fiemap, | ||
89 | }; | 90 | }; |
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index 991d6dfeb51f..7658b33e2653 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <linux/writeback.h> | 31 | #include <linux/writeback.h> |
32 | #include <linux/buffer_head.h> | 32 | #include <linux/buffer_head.h> |
33 | #include <linux/mpage.h> | 33 | #include <linux/mpage.h> |
34 | #include <linux/fiemap.h> | ||
34 | #include "ext2.h" | 35 | #include "ext2.h" |
35 | #include "acl.h" | 36 | #include "acl.h" |
36 | #include "xip.h" | 37 | #include "xip.h" |
@@ -704,6 +705,13 @@ int ext2_get_block(struct inode *inode, sector_t iblock, struct buffer_head *bh_ | |||
704 | 705 | ||
705 | } | 706 | } |
706 | 707 | ||
708 | int ext2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, | ||
709 | u64 start, u64 len) | ||
710 | { | ||
711 | return generic_block_fiemap(inode, fieinfo, start, len, | ||
712 | ext2_get_block); | ||
713 | } | ||
714 | |||
707 | static int ext2_writepage(struct page *page, struct writeback_control *wbc) | 715 | static int ext2_writepage(struct page *page, struct writeback_control *wbc) |
708 | { | 716 | { |
709 | return block_write_full_page(page, ext2_get_block, wbc); | 717 | return block_write_full_page(page, ext2_get_block, wbc); |
diff --git a/fs/ext3/file.c b/fs/ext3/file.c index acc4913d3019..3be1e0689c9a 100644 --- a/fs/ext3/file.c +++ b/fs/ext3/file.c | |||
@@ -134,5 +134,6 @@ const struct inode_operations ext3_file_inode_operations = { | |||
134 | .removexattr = generic_removexattr, | 134 | .removexattr = generic_removexattr, |
135 | #endif | 135 | #endif |
136 | .permission = ext3_permission, | 136 | .permission = ext3_permission, |
137 | .fiemap = ext3_fiemap, | ||
137 | }; | 138 | }; |
138 | 139 | ||
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index 507d8689b111..ebfec4d0148e 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c | |||
@@ -36,6 +36,7 @@ | |||
36 | #include <linux/mpage.h> | 36 | #include <linux/mpage.h> |
37 | #include <linux/uio.h> | 37 | #include <linux/uio.h> |
38 | #include <linux/bio.h> | 38 | #include <linux/bio.h> |
39 | #include <linux/fiemap.h> | ||
39 | #include "xattr.h" | 40 | #include "xattr.h" |
40 | #include "acl.h" | 41 | #include "acl.h" |
41 | 42 | ||
@@ -981,6 +982,13 @@ out: | |||
981 | return ret; | 982 | return ret; |
982 | } | 983 | } |
983 | 984 | ||
985 | int ext3_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, | ||
986 | u64 start, u64 len) | ||
987 | { | ||
988 | return generic_block_fiemap(inode, fieinfo, start, len, | ||
989 | ext3_get_block); | ||
990 | } | ||
991 | |||
984 | /* | 992 | /* |
985 | * `handle' can be NULL if create is zero | 993 | * `handle' can be NULL if create is zero |
986 | */ | 994 | */ |
diff --git a/fs/ioctl.c b/fs/ioctl.c index 045d9601fbbd..33a6b7ecb8b8 100644 --- a/fs/ioctl.c +++ b/fs/ioctl.c | |||
@@ -13,6 +13,8 @@ | |||
13 | #include <linux/security.h> | 13 | #include <linux/security.h> |
14 | #include <linux/module.h> | 14 | #include <linux/module.h> |
15 | #include <linux/uaccess.h> | 15 | #include <linux/uaccess.h> |
16 | #include <linux/writeback.h> | ||
17 | #include <linux/buffer_head.h> | ||
16 | 18 | ||
17 | #include <asm/ioctls.h> | 19 | #include <asm/ioctls.h> |
18 | 20 | ||
@@ -224,6 +226,122 @@ static int ioctl_fiemap(struct file *filp, unsigned long arg) | |||
224 | return error; | 226 | return error; |
225 | } | 227 | } |
226 | 228 | ||
229 | #define blk_to_logical(inode, blk) (blk << (inode)->i_blkbits) | ||
230 | #define logical_to_blk(inode, offset) (offset >> (inode)->i_blkbits); | ||
231 | |||
232 | /* | ||
233 | * @inode - the inode to map | ||
234 | * @arg - the pointer to userspace where we copy everything to | ||
235 | * @get_block - the fs's get_block function | ||
236 | * | ||
237 | * This does FIEMAP for block based inodes. Basically it will just loop | ||
238 | * through get_block until we hit the number of extents we want to map, or we | ||
239 | * go past the end of the file and hit a hole. | ||
240 | * | ||
241 | * If it is possible to have data blocks beyond a hole past @inode->i_size, then | ||
242 | * please do not use this function, it will stop at the first unmapped block | ||
243 | * beyond i_size | ||
244 | */ | ||
245 | int generic_block_fiemap(struct inode *inode, | ||
246 | struct fiemap_extent_info *fieinfo, u64 start, | ||
247 | u64 len, get_block_t *get_block) | ||
248 | { | ||
249 | struct buffer_head tmp; | ||
250 | unsigned int start_blk; | ||
251 | long long length = 0, map_len = 0; | ||
252 | u64 logical = 0, phys = 0, size = 0; | ||
253 | u32 flags = FIEMAP_EXTENT_MERGED; | ||
254 | int ret = 0; | ||
255 | |||
256 | if ((ret = fiemap_check_flags(fieinfo, FIEMAP_FLAG_SYNC))) | ||
257 | return ret; | ||
258 | |||
259 | start_blk = logical_to_blk(inode, start); | ||
260 | |||
261 | /* guard against change */ | ||
262 | mutex_lock(&inode->i_mutex); | ||
263 | |||
264 | length = (long long)min_t(u64, len, i_size_read(inode)); | ||
265 | map_len = length; | ||
266 | |||
267 | do { | ||
268 | /* | ||
269 | * we set b_size to the total size we want so it will map as | ||
270 | * many contiguous blocks as possible at once | ||
271 | */ | ||
272 | memset(&tmp, 0, sizeof(struct buffer_head)); | ||
273 | tmp.b_size = map_len; | ||
274 | |||
275 | ret = get_block(inode, start_blk, &tmp, 0); | ||
276 | if (ret) | ||
277 | break; | ||
278 | |||
279 | /* HOLE */ | ||
280 | if (!buffer_mapped(&tmp)) { | ||
281 | /* | ||
282 | * first hole after going past the EOF, this is our | ||
283 | * last extent | ||
284 | */ | ||
285 | if (length <= 0) { | ||
286 | flags = FIEMAP_EXTENT_MERGED|FIEMAP_EXTENT_LAST; | ||
287 | ret = fiemap_fill_next_extent(fieinfo, logical, | ||
288 | phys, size, | ||
289 | flags); | ||
290 | break; | ||
291 | } | ||
292 | |||
293 | length -= blk_to_logical(inode, 1); | ||
294 | |||
295 | /* if we have holes up to/past EOF then we're done */ | ||
296 | if (length <= 0) | ||
297 | break; | ||
298 | |||
299 | start_blk++; | ||
300 | } else { | ||
301 | if (length <= 0 && size) { | ||
302 | ret = fiemap_fill_next_extent(fieinfo, logical, | ||
303 | phys, size, | ||
304 | flags); | ||
305 | if (ret) | ||
306 | break; | ||
307 | } | ||
308 | |||
309 | logical = blk_to_logical(inode, start_blk); | ||
310 | phys = blk_to_logical(inode, tmp.b_blocknr); | ||
311 | size = tmp.b_size; | ||
312 | flags = FIEMAP_EXTENT_MERGED; | ||
313 | |||
314 | length -= tmp.b_size; | ||
315 | start_blk += logical_to_blk(inode, size); | ||
316 | |||
317 | /* | ||
318 | * if we are past the EOF we need to loop again to see | ||
319 | * if there is a hole so we can mark this extent as the | ||
320 | * last one, and if not keep mapping things until we | ||
321 | * find a hole, or we run out of slots in the extent | ||
322 | * array | ||
323 | */ | ||
324 | if (length <= 0) | ||
325 | continue; | ||
326 | |||
327 | ret = fiemap_fill_next_extent(fieinfo, logical, phys, | ||
328 | size, flags); | ||
329 | if (ret) | ||
330 | break; | ||
331 | } | ||
332 | cond_resched(); | ||
333 | } while (1); | ||
334 | |||
335 | mutex_unlock(&inode->i_mutex); | ||
336 | |||
337 | /* if ret is 1 then we just hit the end of the extent array */ | ||
338 | if (ret == 1) | ||
339 | ret = 0; | ||
340 | |||
341 | return ret; | ||
342 | } | ||
343 | EXPORT_SYMBOL(generic_block_fiemap); | ||
344 | |||
227 | static int file_ioctl(struct file *filp, unsigned int cmd, | 345 | static int file_ioctl(struct file *filp, unsigned int cmd, |
228 | unsigned long arg) | 346 | unsigned long arg) |
229 | { | 347 | { |
diff --git a/include/linux/ext3_fs.h b/include/linux/ext3_fs.h index 80171ee89a22..8120fa1bc235 100644 --- a/include/linux/ext3_fs.h +++ b/include/linux/ext3_fs.h | |||
@@ -837,6 +837,8 @@ extern void ext3_truncate (struct inode *); | |||
837 | extern void ext3_set_inode_flags(struct inode *); | 837 | extern void ext3_set_inode_flags(struct inode *); |
838 | extern void ext3_get_inode_flags(struct ext3_inode_info *); | 838 | extern void ext3_get_inode_flags(struct ext3_inode_info *); |
839 | extern void ext3_set_aops(struct inode *inode); | 839 | extern void ext3_set_aops(struct inode *inode); |
840 | extern int ext3_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, | ||
841 | u64 start, u64 len); | ||
840 | 842 | ||
841 | /* ioctl.c */ | 843 | /* ioctl.c */ |
842 | extern int ext3_ioctl (struct inode *, struct file *, unsigned int, | 844 | extern int ext3_ioctl (struct inode *, struct file *, unsigned int, |
diff --git a/include/linux/fs.h b/include/linux/fs.h index 194fb237a307..385c9a197df1 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
@@ -1998,6 +1998,9 @@ extern int vfs_fstat(unsigned int, struct kstat *); | |||
1998 | 1998 | ||
1999 | extern int do_vfs_ioctl(struct file *filp, unsigned int fd, unsigned int cmd, | 1999 | extern int do_vfs_ioctl(struct file *filp, unsigned int fd, unsigned int cmd, |
2000 | unsigned long arg); | 2000 | unsigned long arg); |
2001 | extern int generic_block_fiemap(struct inode *inode, | ||
2002 | struct fiemap_extent_info *fieinfo, u64 start, | ||
2003 | u64 len, get_block_t *get_block); | ||
2001 | 2004 | ||
2002 | extern void get_filesystem(struct file_system_type *fs); | 2005 | extern void get_filesystem(struct file_system_type *fs); |
2003 | extern void put_filesystem(struct file_system_type *fs); | 2006 | extern void put_filesystem(struct file_system_type *fs); |