Merge tag 'fs.move_mount.move_mount_set_group.v5.15' of git://git.kernel.org/pub...
[linux-2.6-microblaze.git] / fs / iomap / seek.c
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/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 iomap_seek_hole_iter(const struct iomap_iter *iter,
14                 loff_t *hole_pos)
15 {
16         loff_t length = iomap_length(iter);
17
18         switch (iter->iomap.type) {
19         case IOMAP_UNWRITTEN:
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)
23                         return length;
24                 return 0;
25         case IOMAP_HOLE:
26                 *hole_pos = iter->pos;
27                 return 0;
28         default:
29                 return length;
30         }
31 }
32
33 loff_t
34 iomap_seek_hole(struct inode *inode, loff_t pos, const struct iomap_ops *ops)
35 {
36         loff_t size = i_size_read(inode);
37         struct iomap_iter iter = {
38                 .inode  = inode,
39                 .pos    = pos,
40                 .flags  = IOMAP_REPORT,
41         };
42         int ret;
43
44         /* Nothing to be found before or beyond the end of the file. */
45         if (pos < 0 || pos >= size)
46                 return -ENXIO;
47
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;
56 }
57 EXPORT_SYMBOL_GPL(iomap_seek_hole);
58
59 static loff_t iomap_seek_data_iter(const struct iomap_iter *iter,
60                 loff_t *hole_pos)
61 {
62         loff_t length = iomap_length(iter);
63
64         switch (iter->iomap.type) {
65         case IOMAP_HOLE:
66                 return length;
67         case IOMAP_UNWRITTEN:
68                 *hole_pos = mapping_seek_hole_data(iter->inode->i_mapping,
69                                 iter->pos, iter->pos + length, SEEK_DATA);
70                 if (*hole_pos < 0)
71                         return length;
72                 return 0;
73         default:
74                 *hole_pos = iter->pos;
75                 return 0;
76         }
77 }
78
79 loff_t
80 iomap_seek_data(struct inode *inode, loff_t pos, const struct iomap_ops *ops)
81 {
82         loff_t size = i_size_read(inode);
83         struct iomap_iter iter = {
84                 .inode  = inode,
85                 .pos    = pos,
86                 .flags  = IOMAP_REPORT,
87         };
88         int ret;
89
90         /* Nothing to be found before or beyond the end of the file. */
91         if (pos < 0 || pos >= size)
92                 return -ENXIO;
93
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;
101         /* We've reached the end of the file without finding data */
102         return -ENXIO;
103 }
104 EXPORT_SYMBOL_GPL(iomap_seek_data);