Commit | Line | Data |
---|---|---|
5157fb8f DW |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* | |
3 | * Copyright (c) 2016-2018 Christoph Hellwig. | |
4 | */ | |
5 | #include <linux/module.h> | |
6 | #include <linux/compiler.h> | |
7 | #include <linux/fs.h> | |
8 | #include <linux/iomap.h> | |
10c5db28 | 9 | #include <linux/fiemap.h> |
5157fb8f | 10 | |
5157fb8f DW |
11 | struct fiemap_ctx { |
12 | struct fiemap_extent_info *fi; | |
13 | struct iomap prev; | |
14 | }; | |
15 | ||
16 | static int iomap_to_fiemap(struct fiemap_extent_info *fi, | |
17 | struct iomap *iomap, u32 flags) | |
18 | { | |
19 | switch (iomap->type) { | |
20 | case IOMAP_HOLE: | |
21 | /* skip holes */ | |
22 | return 0; | |
23 | case IOMAP_DELALLOC: | |
24 | flags |= FIEMAP_EXTENT_DELALLOC | FIEMAP_EXTENT_UNKNOWN; | |
25 | break; | |
26 | case IOMAP_MAPPED: | |
27 | break; | |
28 | case IOMAP_UNWRITTEN: | |
29 | flags |= FIEMAP_EXTENT_UNWRITTEN; | |
30 | break; | |
31 | case IOMAP_INLINE: | |
32 | flags |= FIEMAP_EXTENT_DATA_INLINE; | |
33 | break; | |
34 | } | |
35 | ||
36 | if (iomap->flags & IOMAP_F_MERGED) | |
37 | flags |= FIEMAP_EXTENT_MERGED; | |
38 | if (iomap->flags & IOMAP_F_SHARED) | |
39 | flags |= FIEMAP_EXTENT_SHARED; | |
40 | ||
41 | return fiemap_fill_next_extent(fi, iomap->offset, | |
42 | iomap->addr != IOMAP_NULL_ADDR ? iomap->addr : 0, | |
43 | iomap->length, flags); | |
44 | } | |
45 | ||
46 | static loff_t | |
47 | iomap_fiemap_actor(struct inode *inode, loff_t pos, loff_t length, void *data, | |
c039b997 | 48 | struct iomap *iomap, struct iomap *srcmap) |
5157fb8f DW |
49 | { |
50 | struct fiemap_ctx *ctx = data; | |
51 | loff_t ret = length; | |
52 | ||
53 | if (iomap->type == IOMAP_HOLE) | |
54 | return length; | |
55 | ||
56 | ret = iomap_to_fiemap(ctx->fi, &ctx->prev, 0); | |
57 | ctx->prev = *iomap; | |
58 | switch (ret) { | |
59 | case 0: /* success */ | |
60 | return length; | |
61 | case 1: /* extent array full */ | |
62 | return 0; | |
63 | default: | |
64 | return ret; | |
65 | } | |
66 | } | |
67 | ||
68 | int iomap_fiemap(struct inode *inode, struct fiemap_extent_info *fi, | |
27328818 | 69 | u64 start, u64 len, const struct iomap_ops *ops) |
5157fb8f DW |
70 | { |
71 | struct fiemap_ctx ctx; | |
72 | loff_t ret; | |
73 | ||
74 | memset(&ctx, 0, sizeof(ctx)); | |
75 | ctx.fi = fi; | |
76 | ctx.prev.type = IOMAP_HOLE; | |
77 | ||
45dd052e | 78 | ret = fiemap_prep(inode, fi, start, &len, 0); |
5157fb8f DW |
79 | if (ret) |
80 | return ret; | |
81 | ||
5157fb8f DW |
82 | while (len > 0) { |
83 | ret = iomap_apply(inode, start, len, IOMAP_REPORT, ops, &ctx, | |
84 | iomap_fiemap_actor); | |
85 | /* inode with no (attribute) mapping will give ENOENT */ | |
86 | if (ret == -ENOENT) | |
87 | break; | |
88 | if (ret < 0) | |
89 | return ret; | |
90 | if (ret == 0) | |
91 | break; | |
92 | ||
93 | start += ret; | |
94 | len -= ret; | |
95 | } | |
96 | ||
97 | if (ctx.prev.type != IOMAP_HOLE) { | |
98 | ret = iomap_to_fiemap(fi, &ctx.prev, FIEMAP_EXTENT_LAST); | |
99 | if (ret < 0) | |
100 | return ret; | |
101 | } | |
102 | ||
103 | return 0; | |
104 | } | |
105 | EXPORT_SYMBOL_GPL(iomap_fiemap); | |
106 | ||
107 | static loff_t | |
108 | iomap_bmap_actor(struct inode *inode, loff_t pos, loff_t length, | |
c039b997 | 109 | void *data, struct iomap *iomap, struct iomap *srcmap) |
5157fb8f DW |
110 | { |
111 | sector_t *bno = data, addr; | |
112 | ||
113 | if (iomap->type == IOMAP_MAPPED) { | |
114 | addr = (pos - iomap->offset + iomap->addr) >> inode->i_blkbits; | |
b75dfde1 | 115 | *bno = addr; |
5157fb8f DW |
116 | } |
117 | return 0; | |
118 | } | |
119 | ||
120 | /* legacy ->bmap interface. 0 is the error return (!) */ | |
121 | sector_t | |
122 | iomap_bmap(struct address_space *mapping, sector_t bno, | |
123 | const struct iomap_ops *ops) | |
124 | { | |
125 | struct inode *inode = mapping->host; | |
126 | loff_t pos = bno << inode->i_blkbits; | |
127 | unsigned blocksize = i_blocksize(inode); | |
2b91b28e | 128 | int ret; |
5157fb8f DW |
129 | |
130 | if (filemap_write_and_wait(mapping)) | |
131 | return 0; | |
132 | ||
133 | bno = 0; | |
2b91b28e DW |
134 | ret = iomap_apply(inode, pos, blocksize, 0, ops, &bno, |
135 | iomap_bmap_actor); | |
136 | if (ret) | |
137 | return 0; | |
5157fb8f DW |
138 | return bno; |
139 | } | |
140 | EXPORT_SYMBOL_GPL(iomap_bmap); |