1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright (C) 2017 Red Hat, Inc.
4 * Copyright (c) 2018-2021 Christoph Hellwig.
5 */
6 #include <linux/iomap.h>
7 #include <linux/pagemap.h>
8
iomap_seek_hole_iter(struct iomap_iter * iter,loff_t * hole_pos)9 static int iomap_seek_hole_iter(struct iomap_iter *iter,
10 loff_t *hole_pos)
11 {
12 loff_t length = iomap_length(iter);
13
14 switch (iter->iomap.type) {
15 case IOMAP_UNWRITTEN:
16 *hole_pos = mapping_seek_hole_data(iter->inode->i_mapping,
17 iter->pos, iter->pos + length, SEEK_HOLE);
18 if (*hole_pos == iter->pos + length)
19 return iomap_iter_advance(iter, &length);
20 return 0;
21 case IOMAP_HOLE:
22 *hole_pos = iter->pos;
23 return 0;
24 default:
25 return iomap_iter_advance(iter, &length);
26 }
27 }
28
29 loff_t
iomap_seek_hole(struct inode * inode,loff_t pos,const struct iomap_ops * ops)30 iomap_seek_hole(struct inode *inode, loff_t pos, const struct iomap_ops *ops)
31 {
32 loff_t size = i_size_read(inode);
33 struct iomap_iter iter = {
34 .inode = inode,
35 .pos = pos,
36 .flags = IOMAP_REPORT,
37 };
38 int ret;
39
40 /* Nothing to be found before or beyond the end of the file. */
41 if (pos < 0 || pos >= size)
42 return -ENXIO;
43
44 iter.len = size - pos;
45 while ((ret = iomap_iter(&iter, ops)) > 0)
46 iter.status = iomap_seek_hole_iter(&iter, &pos);
47 if (ret < 0)
48 return ret;
49 if (iter.len) /* found hole before EOF */
50 return pos;
51 return size;
52 }
53 EXPORT_SYMBOL_GPL(iomap_seek_hole);
54
iomap_seek_data_iter(struct iomap_iter * iter,loff_t * hole_pos)55 static int iomap_seek_data_iter(struct iomap_iter *iter,
56 loff_t *hole_pos)
57 {
58 loff_t length = iomap_length(iter);
59
60 switch (iter->iomap.type) {
61 case IOMAP_HOLE:
62 return iomap_iter_advance(iter, &length);
63 case IOMAP_UNWRITTEN:
64 *hole_pos = mapping_seek_hole_data(iter->inode->i_mapping,
65 iter->pos, iter->pos + length, SEEK_DATA);
66 if (*hole_pos < 0)
67 return iomap_iter_advance(iter, &length);
68 return 0;
69 default:
70 *hole_pos = iter->pos;
71 return 0;
72 }
73 }
74
75 loff_t
iomap_seek_data(struct inode * inode,loff_t pos,const struct iomap_ops * ops)76 iomap_seek_data(struct inode *inode, loff_t pos, const struct iomap_ops *ops)
77 {
78 loff_t size = i_size_read(inode);
79 struct iomap_iter iter = {
80 .inode = inode,
81 .pos = pos,
82 .flags = IOMAP_REPORT,
83 };
84 int ret;
85
86 /* Nothing to be found before or beyond the end of the file. */
87 if (pos < 0 || pos >= size)
88 return -ENXIO;
89
90 iter.len = size - pos;
91 while ((ret = iomap_iter(&iter, ops)) > 0)
92 iter.status = iomap_seek_data_iter(&iter, &pos);
93 if (ret < 0)
94 return ret;
95 if (iter.len) /* found data before EOF */
96 return pos;
97 /* We've reached the end of the file without finding data */
98 return -ENXIO;
99 }
100 EXPORT_SYMBOL_GPL(iomap_seek_data);
101