Skip to content

Commit 5f4e575

Browse files
Christoph Hellwigdchinner
authored andcommitted
fs: add iomap_file_dirty
Originally-From: Christoph Hellwig <[email protected]> This function uses the iomap infrastructure to re-write all pages in a given range. This is useful for doing a copy-up of COW ranges, and might be useful for scrubbing in the future. Signed-off-by: Christoph Hellwig <[email protected]> Reviewed-by: Dave Chinner <[email protected]> Signed-off-by: Dave Chinner <[email protected]>
1 parent ea78d80 commit 5f4e575

File tree

2 files changed

+84
-0
lines changed

2 files changed

+84
-0
lines changed

fs/iomap.c

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,88 @@ iomap_file_buffered_write(struct kiocb *iocb, struct iov_iter *iter,
252252
}
253253
EXPORT_SYMBOL_GPL(iomap_file_buffered_write);
254254

255+
static struct page *
256+
__iomap_read_page(struct inode *inode, loff_t offset)
257+
{
258+
struct address_space *mapping = inode->i_mapping;
259+
struct page *page;
260+
261+
page = read_mapping_page(mapping, offset >> PAGE_SHIFT, NULL);
262+
if (IS_ERR(page))
263+
return page;
264+
if (!PageUptodate(page)) {
265+
put_page(page);
266+
return ERR_PTR(-EIO);
267+
}
268+
return page;
269+
}
270+
271+
static loff_t
272+
iomap_dirty_actor(struct inode *inode, loff_t pos, loff_t length, void *data,
273+
struct iomap *iomap)
274+
{
275+
long status = 0;
276+
ssize_t written = 0;
277+
278+
do {
279+
struct page *page, *rpage;
280+
unsigned long offset; /* Offset into pagecache page */
281+
unsigned long bytes; /* Bytes to write to page */
282+
283+
offset = (pos & (PAGE_SIZE - 1));
284+
bytes = min_t(unsigned long, PAGE_SIZE - offset, length);
285+
286+
rpage = __iomap_read_page(inode, pos);
287+
if (IS_ERR(rpage))
288+
return PTR_ERR(rpage);
289+
290+
status = iomap_write_begin(inode, pos, bytes,
291+
AOP_FLAG_NOFS | AOP_FLAG_UNINTERRUPTIBLE,
292+
&page, iomap);
293+
put_page(rpage);
294+
if (unlikely(status))
295+
return status;
296+
297+
WARN_ON_ONCE(!PageUptodate(page));
298+
299+
status = iomap_write_end(inode, pos, bytes, bytes, page);
300+
if (unlikely(status <= 0)) {
301+
if (WARN_ON_ONCE(status == 0))
302+
return -EIO;
303+
return status;
304+
}
305+
306+
cond_resched();
307+
308+
pos += status;
309+
written += status;
310+
length -= status;
311+
312+
balance_dirty_pages_ratelimited(inode->i_mapping);
313+
} while (length);
314+
315+
return written;
316+
}
317+
318+
int
319+
iomap_file_dirty(struct inode *inode, loff_t pos, loff_t len,
320+
struct iomap_ops *ops)
321+
{
322+
loff_t ret;
323+
324+
while (len) {
325+
ret = iomap_apply(inode, pos, len, IOMAP_WRITE, ops, NULL,
326+
iomap_dirty_actor);
327+
if (ret <= 0)
328+
return ret;
329+
pos += ret;
330+
len -= ret;
331+
}
332+
333+
return 0;
334+
}
335+
EXPORT_SYMBOL_GPL(iomap_file_dirty);
336+
255337
static int iomap_zero(struct inode *inode, loff_t pos, unsigned offset,
256338
unsigned bytes, struct iomap *iomap)
257339
{

include/linux/iomap.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ struct iomap_ops {
6464

6565
ssize_t iomap_file_buffered_write(struct kiocb *iocb, struct iov_iter *from,
6666
struct iomap_ops *ops);
67+
int iomap_file_dirty(struct inode *inode, loff_t pos, loff_t len,
68+
struct iomap_ops *ops);
6769
int iomap_zero_range(struct inode *inode, loff_t pos, loff_t len,
6870
bool *did_zero, struct iomap_ops *ops);
6971
int iomap_truncate_page(struct inode *inode, loff_t pos, bool *did_zero,

0 commit comments

Comments
 (0)