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