xref: /openbmc/linux/fs/iomap/fiemap.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
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