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)

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);
        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,

Reply via email to