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