diff mbox

[4/6] fs: add iomap_file_dirty

Message ID 147216786712.525.5901639662288553230.stgit@birch.djwong.org (mailing list archive)
State Accepted, archived
Headers show

Commit Message

Christoph Hellwig Aug. 25, 2016, 11:31 p.m. UTC
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.

XXX: might want a bigger name, and possible a better implementation
that doesn't require two lookups in the radix tree.

Signed-off-by: Christoph Hellwig <hch@lst.de>
---
 fs/iomap.c            |   82 +++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/iomap.h |    2 +
 2 files changed, 84 insertions(+)

Comments

Christoph Hellwig Sept. 5, 2016, 2:57 p.m. UTC | #1
On Thu, Aug 25, 2016 at 04:31:07PM -0700, Christoph Hellwig wrote:
> Originally-from: Christoph Hellwig <hch@lst.de>

This should be a

From: Christoph Hellwig <hch@lst.de>

so that git picks up authorship information correctly.

> XXX: might want a bigger name, and possible a better implementation
> that doesn't require two lookups in the radix tree.

And these need to be looked into.  I can take a stab at it, but I need
to get a few other things off my plate first.
Darrick J. Wong Sept. 6, 2016, 5:34 p.m. UTC | #2
On Mon, Sep 05, 2016 at 07:57:51AM -0700, Christoph Hellwig wrote:
> On Thu, Aug 25, 2016 at 04:31:07PM -0700, Christoph Hellwig wrote:
> > Originally-from: Christoph Hellwig <hch@lst.de>
> 
> This should be a
> 
> From: Christoph Hellwig <hch@lst.de>
> 
> so that git picks up authorship information correctly.
> 
> > XXX: might want a bigger name, and possible a better implementation
> > that doesn't require two lookups in the radix tree.
> 
> And these need to be looked into.  I can take a stab at it, but I need
> to get a few other things off my plate first.

Yeah.  It works well enough for unsharing blocks, if inefficiently.

Not sure what "a bigger name" means, though.  I tried feeding the
function prototype through figlet but gcc didn't like that. ;)

--D
Christoph Hellwig Sept. 11, 2016, 12:58 p.m. UTC | #3
On Tue, Sep 06, 2016 at 10:34:28AM -0700, Darrick J. Wong wrote:
> > > XXX: might want a bigger name, and possible a better implementation
> > > that doesn't require two lookups in the radix tree.
> > 
> > And these need to be looked into.  I can take a stab at it, but I need
> > to get a few other things off my plate first.
> 
> Yeah.  It works well enough for unsharing blocks, if inefficiently.
> 
> Not sure what "a bigger name" means, though.  I tried feeding the
> function prototype through figlet but gcc didn't like that. ;)

That should have been "better", sorry.
Dave Chinner Sept. 19, 2016, 12:11 a.m. UTC | #4
On Mon, Sep 05, 2016 at 07:57:51AM -0700, Christoph Hellwig wrote:
> On Thu, Aug 25, 2016 at 04:31:07PM -0700, Christoph Hellwig wrote:
> > Originally-from: Christoph Hellwig <hch@lst.de>
> 
> This should be a
> 
> From: Christoph Hellwig <hch@lst.de>
> 
> so that git picks up authorship information correctly.
> 
> > XXX: might want a bigger name, and possible a better implementation
> > that doesn't require two lookups in the radix tree.
> 
> And these need to be looked into.  I can take a stab at it, but I need
> to get a few other things off my plate first.

Seeing as it works and isn't too ugly to live, I think I'm going to
merge this as is. When a better implementation comes along we
can replace it with that...

Cheers,

Dave.
diff mbox

Patch

diff --git a/fs/iomap.c b/fs/iomap.c
index 0342254..7b295d5 100644
--- a/fs/iomap.c
+++ b/fs/iomap.c
@@ -252,6 +252,88 @@  iomap_file_buffered_write(struct kiocb *iocb, struct iov_iter *iter,
 }
 EXPORT_SYMBOL_GPL(iomap_file_buffered_write);
 
+static struct page *
+__iomap_read_page(struct inode *inode, loff_t offset)
+{
+	struct address_space *mapping = inode->i_mapping;
+	struct page *page;
+
+	page = read_mapping_page(mapping, offset >> PAGE_SHIFT, NULL);
+	if (IS_ERR(page))
+		return page;
+	if (!PageUptodate(page)) {
+		put_page(page);
+		return ERR_PTR(-EIO);
+	}
+	return page;
+}
+
+static loff_t
+iomap_dirty_actor(struct inode *inode, loff_t pos, loff_t length, void *data,
+		struct iomap *iomap)
+{
+	long status = 0;
+	ssize_t written = 0;
+
+	do {
+		struct page *page, *rpage;
+		unsigned long offset;	/* Offset into pagecache page */
+		unsigned long bytes;	/* Bytes to write to page */
+
+		offset = (pos & (PAGE_SIZE - 1));
+		bytes = min_t(unsigned long, PAGE_SIZE - offset, length);
+
+		rpage = __iomap_read_page(inode, pos);
+		if (IS_ERR(rpage))
+			return PTR_ERR(rpage);
+
+		status = iomap_write_begin(inode, pos, bytes,
+				AOP_FLAG_NOFS | AOP_FLAG_UNINTERRUPTIBLE,
+				&page, iomap);
+		put_page(rpage);
+		if (unlikely(status))
+			return status;
+
+		WARN_ON_ONCE(!PageUptodate(page));
+
+		status = iomap_write_end(inode, pos, bytes, bytes, page);
+		if (unlikely(status <= 0)) {
+			if (WARN_ON_ONCE(status == 0))
+				return -EIO;
+			return status;
+		}
+
+		cond_resched();
+
+		pos += status;
+		written += status;
+		length -= status;
+
+		balance_dirty_pages_ratelimited(inode->i_mapping);
+	} while (length);
+
+	return written;
+}
+
+int
+iomap_file_dirty(struct inode *inode, loff_t pos, loff_t len,
+		struct iomap_ops *ops)
+{
+	loff_t ret;
+
+	while (len) {
+		ret = iomap_apply(inode, pos, len, IOMAP_WRITE, ops, NULL,
+				iomap_dirty_actor);
+		if (ret <= 0)
+			return ret;
+		pos += ret;
+		len -= ret;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(iomap_file_dirty);
+
 static int iomap_zero(struct inode *inode, loff_t pos, unsigned offset,
 		unsigned bytes, struct iomap *iomap)
 {
diff --git a/include/linux/iomap.h b/include/linux/iomap.h
index 3267df4..b2e30e5 100644
--- a/include/linux/iomap.h
+++ b/include/linux/iomap.h
@@ -58,6 +58,8 @@  struct iomap_ops {
 
 ssize_t iomap_file_buffered_write(struct kiocb *iocb, struct iov_iter *from,
 		struct iomap_ops *ops);
+int iomap_file_dirty(struct inode *inode, loff_t pos, loff_t len,
+		struct iomap_ops *ops);
 int iomap_zero_range(struct inode *inode, loff_t pos, loff_t len,
 		bool *did_zero, struct iomap_ops *ops);
 int iomap_truncate_page(struct inode *inode, loff_t pos, bool *did_zero,