diff options
author | Christoph Hellwig <hch@lst.de> | 2016-06-20 19:38:45 -0400 |
---|---|---|
committer | Dave Chinner <david@fromorbit.com> | 2016-06-20 19:38:45 -0400 |
commit | 8be9f564d25e7adc582f9f3689040ce5aa6f1f5b (patch) | |
tree | eac9cc4797502f733b15228a861c0ae7c152f64b | |
parent | 9a286f0e52a2dac362caf78a458efa8f3c05b99e (diff) |
fs: iomap based fiemap implementation
Add a simple fiemap implementation based on iomap_ops, partially based
on a previous implementation from Bob Peterson <rpeterso@redhat.com>.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Dave Chinner <david@fromorbit.com>
-rw-r--r-- | fs/iomap.c | 90 | ||||
-rw-r--r-- | include/linux/iomap.h | 3 |
2 files changed, 93 insertions, 0 deletions
diff --git a/fs/iomap.c b/fs/iomap.c index 477817c00bac..48141b8eff5f 100644 --- a/fs/iomap.c +++ b/fs/iomap.c | |||
@@ -405,3 +405,93 @@ out_unlock: | |||
405 | return ret; | 405 | return ret; |
406 | } | 406 | } |
407 | EXPORT_SYMBOL_GPL(iomap_page_mkwrite); | 407 | EXPORT_SYMBOL_GPL(iomap_page_mkwrite); |
408 | |||
409 | struct fiemap_ctx { | ||
410 | struct fiemap_extent_info *fi; | ||
411 | struct iomap prev; | ||
412 | }; | ||
413 | |||
414 | static int iomap_to_fiemap(struct fiemap_extent_info *fi, | ||
415 | struct iomap *iomap, u32 flags) | ||
416 | { | ||
417 | switch (iomap->type) { | ||
418 | case IOMAP_HOLE: | ||
419 | /* skip holes */ | ||
420 | return 0; | ||
421 | case IOMAP_DELALLOC: | ||
422 | flags |= FIEMAP_EXTENT_DELALLOC | FIEMAP_EXTENT_UNKNOWN; | ||
423 | break; | ||
424 | case IOMAP_UNWRITTEN: | ||
425 | flags |= FIEMAP_EXTENT_UNWRITTEN; | ||
426 | break; | ||
427 | case IOMAP_MAPPED: | ||
428 | break; | ||
429 | } | ||
430 | |||
431 | return fiemap_fill_next_extent(fi, iomap->offset, | ||
432 | iomap->blkno != IOMAP_NULL_BLOCK ? iomap->blkno << 9: 0, | ||
433 | iomap->length, flags | FIEMAP_EXTENT_MERGED); | ||
434 | |||
435 | } | ||
436 | |||
437 | static loff_t | ||
438 | iomap_fiemap_actor(struct inode *inode, loff_t pos, loff_t length, void *data, | ||
439 | struct iomap *iomap) | ||
440 | { | ||
441 | struct fiemap_ctx *ctx = data; | ||
442 | loff_t ret = length; | ||
443 | |||
444 | if (iomap->type == IOMAP_HOLE) | ||
445 | return length; | ||
446 | |||
447 | ret = iomap_to_fiemap(ctx->fi, &ctx->prev, 0); | ||
448 | ctx->prev = *iomap; | ||
449 | switch (ret) { | ||
450 | case 0: /* success */ | ||
451 | return length; | ||
452 | case 1: /* extent array full */ | ||
453 | return 0; | ||
454 | default: | ||
455 | return ret; | ||
456 | } | ||
457 | } | ||
458 | |||
459 | int iomap_fiemap(struct inode *inode, struct fiemap_extent_info *fi, | ||
460 | loff_t start, loff_t len, struct iomap_ops *ops) | ||
461 | { | ||
462 | struct fiemap_ctx ctx; | ||
463 | loff_t ret; | ||
464 | |||
465 | memset(&ctx, 0, sizeof(ctx)); | ||
466 | ctx.fi = fi; | ||
467 | ctx.prev.type = IOMAP_HOLE; | ||
468 | |||
469 | ret = fiemap_check_flags(fi, FIEMAP_FLAG_SYNC); | ||
470 | if (ret) | ||
471 | return ret; | ||
472 | |||
473 | ret = filemap_write_and_wait(inode->i_mapping); | ||
474 | if (ret) | ||
475 | return ret; | ||
476 | |||
477 | while (len > 0) { | ||
478 | ret = iomap_apply(inode, start, len, 0, ops, &ctx, | ||
479 | iomap_fiemap_actor); | ||
480 | if (ret < 0) | ||
481 | return ret; | ||
482 | if (ret == 0) | ||
483 | break; | ||
484 | |||
485 | start += ret; | ||
486 | len -= ret; | ||
487 | } | ||
488 | |||
489 | if (ctx.prev.type != IOMAP_HOLE) { | ||
490 | ret = iomap_to_fiemap(fi, &ctx.prev, FIEMAP_EXTENT_LAST); | ||
491 | if (ret < 0) | ||
492 | return ret; | ||
493 | } | ||
494 | |||
495 | return 0; | ||
496 | } | ||
497 | EXPORT_SYMBOL_GPL(iomap_fiemap); | ||
diff --git a/include/linux/iomap.h b/include/linux/iomap.h index d2f469ae899a..3267df461012 100644 --- a/include/linux/iomap.h +++ b/include/linux/iomap.h | |||
@@ -3,6 +3,7 @@ | |||
3 | 3 | ||
4 | #include <linux/types.h> | 4 | #include <linux/types.h> |
5 | 5 | ||
6 | struct fiemap_extent_info; | ||
6 | struct inode; | 7 | struct inode; |
7 | struct iov_iter; | 8 | struct iov_iter; |
8 | struct kiocb; | 9 | struct kiocb; |
@@ -63,5 +64,7 @@ int iomap_truncate_page(struct inode *inode, loff_t pos, bool *did_zero, | |||
63 | struct iomap_ops *ops); | 64 | struct iomap_ops *ops); |
64 | int iomap_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf, | 65 | int iomap_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf, |
65 | struct iomap_ops *ops); | 66 | struct iomap_ops *ops); |
67 | int iomap_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, | ||
68 | loff_t start, loff_t len, struct iomap_ops *ops); | ||
66 | 69 | ||
67 | #endif /* LINUX_IOMAP_H */ | 70 | #endif /* LINUX_IOMAP_H */ |