Line data Source code
1 : // SPDX-License-Identifier: GPL-2.0
2 : /*
3 : * Copyright (C) 2017 Red Hat, Inc.
4 : * Copyright (c) 2018 Christoph Hellwig.
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 :
13 : static loff_t
14 0 : iomap_seek_hole_actor(struct inode *inode, loff_t start, loff_t length,
15 : void *data, struct iomap *iomap, struct iomap *srcmap)
16 : {
17 0 : loff_t offset = start;
18 :
19 0 : switch (iomap->type) {
20 0 : case IOMAP_UNWRITTEN:
21 0 : offset = mapping_seek_hole_data(inode->i_mapping, start,
22 : start + length, SEEK_HOLE);
23 0 : if (offset == start + length)
24 : return length;
25 0 : fallthrough;
26 : case IOMAP_HOLE:
27 0 : *(loff_t *)data = offset;
28 0 : return 0;
29 : default:
30 : return length;
31 : }
32 : }
33 :
34 : loff_t
35 0 : iomap_seek_hole(struct inode *inode, loff_t offset, const struct iomap_ops *ops)
36 : {
37 0 : loff_t size = i_size_read(inode);
38 0 : loff_t length = size - offset;
39 0 : loff_t ret;
40 :
41 : /* Nothing to be found before or beyond the end of the file. */
42 0 : if (offset < 0 || offset >= size)
43 : return -ENXIO;
44 :
45 0 : while (length > 0) {
46 0 : ret = iomap_apply(inode, offset, length, IOMAP_REPORT, ops,
47 : &offset, iomap_seek_hole_actor);
48 0 : if (ret < 0)
49 0 : return ret;
50 0 : if (ret == 0)
51 : break;
52 :
53 0 : offset += ret;
54 0 : length -= ret;
55 : }
56 :
57 0 : return offset;
58 : }
59 : EXPORT_SYMBOL_GPL(iomap_seek_hole);
60 :
61 : static loff_t
62 0 : iomap_seek_data_actor(struct inode *inode, loff_t start, loff_t length,
63 : void *data, struct iomap *iomap, struct iomap *srcmap)
64 : {
65 0 : loff_t offset = start;
66 :
67 0 : switch (iomap->type) {
68 : case IOMAP_HOLE:
69 : return length;
70 0 : case IOMAP_UNWRITTEN:
71 0 : offset = mapping_seek_hole_data(inode->i_mapping, start,
72 : start + length, SEEK_DATA);
73 0 : if (offset < 0)
74 : return length;
75 0 : fallthrough;
76 : default:
77 0 : *(loff_t *)data = offset;
78 0 : return 0;
79 : }
80 : }
81 :
82 : loff_t
83 0 : iomap_seek_data(struct inode *inode, loff_t offset, const struct iomap_ops *ops)
84 : {
85 0 : loff_t size = i_size_read(inode);
86 0 : loff_t length = size - offset;
87 0 : loff_t ret;
88 :
89 : /* Nothing to be found before or beyond the end of the file. */
90 0 : if (offset < 0 || offset >= size)
91 : return -ENXIO;
92 :
93 0 : while (length > 0) {
94 0 : ret = iomap_apply(inode, offset, length, IOMAP_REPORT, ops,
95 : &offset, iomap_seek_data_actor);
96 0 : if (ret < 0)
97 0 : return ret;
98 0 : if (ret == 0)
99 : break;
100 :
101 0 : offset += ret;
102 0 : length -= ret;
103 : }
104 :
105 0 : if (length <= 0)
106 : return -ENXIO;
107 0 : return offset;
108 : }
109 : EXPORT_SYMBOL_GPL(iomap_seek_data);
|