[Cluster-devel] [PATCH v7 4/5] iomap: Add a page_prepare callback
Darrick J. Wong
darrick.wong at oracle.com
Tue Apr 30 15:26:25 UTC 2019
On Tue, Apr 30, 2019 at 12:09:33AM +0200, Andreas Gruenbacher wrote:
> Move the page_done callback into a separate iomap_page_ops structure and
> add a page_prepare calback to be called before the next page is written
> to. In gfs2, we'll want to start a transaction in page_prepare and end
> it in page_done. Other filesystems that implement data journaling will
> require the same kind of mechanism.
>
> Signed-off-by: Andreas Gruenbacher <agruenba at redhat.com>
> Reviewed-by: Christoph Hellwig <hch at lst.de>
> Reviewed-by: Jan Kara <jack at suse.cz>
Looks fine, assuming you've done the appropriate QA/testing on the gfs2
side. :)
Reviewed-by: Darrick J. Wong <darrick.wong at oracle.com>
--D
> ---
> fs/gfs2/bmap.c | 15 ++++++++++-----
> fs/iomap.c | 36 ++++++++++++++++++++++++++----------
> include/linux/iomap.h | 22 +++++++++++++++++-----
> 3 files changed, 53 insertions(+), 20 deletions(-)
>
> diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c
> index 5da4ca9041c0..aa014725f84a 100644
> --- a/fs/gfs2/bmap.c
> +++ b/fs/gfs2/bmap.c
> @@ -991,15 +991,20 @@ static void gfs2_write_unlock(struct inode *inode)
> gfs2_glock_dq_uninit(&ip->i_gh);
> }
>
> -static void gfs2_iomap_journaled_page_done(struct inode *inode, loff_t pos,
> - unsigned copied, struct page *page,
> - struct iomap *iomap)
> +static void gfs2_iomap_page_done(struct inode *inode, loff_t pos,
> + unsigned copied, struct page *page,
> + struct iomap *iomap)
> {
> struct gfs2_inode *ip = GFS2_I(inode);
>
> - gfs2_page_add_databufs(ip, page, offset_in_page(pos), copied);
> + if (page)
> + gfs2_page_add_databufs(ip, page, offset_in_page(pos), copied);
> }
>
> +static const struct iomap_page_ops gfs2_iomap_page_ops = {
> + .page_done = gfs2_iomap_page_done,
> +};
> +
> static int gfs2_iomap_begin_write(struct inode *inode, loff_t pos,
> loff_t length, unsigned flags,
> struct iomap *iomap,
> @@ -1077,7 +1082,7 @@ static int gfs2_iomap_begin_write(struct inode *inode, loff_t pos,
> }
> }
> if (!gfs2_is_stuffed(ip) && gfs2_is_jdata(ip))
> - iomap->page_done = gfs2_iomap_journaled_page_done;
> + iomap->page_ops = &gfs2_iomap_page_ops;
> return 0;
>
> out_trans_end:
> diff --git a/fs/iomap.c b/fs/iomap.c
> index 62e3461704ce..a3ffc83134ee 100644
> --- a/fs/iomap.c
> +++ b/fs/iomap.c
> @@ -665,6 +665,7 @@ static int
> iomap_write_begin(struct inode *inode, loff_t pos, unsigned len, unsigned flags,
> struct page **pagep, struct iomap *iomap)
> {
> + const struct iomap_page_ops *page_ops = iomap->page_ops;
> pgoff_t index = pos >> PAGE_SHIFT;
> struct page *page;
> int status = 0;
> @@ -674,9 +675,17 @@ iomap_write_begin(struct inode *inode, loff_t pos, unsigned len, unsigned flags,
> if (fatal_signal_pending(current))
> return -EINTR;
>
> + if (page_ops && page_ops->page_prepare) {
> + status = page_ops->page_prepare(inode, pos, len, iomap);
> + if (status)
> + return status;
> + }
> +
> page = grab_cache_page_write_begin(inode->i_mapping, index, flags);
> - if (!page)
> - return -ENOMEM;
> + if (!page) {
> + status = -ENOMEM;
> + goto out_no_page;
> + }
>
> if (iomap->type == IOMAP_INLINE)
> iomap_read_inline_data(inode, page, iomap);
> @@ -684,15 +693,21 @@ iomap_write_begin(struct inode *inode, loff_t pos, unsigned len, unsigned flags,
> status = __block_write_begin_int(page, pos, len, NULL, iomap);
> else
> status = __iomap_write_begin(inode, pos, len, page, iomap);
> - if (unlikely(status)) {
> - unlock_page(page);
> - put_page(page);
> - page = NULL;
>
> - iomap_write_failed(inode, pos, len);
> - }
> + if (unlikely(status))
> + goto out_unlock;
>
> *pagep = page;
> + return 0;
> +
> +out_unlock:
> + unlock_page(page);
> + put_page(page);
> + iomap_write_failed(inode, pos, len);
> +
> +out_no_page:
> + if (page_ops && page_ops->page_done)
> + page_ops->page_done(inode, pos, 0, NULL, iomap);
> return status;
> }
>
> @@ -766,6 +781,7 @@ static int
> iomap_write_end(struct inode *inode, loff_t pos, unsigned len,
> unsigned copied, struct page *page, struct iomap *iomap)
> {
> + const struct iomap_page_ops *page_ops = iomap->page_ops;
> int ret;
>
> if (iomap->type == IOMAP_INLINE) {
> @@ -778,8 +794,8 @@ iomap_write_end(struct inode *inode, loff_t pos, unsigned len,
> }
>
> __generic_write_end(inode, pos, ret, page);
> - if (iomap->page_done)
> - iomap->page_done(inode, pos, copied, page, iomap);
> + if (page_ops && page_ops->page_done)
> + page_ops->page_done(inode, pos, copied, page, iomap);
> put_page(page);
>
> if (ret < len)
> diff --git a/include/linux/iomap.h b/include/linux/iomap.h
> index 0fefb5455bda..2103b94cb1bf 100644
> --- a/include/linux/iomap.h
> +++ b/include/linux/iomap.h
> @@ -53,6 +53,8 @@ struct vm_fault;
> */
> #define IOMAP_NULL_ADDR -1ULL /* addr is not valid */
>
> +struct iomap_page_ops;
> +
> struct iomap {
> u64 addr; /* disk offset of mapping, bytes */
> loff_t offset; /* file offset of mapping, bytes */
> @@ -63,12 +65,22 @@ struct iomap {
> struct dax_device *dax_dev; /* dax_dev for dax operations */
> void *inline_data;
> void *private; /* filesystem private */
> + const struct iomap_page_ops *page_ops;
> +};
>
> - /*
> - * Called when finished processing a page in the mapping returned in
> - * this iomap. At least for now this is only supported in the buffered
> - * write path.
> - */
> +/*
> + * When a filesystem sets page_ops in an iomap mapping it returns, page_prepare
> + * and page_done will be called for each page written to. This only applies to
> + * buffered writes as unbuffered writes will not typically have pages
> + * associated with them.
> + *
> + * When page_prepare succeeds, page_done will always be called to do any
> + * cleanup work necessary. In that page_done call, @page will be NULL if the
> + * associated page could not be obtained.
> + */
> +struct iomap_page_ops {
> + int (*page_prepare)(struct inode *inode, loff_t pos, unsigned len,
> + struct iomap *iomap);
> void (*page_done)(struct inode *inode, loff_t pos, unsigned copied,
> struct page *page, struct iomap *iomap);
> };
> --
> 2.20.1
>
More information about the Cluster-devel
mailing list