Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0 2 : : /* 3 : : * Copyright (C) 2010 Red Hat, Inc. 4 : : * Copyright (c) 2016-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 : : 11 : : /* 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 : : */ 22 : : loff_t 23 : 0 : iomap_apply(struct inode *inode, loff_t pos, loff_t length, unsigned flags, 24 : : const struct iomap_ops *ops, void *data, iomap_actor_t actor) 25 : : { 26 : 0 : struct iomap iomap = { 0 }; 27 : : loff_t written = 0, ret; 28 : : 29 : : /* 30 : : * Need to map a range from start position for length bytes. This can 31 : : * span multiple pages - it is only guaranteed to return a range of a 32 : : * single type of pages (e.g. all into a hole, all mapped or all 33 : : * unwritten). Failure at this point has nothing to undo. 34 : : * 35 : : * If allocation is required for this range, reserve the space now so 36 : : * that the allocation is guaranteed to succeed later on. Once we copy 37 : : * the data into the page cache pages, then we cannot fail otherwise we 38 : : * expose transient stale data. If the reserve fails, we can safely 39 : : * back out at this point as there is nothing to undo. 40 : : */ 41 : 0 : ret = ops->iomap_begin(inode, pos, length, flags, &iomap); 42 : 0 : if (ret) 43 : : return ret; 44 : 0 : if (WARN_ON(iomap.offset > pos)) 45 : : return -EIO; 46 : 0 : if (WARN_ON(iomap.length == 0)) 47 : : return -EIO; 48 : : 49 : : /* 50 : : * Cut down the length to the one actually provided by the filesystem, 51 : : * as it might not be able to give us the whole size that we requested. 52 : : */ 53 : 0 : if (iomap.offset + iomap.length < pos + length) 54 : 0 : length = iomap.offset + iomap.length - pos; 55 : : 56 : : /* 57 : : * Now that we have guaranteed that the space allocation will succeed. 58 : : * we can do the copy-in page by page without having to worry about 59 : : * failures exposing transient data. 60 : : */ 61 : 0 : written = actor(inode, pos, length, data, &iomap); 62 : : 63 : : /* 64 : : * Now the data has been copied, commit the range we've copied. This 65 : : * should not fail unless the filesystem has had a fatal error. 66 : : */ 67 : 0 : if (ops->iomap_end) { 68 : 0 : ret = ops->iomap_end(inode, pos, length, 69 : 0 : written > 0 ? written : 0, 70 : : flags, &iomap); 71 : : } 72 : : 73 : 0 : return written ? written : ret; 74 : : }