aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@lst.de>2016-09-18 20:12:45 -0400
committerDave Chinner <david@fromorbit.com>2016-09-18 20:12:45 -0400
commit5f4e5752a8a3a72c79514def2ad9fc7cd410ce2e (patch)
tree943edac57e87caabeaece086af13c8a0c6cef60f
parentea78d80866ce375defb2fdd1c8a3aafec95e0f85 (diff)
fs: add iomap_file_dirty
Originally-From: Christoph Hellwig <hch@lst.de> 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 <hch@lst.de> Reviewed-by: Dave Chinner <dchinner@redhat.com> Signed-off-by: Dave Chinner <david@fromorbit.com>
-rw-r--r--fs/iomap.c82
-rw-r--r--include/linux/iomap.h2
2 files changed, 84 insertions, 0 deletions
diff --git a/fs/iomap.c b/fs/iomap.c
index 706270f21b35..e9b3f991c2d8 100644
--- a/fs/iomap.c
+++ b/fs/iomap.c
@@ -252,6 +252,88 @@ iomap_file_buffered_write(struct kiocb *iocb, struct iov_iter *iter,
252} 252}
253EXPORT_SYMBOL_GPL(iomap_file_buffered_write); 253EXPORT_SYMBOL_GPL(iomap_file_buffered_write);
254 254
255static 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
271static loff_t
272iomap_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
318int
319iomap_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}
335EXPORT_SYMBOL_GPL(iomap_file_dirty);
336
255static int iomap_zero(struct inode *inode, loff_t pos, unsigned offset, 337static int iomap_zero(struct inode *inode, loff_t pos, unsigned offset,
256 unsigned bytes, struct iomap *iomap) 338 unsigned bytes, struct iomap *iomap)
257{ 339{
diff --git a/include/linux/iomap.h b/include/linux/iomap.h
index 3d70ece10313..3a56212a0a8d 100644
--- a/include/linux/iomap.h
+++ b/include/linux/iomap.h
@@ -64,6 +64,8 @@ struct iomap_ops {
64 64
65ssize_t iomap_file_buffered_write(struct kiocb *iocb, struct iov_iter *from, 65ssize_t iomap_file_buffered_write(struct kiocb *iocb, struct iov_iter *from,
66 struct iomap_ops *ops); 66 struct iomap_ops *ops);
67int iomap_file_dirty(struct inode *inode, loff_t pos, loff_t len,
68 struct iomap_ops *ops);
67int iomap_zero_range(struct inode *inode, loff_t pos, loff_t len, 69int iomap_zero_range(struct inode *inode, loff_t pos, loff_t len,
68 bool *did_zero, struct iomap_ops *ops); 70 bool *did_zero, struct iomap_ops *ops);
69int iomap_truncate_page(struct inode *inode, loff_t pos, bool *did_zero, 71int iomap_truncate_page(struct inode *inode, loff_t pos, bool *did_zero,