| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100 |
- // SPDX-License-Identifier: GPL-2.0
- /*
- * Copyright (C) 2017 Red Hat, Inc.
- * Copyright (c) 2018-2021 Christoph Hellwig.
- */
- #include <linux/iomap.h>
- #include <linux/pagemap.h>
- static int iomap_seek_hole_iter(struct iomap_iter *iter,
- loff_t *hole_pos)
- {
- loff_t length = iomap_length(iter);
- switch (iter->iomap.type) {
- case IOMAP_UNWRITTEN:
- *hole_pos = mapping_seek_hole_data(iter->inode->i_mapping,
- iter->pos, iter->pos + length, SEEK_HOLE);
- if (*hole_pos == iter->pos + length)
- return iomap_iter_advance(iter, length);
- return 0;
- case IOMAP_HOLE:
- *hole_pos = iter->pos;
- return 0;
- default:
- return iomap_iter_advance(iter, length);
- }
- }
- loff_t
- iomap_seek_hole(struct inode *inode, loff_t pos, const struct iomap_ops *ops)
- {
- loff_t size = i_size_read(inode);
- struct iomap_iter iter = {
- .inode = inode,
- .pos = pos,
- .flags = IOMAP_REPORT,
- };
- int ret;
- /* Nothing to be found before or beyond the end of the file. */
- if (pos < 0 || pos >= size)
- return -ENXIO;
- iter.len = size - pos;
- while ((ret = iomap_iter(&iter, ops)) > 0)
- iter.status = iomap_seek_hole_iter(&iter, &pos);
- if (ret < 0)
- return ret;
- if (iter.len) /* found hole before EOF */
- return pos;
- return size;
- }
- EXPORT_SYMBOL_GPL(iomap_seek_hole);
- static int iomap_seek_data_iter(struct iomap_iter *iter,
- loff_t *hole_pos)
- {
- loff_t length = iomap_length(iter);
- switch (iter->iomap.type) {
- case IOMAP_HOLE:
- return iomap_iter_advance(iter, length);
- case IOMAP_UNWRITTEN:
- *hole_pos = mapping_seek_hole_data(iter->inode->i_mapping,
- iter->pos, iter->pos + length, SEEK_DATA);
- if (*hole_pos < 0)
- return iomap_iter_advance(iter, length);
- return 0;
- default:
- *hole_pos = iter->pos;
- return 0;
- }
- }
- loff_t
- iomap_seek_data(struct inode *inode, loff_t pos, const struct iomap_ops *ops)
- {
- loff_t size = i_size_read(inode);
- struct iomap_iter iter = {
- .inode = inode,
- .pos = pos,
- .flags = IOMAP_REPORT,
- };
- int ret;
- /* Nothing to be found before or beyond the end of the file. */
- if (pos < 0 || pos >= size)
- return -ENXIO;
- iter.len = size - pos;
- while ((ret = iomap_iter(&iter, ops)) > 0)
- iter.status = iomap_seek_data_iter(&iter, &pos);
- if (ret < 0)
- return ret;
- if (iter.len) /* found data before EOF */
- return pos;
- /* We've reached the end of the file without finding data */
- return -ENXIO;
- }
- EXPORT_SYMBOL_GPL(iomap_seek_data);
|