blob: ce6fb810854fecbd44d083114ba8d63ccb9b3bf0 [file] [log] [blame]
Darrick J. Wong56a17892019-07-15 08:50:58 -07001// 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
Darrick J. Wong56a17892019-07-15 08:50:58 -070013static loff_t
Matthew Wilcox (Oracle)54fa39a2021-02-25 17:15:52 -080014iomap_seek_hole_actor(struct inode *inode, loff_t start, loff_t length,
Goldwyn Rodriguesc039b992019-10-18 16:44:10 -070015 void *data, struct iomap *iomap, struct iomap *srcmap)
Darrick J. Wong56a17892019-07-15 08:50:58 -070016{
Matthew Wilcox (Oracle)54fa39a2021-02-25 17:15:52 -080017 loff_t offset = start;
18
Darrick J. Wong56a17892019-07-15 08:50:58 -070019 switch (iomap->type) {
20 case IOMAP_UNWRITTEN:
Matthew Wilcox (Oracle)54fa39a2021-02-25 17:15:52 -080021 offset = mapping_seek_hole_data(inode->i_mapping, start,
22 start + length, SEEK_HOLE);
23 if (offset == start + length)
Darrick J. Wong56a17892019-07-15 08:50:58 -070024 return length;
Gustavo A. R. Silvadf561f662020-08-23 17:36:59 -050025 fallthrough;
Darrick J. Wong56a17892019-07-15 08:50:58 -070026 case IOMAP_HOLE:
27 *(loff_t *)data = offset;
28 return 0;
29 default:
30 return length;
31 }
32}
33
34loff_t
35iomap_seek_hole(struct inode *inode, loff_t offset, const struct iomap_ops *ops)
36{
37 loff_t size = i_size_read(inode);
Darrick J. Wong56a17892019-07-15 08:50:58 -070038 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
Christoph Hellwig49694d12021-07-15 09:58:04 -070044 while (offset < size) {
45 ret = iomap_apply(inode, offset, size - offset, IOMAP_REPORT,
46 ops, &offset, iomap_seek_hole_actor);
Darrick J. Wong56a17892019-07-15 08:50:58 -070047 if (ret < 0)
48 return ret;
49 if (ret == 0)
50 break;
Darrick J. Wong56a17892019-07-15 08:50:58 -070051 offset += ret;
Darrick J. Wong56a17892019-07-15 08:50:58 -070052 }
53
54 return offset;
55}
56EXPORT_SYMBOL_GPL(iomap_seek_hole);
57
58static loff_t
Matthew Wilcox (Oracle)54fa39a2021-02-25 17:15:52 -080059iomap_seek_data_actor(struct inode *inode, loff_t start, loff_t length,
Goldwyn Rodriguesc039b992019-10-18 16:44:10 -070060 void *data, struct iomap *iomap, struct iomap *srcmap)
Darrick J. Wong56a17892019-07-15 08:50:58 -070061{
Matthew Wilcox (Oracle)54fa39a2021-02-25 17:15:52 -080062 loff_t offset = start;
63
Darrick J. Wong56a17892019-07-15 08:50:58 -070064 switch (iomap->type) {
65 case IOMAP_HOLE:
66 return length;
67 case IOMAP_UNWRITTEN:
Matthew Wilcox (Oracle)54fa39a2021-02-25 17:15:52 -080068 offset = mapping_seek_hole_data(inode->i_mapping, start,
69 start + length, SEEK_DATA);
Darrick J. Wong56a17892019-07-15 08:50:58 -070070 if (offset < 0)
71 return length;
Gustavo A. R. Silvadf561f662020-08-23 17:36:59 -050072 fallthrough;
Darrick J. Wong56a17892019-07-15 08:50:58 -070073 default:
74 *(loff_t *)data = offset;
75 return 0;
76 }
77}
78
79loff_t
80iomap_seek_data(struct inode *inode, loff_t offset, const struct iomap_ops *ops)
81{
82 loff_t size = i_size_read(inode);
Darrick J. Wong56a17892019-07-15 08:50:58 -070083 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
Christoph Hellwig3ac1d422021-07-15 09:58:04 -070089 while (offset < size) {
90 ret = iomap_apply(inode, offset, size - offset, IOMAP_REPORT,
91 ops, &offset, iomap_seek_data_actor);
Darrick J. Wong56a17892019-07-15 08:50:58 -070092 if (ret < 0)
93 return ret;
94 if (ret == 0)
Christoph Hellwig3ac1d422021-07-15 09:58:04 -070095 return offset;
Darrick J. Wong56a17892019-07-15 08:50:58 -070096 offset += ret;
Darrick J. Wong56a17892019-07-15 08:50:58 -070097 }
98
Christoph Hellwig3ac1d422021-07-15 09:58:04 -070099 /* We've reached the end of the file without finding data */
100 return -ENXIO;
Darrick J. Wong56a17892019-07-15 08:50:58 -0700101}
102EXPORT_SYMBOL_GPL(iomap_seek_data);