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