xref: /openbmc/linux/fs/iomap/seek.c (revision 762f99f4f3cb41a775b5157dd761217beba65873)
156a17898SDarrick J. Wong // SPDX-License-Identifier: GPL-2.0
256a17898SDarrick J. Wong /*
356a17898SDarrick J. Wong  * Copyright (C) 2017 Red Hat, Inc.
440670d18SChristoph Hellwig  * Copyright (c) 2018-2021 Christoph Hellwig.
556a17898SDarrick J. Wong  */
656a17898SDarrick J. Wong #include <linux/module.h>
756a17898SDarrick J. Wong #include <linux/compiler.h>
856a17898SDarrick J. Wong #include <linux/fs.h>
956a17898SDarrick J. Wong #include <linux/iomap.h>
1056a17898SDarrick J. Wong #include <linux/pagemap.h>
1156a17898SDarrick J. Wong #include <linux/pagevec.h>
1256a17898SDarrick J. Wong 
iomap_seek_hole_iter(const struct iomap_iter * iter,loff_t * hole_pos)1340670d18SChristoph Hellwig static loff_t iomap_seek_hole_iter(const struct iomap_iter *iter,
1440670d18SChristoph Hellwig 		loff_t *hole_pos)
1556a17898SDarrick J. Wong {
1640670d18SChristoph Hellwig 	loff_t length = iomap_length(iter);
1754fa39acSMatthew Wilcox (Oracle) 
1840670d18SChristoph Hellwig 	switch (iter->iomap.type) {
1956a17898SDarrick J. Wong 	case IOMAP_UNWRITTEN:
2040670d18SChristoph Hellwig 		*hole_pos = mapping_seek_hole_data(iter->inode->i_mapping,
2140670d18SChristoph Hellwig 				iter->pos, iter->pos + length, SEEK_HOLE);
2240670d18SChristoph Hellwig 		if (*hole_pos == iter->pos + length)
2356a17898SDarrick J. Wong 			return length;
2440670d18SChristoph Hellwig 		return 0;
2556a17898SDarrick J. Wong 	case IOMAP_HOLE:
2640670d18SChristoph Hellwig 		*hole_pos = iter->pos;
2756a17898SDarrick J. Wong 		return 0;
2856a17898SDarrick J. Wong 	default:
2956a17898SDarrick J. Wong 		return length;
3056a17898SDarrick J. Wong 	}
3156a17898SDarrick J. Wong }
3256a17898SDarrick J. Wong 
3356a17898SDarrick J. Wong loff_t
iomap_seek_hole(struct inode * inode,loff_t pos,const struct iomap_ops * ops)3440670d18SChristoph Hellwig iomap_seek_hole(struct inode *inode, loff_t pos, const struct iomap_ops *ops)
3556a17898SDarrick J. Wong {
3656a17898SDarrick J. Wong 	loff_t size = i_size_read(inode);
3740670d18SChristoph Hellwig 	struct iomap_iter iter = {
3840670d18SChristoph Hellwig 		.inode	= inode,
3940670d18SChristoph Hellwig 		.pos	= pos,
4040670d18SChristoph Hellwig 		.flags	= IOMAP_REPORT,
4140670d18SChristoph Hellwig 	};
4240670d18SChristoph Hellwig 	int ret;
4356a17898SDarrick J. Wong 
4456a17898SDarrick J. Wong 	/* Nothing to be found before or beyond the end of the file. */
4540670d18SChristoph Hellwig 	if (pos < 0 || pos >= size)
4656a17898SDarrick J. Wong 		return -ENXIO;
4756a17898SDarrick J. Wong 
4840670d18SChristoph Hellwig 	iter.len = size - pos;
4940670d18SChristoph Hellwig 	while ((ret = iomap_iter(&iter, ops)) > 0)
5040670d18SChristoph Hellwig 		iter.processed = iomap_seek_hole_iter(&iter, &pos);
5156a17898SDarrick J. Wong 	if (ret < 0)
5256a17898SDarrick J. Wong 		return ret;
5340670d18SChristoph Hellwig 	if (iter.len) /* found hole before EOF */
5440670d18SChristoph Hellwig 		return pos;
5540670d18SChristoph Hellwig 	return size;
5656a17898SDarrick J. Wong }
5756a17898SDarrick J. Wong EXPORT_SYMBOL_GPL(iomap_seek_hole);
5856a17898SDarrick J. Wong 
iomap_seek_data_iter(const struct iomap_iter * iter,loff_t * hole_pos)59*c4740bf1SChristoph Hellwig static loff_t iomap_seek_data_iter(const struct iomap_iter *iter,
60*c4740bf1SChristoph Hellwig 		loff_t *hole_pos)
6156a17898SDarrick J. Wong {
62*c4740bf1SChristoph Hellwig 	loff_t length = iomap_length(iter);
6354fa39acSMatthew Wilcox (Oracle) 
64*c4740bf1SChristoph Hellwig 	switch (iter->iomap.type) {
6556a17898SDarrick J. Wong 	case IOMAP_HOLE:
6656a17898SDarrick J. Wong 		return length;
6756a17898SDarrick J. Wong 	case IOMAP_UNWRITTEN:
68*c4740bf1SChristoph Hellwig 		*hole_pos = mapping_seek_hole_data(iter->inode->i_mapping,
69*c4740bf1SChristoph Hellwig 				iter->pos, iter->pos + length, SEEK_DATA);
70*c4740bf1SChristoph Hellwig 		if (*hole_pos < 0)
7156a17898SDarrick J. Wong 			return length;
72*c4740bf1SChristoph Hellwig 		return 0;
7356a17898SDarrick J. Wong 	default:
74*c4740bf1SChristoph Hellwig 		*hole_pos = iter->pos;
7556a17898SDarrick J. Wong 		return 0;
7656a17898SDarrick J. Wong 	}
7756a17898SDarrick J. Wong }
7856a17898SDarrick J. Wong 
7956a17898SDarrick J. Wong loff_t
iomap_seek_data(struct inode * inode,loff_t pos,const struct iomap_ops * ops)80*c4740bf1SChristoph Hellwig iomap_seek_data(struct inode *inode, loff_t pos, const struct iomap_ops *ops)
8156a17898SDarrick J. Wong {
8256a17898SDarrick J. Wong 	loff_t size = i_size_read(inode);
83*c4740bf1SChristoph Hellwig 	struct iomap_iter iter = {
84*c4740bf1SChristoph Hellwig 		.inode	= inode,
85*c4740bf1SChristoph Hellwig 		.pos	= pos,
86*c4740bf1SChristoph Hellwig 		.flags	= IOMAP_REPORT,
87*c4740bf1SChristoph Hellwig 	};
88*c4740bf1SChristoph Hellwig 	int ret;
8956a17898SDarrick J. Wong 
9056a17898SDarrick J. Wong 	/* Nothing to be found before or beyond the end of the file. */
91*c4740bf1SChristoph Hellwig 	if (pos < 0 || pos >= size)
9256a17898SDarrick J. Wong 		return -ENXIO;
9356a17898SDarrick J. Wong 
94*c4740bf1SChristoph Hellwig 	iter.len = size - pos;
95*c4740bf1SChristoph Hellwig 	while ((ret = iomap_iter(&iter, ops)) > 0)
96*c4740bf1SChristoph Hellwig 		iter.processed = iomap_seek_data_iter(&iter, &pos);
9756a17898SDarrick J. Wong 	if (ret < 0)
9856a17898SDarrick J. Wong 		return ret;
99*c4740bf1SChristoph Hellwig 	if (iter.len) /* found data before EOF */
100*c4740bf1SChristoph Hellwig 		return pos;
1013ac1d426SChristoph Hellwig 	/* We've reached the end of the file without finding data */
10256a17898SDarrick J. Wong 	return -ENXIO;
10356a17898SDarrick J. Wong }
10456a17898SDarrick J. Wong EXPORT_SYMBOL_GPL(iomap_seek_data);
105