[PATCH v7] iomap: make inline data support more flexible
Andreas Gruenbacher
agruenba at redhat.com
Mon Jul 26 23:03:14 AEST 2021
On Mon, Jul 26, 2021 at 2:33 PM Matthew Wilcox <willy at infradead.org> wrote:
> On Mon, Jul 26, 2021 at 01:06:11PM +0200, Andreas Gruenbacher wrote:
> > @@ -671,11 +683,11 @@ static size_t iomap_write_end_inline(struct inode *inode, struct page *page,
> > void *addr;
> >
> > WARN_ON_ONCE(!PageUptodate(page));
> > - BUG_ON(pos + copied > PAGE_SIZE - offset_in_page(iomap->inline_data));
> > + BUG_ON(!iomap_inline_data_size_valid(iomap));
> >
> > flush_dcache_page(page);
> > addr = kmap_atomic(page);
> > - memcpy(iomap->inline_data + pos, addr + pos, copied);
> > + memcpy(iomap_inline_data(iomap, pos), addr + pos, copied);
> > kunmap_atomic(addr);
> >
> > mark_inode_dirty(inode);
>
> Only tangentially related ... why do we memcpy the data into the tail
> at write_end() time instead of at writepage() time? I see there's a
> workaround for that in gfs2's page_mkwrite():
>
> if (gfs2_is_stuffed(ip)) {
> err = gfs2_unstuff_dinode(ip);
>
> (an mmap store cannot change the size of the file, so this would be
> unnecessary)
Not sure if an additional __set_page_dirty_nobuffers is needed in that
case, but doing the writeback at writepage time should work just as
well. It's just that gfs2 did it at write time historically. The
un-inlining in gfs2_page_mkwrite() could probably also be removed.
I can give this a try, but I'll unfortunately be AFK for the next
couple of days.
> Something like this ...
>
> diff --git a/fs/iomap/buffered-io.c b/fs/iomap/buffered-io.c
> index 87ccb3438bec..3aeebe899fc5 100644
> --- a/fs/iomap/buffered-io.c
> +++ b/fs/iomap/buffered-io.c
> @@ -665,9 +665,10 @@ static size_t __iomap_write_end(struct inode *inode, loff_t pos, size_t len,
> return copied;
> }
>
> -static size_t iomap_write_end_inline(struct inode *inode, struct page *page,
> - struct iomap *iomap, loff_t pos, size_t copied)
> +static int iomap_write_inline_data(struct inode *inode, struct page *page,
> + struct iomap *iomap)
> {
> + size_t size = i_size_read(inode) - page_offset(page);
You surely mean inode->i_size - iomap->offset.
> void *addr;
>
> WARN_ON_ONCE(!PageUptodate(page));
> @@ -675,11 +676,10 @@ static size_t iomap_write_end_inline(struct inode *inode, struct page *page,
>
> flush_dcache_page(page);
> addr = kmap_atomic(page);
> - memcpy(iomap->inline_data + pos, addr + pos, copied);
> + memcpy(iomap->inline_data, addr, size);
> kunmap_atomic(addr);
>
> - mark_inode_dirty(inode);
> - return copied;
> + return 0;
> }
>
> /* Returns the number of bytes copied. May be 0. Cannot be an errno. */
> @@ -691,9 +691,7 @@ static size_t iomap_write_end(struct inode *inode, loff_t pos, size_t len,
> loff_t old_size = inode->i_size;
> size_t ret;
>
> - if (srcmap->type == IOMAP_INLINE) {
> - ret = iomap_write_end_inline(inode, page, iomap, pos, copied);
> - } else if (srcmap->flags & IOMAP_F_BUFFER_HEAD) {
> + if (srcmap->flags & IOMAP_F_BUFFER_HEAD) {
> ret = block_write_end(NULL, inode->i_mapping, pos, len, copied,
> page, NULL);
> } else {
> @@ -1314,6 +1312,9 @@ iomap_writepage_map(struct iomap_writepage_ctx *wpc,
>
> WARN_ON_ONCE(iop && atomic_read(&iop->write_bytes_pending) != 0);
>
> + if (wpc->iomap.type == IOMAP_INLINE)
> + return iomap_write_inline_data(inode, page, iomap);
> +
> /*
> * Walk through the page to find areas to write back. If we run off the
> * end of the current map or find the current map invalid, grab a new
> @@ -1328,8 +1329,6 @@ iomap_writepage_map(struct iomap_writepage_ctx *wpc,
> error = wpc->ops->map_blocks(wpc, inode, file_offset);
> if (error)
> break;
> - if (WARN_ON_ONCE(wpc->iomap.type == IOMAP_INLINE))
> - continue;
> if (wpc->iomap.type == IOMAP_HOLE)
> continue;
> iomap_add_to_ioend(inode, file_offset, page, iop, wpc, wbc,
>
Thanks,
Andreas
More information about the Linux-erofs
mailing list