perf auxtrace arm: Support compat_auxtrace_mmap__{read_head|write_tail}
[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 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 iomap_seek_hole_actor(struct inode *inode, loff_t start, loff_t length,
15                       void *data, struct iomap *iomap, struct iomap *srcmap)
16 {
17         loff_t offset = start;
18
19         switch (iomap->type) {
20         case IOMAP_UNWRITTEN:
21                 offset = mapping_seek_hole_data(inode->i_mapping, start,
22                                 start + length, SEEK_HOLE);
23                 if (offset == start + length)
24                         return length;
25                 fallthrough;
26         case IOMAP_HOLE:
27                 *(loff_t *)data = offset;
28                 return 0;
29         default:
30                 return length;
31         }
32 }
33
34 loff_t
35 iomap_seek_hole(struct inode *inode, loff_t offset, const struct iomap_ops *ops)
36 {
37         loff_t size = i_size_read(inode);
38         loff_t ret;
39
40         /* Nothing to be found before or beyond the end of the file. */
41         if (offset < 0 || offset >= size)
42                 return -ENXIO;
43
44         while (offset < size) {
45                 ret = iomap_apply(inode, offset, size - offset, IOMAP_REPORT,
46                                   ops, &offset, iomap_seek_hole_actor);
47                 if (ret < 0)
48                         return ret;
49                 if (ret == 0)
50                         break;
51                 offset += ret;
52         }
53
54         return offset;
55 }
56 EXPORT_SYMBOL_GPL(iomap_seek_hole);
57
58 static loff_t
59 iomap_seek_data_actor(struct inode *inode, loff_t start, loff_t length,
60                       void *data, struct iomap *iomap, struct iomap *srcmap)
61 {
62         loff_t offset = start;
63
64         switch (iomap->type) {
65         case IOMAP_HOLE:
66                 return length;
67         case IOMAP_UNWRITTEN:
68                 offset = mapping_seek_hole_data(inode->i_mapping, start,
69                                 start + length, SEEK_DATA);
70                 if (offset < 0)
71                         return length;
72                 fallthrough;
73         default:
74                 *(loff_t *)data = offset;
75                 return 0;
76         }
77 }
78
79 loff_t
80 iomap_seek_data(struct inode *inode, loff_t offset, const struct iomap_ops *ops)
81 {
82         loff_t size = i_size_read(inode);
83         loff_t ret;
84
85         /* Nothing to be found before or beyond the end of the file. */
86         if (offset < 0 || offset >= size)
87                 return -ENXIO;
88
89         while (offset < size) {
90                 ret = iomap_apply(inode, offset, size - offset, IOMAP_REPORT,
91                                   ops, &offset, iomap_seek_data_actor);
92                 if (ret < 0)
93                         return ret;
94                 if (ret == 0)
95                         return offset;
96                 offset += ret;
97         }
98
99         /* We've reached the end of the file without finding data */
100         return -ENXIO;
101 }
102 EXPORT_SYMBOL_GPL(iomap_seek_data);