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