15157fb8fSDarrick J. Wong // SPDX-License-Identifier: GPL-2.0
25157fb8fSDarrick J. Wong /*
37892386dSChristoph Hellwig * Copyright (c) 2016-2021 Christoph Hellwig.
45157fb8fSDarrick J. Wong */
55157fb8fSDarrick J. Wong #include <linux/module.h>
65157fb8fSDarrick J. Wong #include <linux/compiler.h>
75157fb8fSDarrick J. Wong #include <linux/fs.h>
85157fb8fSDarrick J. Wong #include <linux/iomap.h>
910c5db28SChristoph Hellwig #include <linux/fiemap.h>
10*cbcc268bSMatthew Wilcox (Oracle) #include <linux/pagemap.h>
115157fb8fSDarrick J. Wong
iomap_to_fiemap(struct fiemap_extent_info * fi,const struct iomap * iomap,u32 flags)125157fb8fSDarrick J. Wong static int iomap_to_fiemap(struct fiemap_extent_info *fi,
137892386dSChristoph Hellwig const struct iomap *iomap, u32 flags)
145157fb8fSDarrick J. Wong {
155157fb8fSDarrick J. Wong switch (iomap->type) {
165157fb8fSDarrick J. Wong case IOMAP_HOLE:
175157fb8fSDarrick J. Wong /* skip holes */
185157fb8fSDarrick J. Wong return 0;
195157fb8fSDarrick J. Wong case IOMAP_DELALLOC:
205157fb8fSDarrick J. Wong flags |= FIEMAP_EXTENT_DELALLOC | FIEMAP_EXTENT_UNKNOWN;
215157fb8fSDarrick J. Wong break;
225157fb8fSDarrick J. Wong case IOMAP_MAPPED:
235157fb8fSDarrick J. Wong break;
245157fb8fSDarrick J. Wong case IOMAP_UNWRITTEN:
255157fb8fSDarrick J. Wong flags |= FIEMAP_EXTENT_UNWRITTEN;
265157fb8fSDarrick J. Wong break;
275157fb8fSDarrick J. Wong case IOMAP_INLINE:
285157fb8fSDarrick J. Wong flags |= FIEMAP_EXTENT_DATA_INLINE;
295157fb8fSDarrick J. Wong break;
305157fb8fSDarrick J. Wong }
315157fb8fSDarrick J. Wong
325157fb8fSDarrick J. Wong if (iomap->flags & IOMAP_F_MERGED)
335157fb8fSDarrick J. Wong flags |= FIEMAP_EXTENT_MERGED;
345157fb8fSDarrick J. Wong if (iomap->flags & IOMAP_F_SHARED)
355157fb8fSDarrick J. Wong flags |= FIEMAP_EXTENT_SHARED;
365157fb8fSDarrick J. Wong
375157fb8fSDarrick J. Wong return fiemap_fill_next_extent(fi, iomap->offset,
385157fb8fSDarrick J. Wong iomap->addr != IOMAP_NULL_ADDR ? iomap->addr : 0,
395157fb8fSDarrick J. Wong iomap->length, flags);
405157fb8fSDarrick J. Wong }
415157fb8fSDarrick J. Wong
iomap_fiemap_iter(const struct iomap_iter * iter,struct fiemap_extent_info * fi,struct iomap * prev)427892386dSChristoph Hellwig static loff_t iomap_fiemap_iter(const struct iomap_iter *iter,
437892386dSChristoph Hellwig struct fiemap_extent_info *fi, struct iomap *prev)
445157fb8fSDarrick J. Wong {
457892386dSChristoph Hellwig int ret;
465157fb8fSDarrick J. Wong
477892386dSChristoph Hellwig if (iter->iomap.type == IOMAP_HOLE)
487892386dSChristoph Hellwig return iomap_length(iter);
495157fb8fSDarrick J. Wong
507892386dSChristoph Hellwig ret = iomap_to_fiemap(fi, prev, 0);
517892386dSChristoph Hellwig *prev = iter->iomap;
525157fb8fSDarrick J. Wong switch (ret) {
535157fb8fSDarrick J. Wong case 0: /* success */
547892386dSChristoph Hellwig return iomap_length(iter);
555157fb8fSDarrick J. Wong case 1: /* extent array full */
565157fb8fSDarrick J. Wong return 0;
577892386dSChristoph Hellwig default: /* error */
585157fb8fSDarrick J. Wong return ret;
595157fb8fSDarrick J. Wong }
605157fb8fSDarrick J. Wong }
615157fb8fSDarrick J. Wong
iomap_fiemap(struct inode * inode,struct fiemap_extent_info * fi,u64 start,u64 len,const struct iomap_ops * ops)625157fb8fSDarrick J. Wong int iomap_fiemap(struct inode *inode, struct fiemap_extent_info *fi,
6327328818SChristoph Hellwig u64 start, u64 len, const struct iomap_ops *ops)
645157fb8fSDarrick J. Wong {
657892386dSChristoph Hellwig struct iomap_iter iter = {
667892386dSChristoph Hellwig .inode = inode,
677892386dSChristoph Hellwig .pos = start,
687892386dSChristoph Hellwig .len = len,
697892386dSChristoph Hellwig .flags = IOMAP_REPORT,
707892386dSChristoph Hellwig };
717892386dSChristoph Hellwig struct iomap prev = {
727892386dSChristoph Hellwig .type = IOMAP_HOLE,
737892386dSChristoph Hellwig };
747892386dSChristoph Hellwig int ret;
755157fb8fSDarrick J. Wong
767892386dSChristoph Hellwig ret = fiemap_prep(inode, fi, start, &iter.len, 0);
775157fb8fSDarrick J. Wong if (ret)
785157fb8fSDarrick J. Wong return ret;
795157fb8fSDarrick J. Wong
807892386dSChristoph Hellwig while ((ret = iomap_iter(&iter, ops)) > 0)
817892386dSChristoph Hellwig iter.processed = iomap_fiemap_iter(&iter, fi, &prev);
827892386dSChristoph Hellwig
837892386dSChristoph Hellwig if (prev.type != IOMAP_HOLE) {
847892386dSChristoph Hellwig ret = iomap_to_fiemap(fi, &prev, FIEMAP_EXTENT_LAST);
857892386dSChristoph Hellwig if (ret < 0)
867892386dSChristoph Hellwig return ret;
877892386dSChristoph Hellwig }
887892386dSChristoph Hellwig
895157fb8fSDarrick J. Wong /* inode with no (attribute) mapping will give ENOENT */
907892386dSChristoph Hellwig if (ret < 0 && ret != -ENOENT)
915157fb8fSDarrick J. Wong return ret;
925157fb8fSDarrick J. Wong return 0;
935157fb8fSDarrick J. Wong }
945157fb8fSDarrick J. Wong EXPORT_SYMBOL_GPL(iomap_fiemap);
955157fb8fSDarrick J. Wong
965157fb8fSDarrick J. Wong /* legacy ->bmap interface. 0 is the error return (!) */
975157fb8fSDarrick J. Wong sector_t
iomap_bmap(struct address_space * mapping,sector_t bno,const struct iomap_ops * ops)985157fb8fSDarrick J. Wong iomap_bmap(struct address_space *mapping, sector_t bno,
995157fb8fSDarrick J. Wong const struct iomap_ops *ops)
1005157fb8fSDarrick J. Wong {
1016d8a1287SChristoph Hellwig struct iomap_iter iter = {
1026d8a1287SChristoph Hellwig .inode = mapping->host,
1036d8a1287SChristoph Hellwig .pos = (loff_t)bno << mapping->host->i_blkbits,
1046d8a1287SChristoph Hellwig .len = i_blocksize(mapping->host),
1056d8a1287SChristoph Hellwig .flags = IOMAP_REPORT,
1066d8a1287SChristoph Hellwig };
1076d8a1287SChristoph Hellwig const unsigned int blkshift = mapping->host->i_blkbits - SECTOR_SHIFT;
1082b91b28eSDarrick J. Wong int ret;
1095157fb8fSDarrick J. Wong
1105157fb8fSDarrick J. Wong if (filemap_write_and_wait(mapping))
1115157fb8fSDarrick J. Wong return 0;
1125157fb8fSDarrick J. Wong
1135157fb8fSDarrick J. Wong bno = 0;
1146d8a1287SChristoph Hellwig while ((ret = iomap_iter(&iter, ops)) > 0) {
1156d8a1287SChristoph Hellwig if (iter.iomap.type == IOMAP_MAPPED)
1166d8a1287SChristoph Hellwig bno = iomap_sector(&iter.iomap, iter.pos) >> blkshift;
1176d8a1287SChristoph Hellwig /* leave iter.processed unset to abort loop */
1186d8a1287SChristoph Hellwig }
1192b91b28eSDarrick J. Wong if (ret)
1202b91b28eSDarrick J. Wong return 0;
1216d8a1287SChristoph Hellwig
1225157fb8fSDarrick J. Wong return bno;
1235157fb8fSDarrick J. Wong }
1245157fb8fSDarrick J. Wong EXPORT_SYMBOL_GPL(iomap_bmap);
125