blob: 484dd8eda861df5408831d3c0f45ebf8cd304e9b [file] [log] [blame]
Christoph Hellwig73ce6ab2019-04-28 08:34:02 -07001// SPDX-License-Identifier: GPL-2.0
Christoph Hellwigae259a92016-06-21 09:23:11 +10002/*
3 * Copyright (C) 2010 Red Hat, Inc.
Christoph Hellwig72b4daa2018-06-19 15:10:57 -07004 * Copyright (c) 2016-2018 Christoph Hellwig.
Christoph Hellwigae259a92016-06-21 09:23:11 +10005 */
6#include <linux/module.h>
7#include <linux/compiler.h>
8#include <linux/fs.h>
9#include <linux/iomap.h>
Ingo Molnarf361bf42017-02-03 23:47:37 +010010
Christoph Hellwigae259a92016-06-21 09:23:11 +100011/*
12 * Execute a iomap write on a segment of the mapping that spans a
13 * contiguous range of pages that have identical block mapping state.
14 *
15 * This avoids the need to map pages individually, do individual allocations
16 * for each page and most importantly avoid the need for filesystem specific
17 * locking per page. Instead, all the operations are amortised over the entire
18 * range of pages. It is assumed that the filesystems will lock whatever
19 * resources they require in the iomap_begin call, and release them in the
20 * iomap_end call.
21 */
Christoph Hellwigbefb5032016-09-19 11:24:49 +100022loff_t
Christoph Hellwigae259a92016-06-21 09:23:11 +100023iomap_apply(struct inode *inode, loff_t pos, loff_t length, unsigned flags,
Christoph Hellwig8ff6daa2017-01-27 23:20:26 -080024 const struct iomap_ops *ops, void *data, iomap_actor_t actor)
Christoph Hellwigae259a92016-06-21 09:23:11 +100025{
Goldwyn Rodriguesc039b992019-10-18 16:44:10 -070026 struct iomap iomap = { .type = IOMAP_HOLE };
27 struct iomap srcmap = { .type = IOMAP_HOLE };
Christoph Hellwigae259a92016-06-21 09:23:11 +100028 loff_t written = 0, ret;
Goldwyn Rodriguesc039b992019-10-18 16:44:10 -070029 u64 end;
Christoph Hellwigae259a92016-06-21 09:23:11 +100030
31 /*
32 * Need to map a range from start position for length bytes. This can
33 * span multiple pages - it is only guaranteed to return a range of a
34 * single type of pages (e.g. all into a hole, all mapped or all
35 * unwritten). Failure at this point has nothing to undo.
36 *
37 * If allocation is required for this range, reserve the space now so
38 * that the allocation is guaranteed to succeed later on. Once we copy
39 * the data into the page cache pages, then we cannot fail otherwise we
40 * expose transient stale data. If the reserve fails, we can safely
41 * back out at this point as there is nothing to undo.
42 */
Goldwyn Rodriguesc039b992019-10-18 16:44:10 -070043 ret = ops->iomap_begin(inode, pos, length, flags, &iomap, &srcmap);
Christoph Hellwigae259a92016-06-21 09:23:11 +100044 if (ret)
45 return ret;
46 if (WARN_ON(iomap.offset > pos))
47 return -EIO;
Darrick J. Wong0c6dda72018-01-26 11:11:20 -080048 if (WARN_ON(iomap.length == 0))
49 return -EIO;
Christoph Hellwigae259a92016-06-21 09:23:11 +100050
51 /*
52 * Cut down the length to the one actually provided by the filesystem,
53 * as it might not be able to give us the whole size that we requested.
54 */
Goldwyn Rodriguesc039b992019-10-18 16:44:10 -070055 end = iomap.offset + iomap.length;
56 if (srcmap.type != IOMAP_HOLE)
57 end = min(end, srcmap.offset + srcmap.length);
58 if (pos + length > end)
59 length = end - pos;
Christoph Hellwigae259a92016-06-21 09:23:11 +100060
61 /*
Goldwyn Rodriguesc039b992019-10-18 16:44:10 -070062 * Now that we have guaranteed that the space allocation will succeed,
Christoph Hellwigae259a92016-06-21 09:23:11 +100063 * we can do the copy-in page by page without having to worry about
64 * failures exposing transient data.
Goldwyn Rodriguesc039b992019-10-18 16:44:10 -070065 *
66 * To support COW operations, we read in data for partially blocks from
67 * the srcmap if the file system filled it in. In that case we the
68 * length needs to be limited to the earlier of the ends of the iomaps.
69 * If the file system did not provide a srcmap we pass in the normal
70 * iomap into the actors so that they don't need to have special
71 * handling for the two cases.
Christoph Hellwigae259a92016-06-21 09:23:11 +100072 */
Goldwyn Rodriguesc039b992019-10-18 16:44:10 -070073 written = actor(inode, pos, length, data, &iomap,
74 srcmap.type != IOMAP_HOLE ? &srcmap : &iomap);
Christoph Hellwigae259a92016-06-21 09:23:11 +100075
76 /*
77 * Now the data has been copied, commit the range we've copied. This
78 * should not fail unless the filesystem has had a fatal error.
79 */
Christoph Hellwigf20ac7a2016-08-17 08:42:34 +100080 if (ops->iomap_end) {
81 ret = ops->iomap_end(inode, pos, length,
82 written > 0 ? written : 0,
83 flags, &iomap);
84 }
Christoph Hellwigae259a92016-06-21 09:23:11 +100085
86 return written ? written : ret;
87}