aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@lst.de>2016-06-20 19:38:45 -0400
committerDave Chinner <david@fromorbit.com>2016-06-20 19:38:45 -0400
commit8be9f564d25e7adc582f9f3689040ce5aa6f1f5b (patch)
treeeac9cc4797502f733b15228a861c0ae7c152f64b
parent9a286f0e52a2dac362caf78a458efa8f3c05b99e (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.c90
-rw-r--r--include/linux/iomap.h3
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}
407EXPORT_SYMBOL_GPL(iomap_page_mkwrite); 407EXPORT_SYMBOL_GPL(iomap_page_mkwrite);
408
409struct fiemap_ctx {
410 struct fiemap_extent_info *fi;
411 struct iomap prev;
412};
413
414static 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
437static loff_t
438iomap_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
459int 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}
497EXPORT_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
6struct fiemap_extent_info;
6struct inode; 7struct inode;
7struct iov_iter; 8struct iov_iter;
8struct kiocb; 9struct 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);
64int iomap_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf, 65int iomap_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf,
65 struct iomap_ops *ops); 66 struct iomap_ops *ops);
67int 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 */