diff options
Diffstat (limited to 'fs/ioctl.c')
-rw-r--r-- | fs/ioctl.c | 118 |
1 files changed, 118 insertions, 0 deletions
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 | { |