Message ID | 1464792297-13185-9-git-send-email-hch@lst.de (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Christoph, 2016-06-01 16:44 GMT+02:00 Christoph Hellwig <hch@lst.de>: > 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> > --- > fs/iomap.c | 90 +++++++++++++++++++++++++++++++++++++++++++++++++++ > include/linux/iomap.h | 3 ++ > 2 files changed, 93 insertions(+) > > diff --git a/fs/iomap.c b/fs/iomap.c > index e51adb6..e874c78 100644 > --- a/fs/iomap.c > +++ b/fs/iomap.c > @@ -405,3 +405,93 @@ out_unlock: > return ret; > } > EXPORT_SYMBOL_GPL(iomap_page_mkwrite); > + > +struct fiemap_ctx { > + struct fiemap_extent_info *fi; > + struct iomap prev; > +}; > + > +static int iomap_to_fiemap(struct fiemap_extent_info *fi, > + struct iomap *iomap, u32 flags) > +{ > + switch (iomap->type) { > + case IOMAP_HOLE: > + /* skip holes */ > + return 0; > + case IOMAP_DELALLOC: > + flags |= FIEMAP_EXTENT_DELALLOC | FIEMAP_EXTENT_UNKNOWN; > + break; > + case IOMAP_UNWRITTEN: > + flags |= FIEMAP_EXTENT_UNWRITTEN; > + break; > + case IOMAP_MAPPED: > + break; > + } > + > + return fiemap_fill_next_extent(fi, iomap->offset, > + iomap->blkno != IOMAP_NULL_BLOCK ? iomap->blkno << 9: 0, > + iomap->length, flags | FIEMAP_EXTENT_MERGED); According to Documentation/filesystems/fiemap.txt, it seems that FIEMAP_EXTENT_MERGED flag should only be set by filesystems with block-based rather than extent-based allocation. Am I overlooking something? > + > +} > + > +static loff_t > +iomap_fiemap_actor(struct inode *inode, loff_t pos, loff_t length, void *data, > + struct iomap *iomap) > +{ > + struct fiemap_ctx *ctx = data; > + loff_t ret = length; > + > + if (iomap->type == IOMAP_HOLE) > + return length; > + > + ret = iomap_to_fiemap(ctx->fi, &ctx->prev, 0); > + ctx->prev = *iomap; > + switch (ret) { > + case 0: /* success */ > + return length; > + case 1: /* extent array full */ > + return 0; > + default: > + return ret; > + } > +} > + > +int iomap_fiemap(struct inode *inode, struct fiemap_extent_info *fi, > + loff_t start, loff_t len, struct iomap_ops *ops) > +{ > + struct fiemap_ctx ctx; > + loff_t ret; > + > + memset(&ctx, 0, sizeof(ctx)); > + ctx.fi = fi; > + ctx.prev.type = IOMAP_HOLE; > + > + ret = fiemap_check_flags(fi, FIEMAP_FLAG_SYNC); > + if (ret) > + return ret; > + > + ret = filemap_write_and_wait(inode->i_mapping); > + if (ret) > + return ret; > + > + while (len > 0) { > + ret = iomap_apply(inode, start, len, 0, ops, &ctx, > + iomap_fiemap_actor); > + if (ret < 0) > + return ret; > + if (ret == 0) > + break; > + > + start += ret; > + len -= ret; > + } > + > + if (ctx.prev.type != IOMAP_HOLE) { > + ret = iomap_to_fiemap(fi, &ctx.prev, FIEMAP_EXTENT_LAST); > + if (ret < 0) > + return ret; > + } > + > + return 0; > +} > +EXPORT_SYMBOL_GPL(iomap_fiemap); > diff --git a/include/linux/iomap.h b/include/linux/iomap.h > index 854766f..b3deee1 100644 > --- a/include/linux/iomap.h > +++ b/include/linux/iomap.h > @@ -3,6 +3,7 @@ > > #include <linux/types.h> > > +struct fiemap_extent_info; > struct inode; > struct iov_iter; > struct kiocb; > @@ -63,5 +64,7 @@ int iomap_truncate_page(struct inode *inode, loff_t pos, bool *did_zero, > struct iomap_ops *ops); > int iomap_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf, > struct iomap_ops *ops); > +int iomap_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, > + loff_t start, loff_t len, struct iomap_ops *ops); > > #endif /* LINUX_IOMAP_H */ > -- > 2.1.4 > > -- > To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html Thanks, Andreas -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/fs/iomap.c b/fs/iomap.c index e51adb6..e874c78 100644 --- a/fs/iomap.c +++ b/fs/iomap.c @@ -405,3 +405,93 @@ out_unlock: return ret; } EXPORT_SYMBOL_GPL(iomap_page_mkwrite); + +struct fiemap_ctx { + struct fiemap_extent_info *fi; + struct iomap prev; +}; + +static int iomap_to_fiemap(struct fiemap_extent_info *fi, + struct iomap *iomap, u32 flags) +{ + switch (iomap->type) { + case IOMAP_HOLE: + /* skip holes */ + return 0; + case IOMAP_DELALLOC: + flags |= FIEMAP_EXTENT_DELALLOC | FIEMAP_EXTENT_UNKNOWN; + break; + case IOMAP_UNWRITTEN: + flags |= FIEMAP_EXTENT_UNWRITTEN; + break; + case IOMAP_MAPPED: + break; + } + + return fiemap_fill_next_extent(fi, iomap->offset, + iomap->blkno != IOMAP_NULL_BLOCK ? iomap->blkno << 9: 0, + iomap->length, flags | FIEMAP_EXTENT_MERGED); + +} + +static loff_t +iomap_fiemap_actor(struct inode *inode, loff_t pos, loff_t length, void *data, + struct iomap *iomap) +{ + struct fiemap_ctx *ctx = data; + loff_t ret = length; + + if (iomap->type == IOMAP_HOLE) + return length; + + ret = iomap_to_fiemap(ctx->fi, &ctx->prev, 0); + ctx->prev = *iomap; + switch (ret) { + case 0: /* success */ + return length; + case 1: /* extent array full */ + return 0; + default: + return ret; + } +} + +int iomap_fiemap(struct inode *inode, struct fiemap_extent_info *fi, + loff_t start, loff_t len, struct iomap_ops *ops) +{ + struct fiemap_ctx ctx; + loff_t ret; + + memset(&ctx, 0, sizeof(ctx)); + ctx.fi = fi; + ctx.prev.type = IOMAP_HOLE; + + ret = fiemap_check_flags(fi, FIEMAP_FLAG_SYNC); + if (ret) + return ret; + + ret = filemap_write_and_wait(inode->i_mapping); + if (ret) + return ret; + + while (len > 0) { + ret = iomap_apply(inode, start, len, 0, ops, &ctx, + iomap_fiemap_actor); + if (ret < 0) + return ret; + if (ret == 0) + break; + + start += ret; + len -= ret; + } + + if (ctx.prev.type != IOMAP_HOLE) { + ret = iomap_to_fiemap(fi, &ctx.prev, FIEMAP_EXTENT_LAST); + if (ret < 0) + return ret; + } + + return 0; +} +EXPORT_SYMBOL_GPL(iomap_fiemap); diff --git a/include/linux/iomap.h b/include/linux/iomap.h index 854766f..b3deee1 100644 --- a/include/linux/iomap.h +++ b/include/linux/iomap.h @@ -3,6 +3,7 @@ #include <linux/types.h> +struct fiemap_extent_info; struct inode; struct iov_iter; struct kiocb; @@ -63,5 +64,7 @@ int iomap_truncate_page(struct inode *inode, loff_t pos, bool *did_zero, struct iomap_ops *ops); int iomap_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf, struct iomap_ops *ops); +int iomap_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, + loff_t start, loff_t len, struct iomap_ops *ops); #endif /* LINUX_IOMAP_H */
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> --- fs/iomap.c | 90 +++++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/iomap.h | 3 ++ 2 files changed, 93 insertions(+)