[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