diff options
| author | Darrick J. Wong <djwong@kernel.org> | 2021-09-01 11:19:49 -0700 |
|---|---|---|
| committer | Darrick J. Wong <djwong@kernel.org> | 2021-12-15 17:29:26 -0800 |
| commit | 7ce91d85f50da47ca729f30c17d6db3883d71807 (patch) | |
| tree | b352be266ef7b5946ccab73da21d5cf1e1503ae9 | |
| parent | 74b282013965f04b503e533845eb5483da7c9521 (diff) | |
| download | xfs-linux-7ce91d85f50da47ca729f30c17d6db3883d71807.tar.gz | |
iomap: set up for COWing around pages
In anticipation of enabling reflink on the realtime volume where the
allocation unit is larger than a page, create an iomap function to dirty
arbitrary parts of a file's page cache so that when we dirty part of a
file that could undergo a COW extent, we can dirty an entire allocation
unit's worth of pages.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
| -rw-r--r-- | fs/iomap/buffered-io.c | 55 | ||||
| -rw-r--r-- | include/linux/iomap.h | 2 |
2 files changed, 57 insertions, 0 deletions
diff --git a/fs/iomap/buffered-io.c b/fs/iomap/buffered-io.c index 71a36ae120ee8..76a879dc2aebf 100644 --- a/fs/iomap/buffered-io.c +++ b/fs/iomap/buffered-io.c @@ -876,6 +876,61 @@ iomap_file_unshare(struct inode *inode, loff_t pos, loff_t len, } EXPORT_SYMBOL_GPL(iomap_file_unshare); +static loff_t iomap_dirty_iter(struct iomap_iter *iter) +{ + loff_t pos = iter->pos; + loff_t length = iomap_length(iter); + long status = 0; + loff_t written = 0; + + do { + unsigned long offset = offset_in_page(pos); + unsigned long bytes = min_t(loff_t, PAGE_SIZE - offset, length); + struct page *page; + + status = iomap_write_begin(iter, pos, bytes, &page); + if (unlikely(status)) + return status; + + mark_page_accessed(page); + + status = iomap_write_end(iter, pos, bytes, bytes, page); + if (WARN_ON_ONCE(status == 0)) + return -EIO; + + cond_resched(); + + pos += status; + written += status; + length -= status; + + balance_dirty_pages_ratelimited(iter->inode->i_mapping); + } while (length); + + return written; +} + +int +iomap_dirty_range(struct inode *inode, loff_t pos, u64 len, + const struct iomap_ops *ops) +{ + struct iomap_iter iter = { + .inode = inode, + .pos = pos, + .len = len, + .flags = IOMAP_WRITE, + }; + int ret; + + if (IS_DAX(inode)) + return -EINVAL; + + while ((ret = iomap_iter(&iter, ops)) > 0) + iter.processed = iomap_dirty_iter(&iter); + return ret; +} +EXPORT_SYMBOL_GPL(iomap_dirty_range); + static s64 __iomap_zero_iter(struct iomap_iter *iter, loff_t pos, u64 length) { struct page *page; diff --git a/include/linux/iomap.h b/include/linux/iomap.h index 6d1b08d0ae930..3c7c939d394ee 100644 --- a/include/linux/iomap.h +++ b/include/linux/iomap.h @@ -235,6 +235,8 @@ int iomap_migrate_page(struct address_space *mapping, struct page *newpage, #endif int iomap_file_unshare(struct inode *inode, loff_t pos, loff_t len, const struct iomap_ops *ops); +int iomap_dirty_range(struct inode *inode, loff_t pos, u64 len, + const struct iomap_ops *ops); int iomap_zero_range(struct inode *inode, loff_t pos, loff_t len, bool *did_zero, const struct iomap_ops *ops); int iomap_truncate_page(struct inode *inode, loff_t pos, bool *did_zero, |
