From patchwork Mon Jan 29 22:18:42 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andreas Gruenbacher X-Patchwork-Id: 10191003 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 0C16260212 for ; Mon, 29 Jan 2018 22:19:03 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id E1B7028613 for ; Mon, 29 Jan 2018 22:19:02 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id D68CC2891D; Mon, 29 Jan 2018 22:19:02 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id B6A7928613 for ; Mon, 29 Jan 2018 22:19:01 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751837AbeA2WTA (ORCPT ); Mon, 29 Jan 2018 17:19:00 -0500 Received: from mx1.redhat.com ([209.132.183.28]:58960 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751666AbeA2WS7 (ORCPT ); Mon, 29 Jan 2018 17:18:59 -0500 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 6A2C068A9; Mon, 29 Jan 2018 22:18:59 +0000 (UTC) Received: from max.home.com (ovpn-116-127.ams2.redhat.com [10.36.116.127]) by smtp.corp.redhat.com (Postfix) with ESMTP id 2AE7B18AC9; Mon, 29 Jan 2018 22:18:57 +0000 (UTC) From: Andreas Gruenbacher To: cluster-devel@redhat.com Cc: Christoph Hellwig , Dave Chinner , linux-fsdevel@vger.kernel.org, Andreas Gruenbacher Subject: [PATCH v2 4/6] iomap: Add write_{begin,end} iomap operations Date: Mon, 29 Jan 2018 23:18:42 +0100 Message-Id: <20180129221844.19476-5-agruenba@redhat.com> In-Reply-To: <20180129221844.19476-1-agruenba@redhat.com> References: <20180129221844.19476-1-agruenba@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.39]); Mon, 29 Jan 2018 22:18:59 +0000 (UTC) Sender: linux-fsdevel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Add write_begin and write_end operations to struct iomap_ops to provide a way of overriding the default behavior of iomap_write_begin and iomap_write_end. This is needed for implementing data journaling: in the data journaling case, pages are written into the journal before being written back to their proper on-disk locations. Signed-off-by: Andreas Gruenbacher Cc: Dave Chinner --- fs/ext2/inode.c | 2 ++ fs/ext4/inode.c | 2 ++ fs/iomap.c | 62 +++++++++++++++++++++++++++++++++++---------------- fs/xfs/xfs_iomap.c | 2 ++ include/linux/iomap.h | 22 ++++++++++++++++++ 5 files changed, 71 insertions(+), 19 deletions(-) diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index 9b2ac55ac34f..9b8ea6108b30 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c @@ -848,6 +848,8 @@ ext2_iomap_end(struct inode *inode, loff_t offset, loff_t length, const struct iomap_ops ext2_iomap_ops = { .iomap_begin = ext2_iomap_begin, + .write_begin = iomap_write_begin, + .write_end = iomap_write_end, .iomap_end = ext2_iomap_end, }; #else diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 534a9130f625..76f4ad697853 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -3601,6 +3601,8 @@ static int ext4_iomap_end(struct inode *inode, loff_t offset, loff_t length, const struct iomap_ops ext4_iomap_ops = { .iomap_begin = ext4_iomap_begin, + .write_begin = iomap_write_begin, + .write_end = iomap_write_end, .iomap_end = ext4_iomap_end, }; diff --git a/fs/iomap.c b/fs/iomap.c index 47d29ccffaef..2e5866ea4522 100644 --- a/fs/iomap.c +++ b/fs/iomap.c @@ -106,7 +106,7 @@ iomap_write_failed(struct inode *inode, loff_t pos, unsigned len) truncate_pagecache_range(inode, max(pos, i_size), pos + len); } -static int +int iomap_write_begin(struct inode *inode, loff_t pos, unsigned len, unsigned flags, struct page **pagep, struct iomap *iomap) { @@ -135,8 +135,9 @@ iomap_write_begin(struct inode *inode, loff_t pos, unsigned len, unsigned flags, *pagep = page; return status; } +EXPORT_SYMBOL_GPL(iomap_write_begin); -static int +int iomap_write_end(struct inode *inode, loff_t pos, unsigned len, unsigned copied, struct page *page) { @@ -148,12 +149,19 @@ iomap_write_end(struct inode *inode, loff_t pos, unsigned len, iomap_write_failed(inode, pos, len); return ret; } +EXPORT_SYMBOL_GPL(iomap_write_end); + +struct iomap_write_args { + struct iov_iter *iter; + const struct iomap_ops *ops; +}; static loff_t iomap_write_actor(struct inode *inode, loff_t pos, loff_t length, void *data, struct iomap *iomap) { - struct iov_iter *i = data; + struct iomap_write_args *args = data; + struct iov_iter *i = args->iter; long status = 0; ssize_t written = 0; unsigned int flags = AOP_FLAG_NOFS; @@ -186,7 +194,7 @@ iomap_write_actor(struct inode *inode, loff_t pos, loff_t length, void *data, break; } - status = iomap_write_begin(inode, pos, bytes, flags, &page, + status = args->ops->write_begin(inode, pos, bytes, flags, &page, iomap); if (unlikely(status)) break; @@ -198,7 +206,7 @@ iomap_write_actor(struct inode *inode, loff_t pos, loff_t length, void *data, flush_dcache_page(page); - status = iomap_write_end(inode, pos, bytes, copied, page); + status =args->ops->write_end(inode, pos, bytes, copied, page); if (unlikely(status < 0)) break; copied = status; @@ -235,10 +243,14 @@ iomap_file_buffered_write(struct kiocb *iocb, struct iov_iter *iter, { struct inode *inode = iocb->ki_filp->f_mapping->host; loff_t pos = iocb->ki_pos, ret = 0, written = 0; + struct iomap_write_args args = { + .iter = iter, + .ops = ops, + }; while (iov_iter_count(iter)) { ret = iomap_apply(inode, pos, iov_iter_count(iter), - IOMAP_WRITE, ops, iter, iomap_write_actor); + IOMAP_WRITE, ops, &args, iomap_write_actor); if (ret <= 0) break; pos += ret; @@ -269,6 +281,7 @@ static loff_t iomap_dirty_actor(struct inode *inode, loff_t pos, loff_t length, void *data, struct iomap *iomap) { + const struct iomap_ops *ops = data; long status = 0; ssize_t written = 0; @@ -284,15 +297,15 @@ iomap_dirty_actor(struct inode *inode, loff_t pos, loff_t length, void *data, if (IS_ERR(rpage)) return PTR_ERR(rpage); - status = iomap_write_begin(inode, pos, bytes, - AOP_FLAG_NOFS, &page, iomap); + status = ops->write_begin(inode, pos, bytes, + AOP_FLAG_NOFS, &page, iomap); put_page(rpage); if (unlikely(status)) return status; WARN_ON_ONCE(!PageUptodate(page)); - status = iomap_write_end(inode, pos, bytes, bytes, page); + status = ops->write_end(inode, pos, bytes, bytes, page); if (unlikely(status <= 0)) { if (WARN_ON_ONCE(status == 0)) return -EIO; @@ -318,7 +331,7 @@ iomap_file_dirty(struct inode *inode, loff_t pos, loff_t len, loff_t ret; while (len) { - ret = iomap_apply(inode, pos, len, IOMAP_WRITE, ops, NULL, + ret = iomap_apply(inode, pos, len, IOMAP_WRITE, ops, (void *)ops, iomap_dirty_actor); if (ret <= 0) return ret; @@ -331,20 +344,21 @@ iomap_file_dirty(struct inode *inode, loff_t pos, loff_t len, EXPORT_SYMBOL_GPL(iomap_file_dirty); static int iomap_zero(struct inode *inode, loff_t pos, unsigned offset, - unsigned bytes, struct iomap *iomap) + unsigned bytes, const struct iomap_ops *ops, + struct iomap *iomap) { struct page *page; int status; - status = iomap_write_begin(inode, pos, bytes, AOP_FLAG_NOFS, &page, - iomap); + status = ops->write_begin(inode, pos, bytes, AOP_FLAG_NOFS, &page, + iomap); if (status) return status; zero_user(page, offset, bytes); mark_page_accessed(page); - return iomap_write_end(inode, pos, bytes, bytes, page); + return ops->write_end(inode, pos, bytes, bytes, page); } static int iomap_dax_zero(loff_t pos, unsigned offset, unsigned bytes, @@ -357,11 +371,16 @@ static int iomap_dax_zero(loff_t pos, unsigned offset, unsigned bytes, offset, bytes); } +struct iomap_zero_range_args { + const struct iomap_ops *ops; + bool *did_zero; +}; + static loff_t iomap_zero_range_actor(struct inode *inode, loff_t pos, loff_t count, void *data, struct iomap *iomap) { - bool *did_zero = data; + struct iomap_zero_range_args *args = data; loff_t written = 0; int status; @@ -378,15 +397,16 @@ iomap_zero_range_actor(struct inode *inode, loff_t pos, loff_t count, if (IS_DAX(inode)) status = iomap_dax_zero(pos, offset, bytes, iomap); else - status = iomap_zero(inode, pos, offset, bytes, iomap); + status = iomap_zero(inode, pos, offset, bytes, + (void *)args->ops, iomap); if (status < 0) return status; pos += bytes; count -= bytes; written += bytes; - if (did_zero) - *did_zero = true; + if (args->did_zero) + *args->did_zero = true; } while (count > 0); return written; @@ -396,11 +416,15 @@ int iomap_zero_range(struct inode *inode, loff_t pos, loff_t len, bool *did_zero, const struct iomap_ops *ops) { + struct iomap_zero_range_args args = { + .ops = ops, + .did_zero = did_zero, + }; loff_t ret; while (len > 0) { ret = iomap_apply(inode, pos, len, IOMAP_ZERO, - ops, did_zero, iomap_zero_range_actor); + ops, &args, iomap_zero_range_actor); if (ret <= 0) return ret; diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c index 7ab52a8bc0a9..a53e3ab229df 100644 --- a/fs/xfs/xfs_iomap.c +++ b/fs/xfs/xfs_iomap.c @@ -1181,6 +1181,8 @@ xfs_file_iomap_end( const struct iomap_ops xfs_iomap_ops = { .iomap_begin = xfs_file_iomap_begin, + .write_begin = iomap_write_begin, + .write_end = iomap_write_end, .iomap_end = xfs_file_iomap_end, }; diff --git a/include/linux/iomap.h b/include/linux/iomap.h index 19a07de28212..423f7ecc1231 100644 --- a/include/linux/iomap.h +++ b/include/linux/iomap.h @@ -61,6 +61,8 @@ struct iomap { #define IOMAP_DIRECT (1 << 4) /* direct I/O */ #define IOMAP_NOWAIT (1 << 5) /* Don't wait for writeback */ +struct page; + struct iomap_ops { /* * Return the existing mapping at pos, or reserve space starting at @@ -70,6 +72,21 @@ struct iomap_ops { int (*iomap_begin)(struct inode *inode, loff_t pos, loff_t length, unsigned flags, struct iomap *iomap); + /* + * Begin writing to a page, similar to block_write_begin but in a + * mapping returned by iomap_begin. Usually initialized to + * iomap_write_begin. + */ + int (*write_begin)(struct inode *inode, loff_t pos, unsigned len, + unsigned flags, struct page **pagep, + struct iomap *iomap); + + /* + * End writing to a page. Usually initialized to iomap_write_end. + */ + int (*write_end)(struct inode *inode, loff_t pos, unsigned len, + unsigned copied, struct page *page); + /* * Commit and/or unreserve space previous allocated using iomap_begin. * Written indicates the length of the successful write operation which @@ -80,6 +97,11 @@ struct iomap_ops { ssize_t written, unsigned flags, struct iomap *iomap); }; +int iomap_write_begin(struct inode *inode, loff_t pos, unsigned len, + unsigned flags, struct page **pagep, struct iomap *iomap); +int iomap_write_end(struct inode *inode, loff_t pos, unsigned len, + unsigned copied, struct page *page); + ssize_t iomap_file_buffered_write(struct kiocb *iocb, struct iov_iter *from, const struct iomap_ops *ops); int iomap_file_dirty(struct inode *inode, loff_t pos, loff_t len,