Merge tag 'iomap-5.3-merge-1' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 11 Jul 2019 03:29:45 +0000 (20:29 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 11 Jul 2019 03:29:45 +0000 (20:29 -0700)
Pull iomap updates from Darrick Wong:
 "There are a few fixes for gfs2 but otherwise it's pretty quiet so far.

   - Only mark inode dirty at the end of writing to a file (instead of
     once for every page written).

   - Fix for an accounting error in the page_done callback"

* tag 'iomap-5.3-merge-1' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux:
  iomap: fix page_done callback for short writes
  fs: fold __generic_write_end back into generic_write_end
  iomap: don't mark the inode dirty in iomap_write_end

fs/buffer.c
fs/gfs2/bmap.c
fs/internal.h
fs/iomap.c
include/linux/iomap.h

index e450c55f643424efcc4e992d9012378fcd602421..49a8715700926ecf2e75446eb0c6debd65615d43 100644 (file)
@@ -2086,38 +2086,6 @@ int block_write_begin(struct address_space *mapping, loff_t pos, unsigned len,
 }
 EXPORT_SYMBOL(block_write_begin);
 
-void __generic_write_end(struct inode *inode, loff_t pos, unsigned copied,
-               struct page *page)
-{
-       loff_t old_size = inode->i_size;
-       bool i_size_changed = false;
-
-       /*
-        * No need to use i_size_read() here, the i_size cannot change under us
-        * because we hold i_rwsem.
-        *
-        * But it's important to update i_size while still holding page lock:
-        * page writeout could otherwise come in and zero beyond i_size.
-        */
-       if (pos + copied > inode->i_size) {
-               i_size_write(inode, pos + copied);
-               i_size_changed = true;
-       }
-
-       unlock_page(page);
-
-       if (old_size < pos)
-               pagecache_isize_extended(inode, old_size, pos);
-       /*
-        * Don't mark the inode dirty under page lock. First, it unnecessarily
-        * makes the holding time of page lock longer. Second, it forces lock
-        * ordering of page lock and transaction start for journaling
-        * filesystems.
-        */
-       if (i_size_changed)
-               mark_inode_dirty(inode);
-}
-
 int block_write_end(struct file *file, struct address_space *mapping,
                        loff_t pos, unsigned len, unsigned copied,
                        struct page *page, void *fsdata)
@@ -2158,9 +2126,37 @@ int generic_write_end(struct file *file, struct address_space *mapping,
                        loff_t pos, unsigned len, unsigned copied,
                        struct page *page, void *fsdata)
 {
+       struct inode *inode = mapping->host;
+       loff_t old_size = inode->i_size;
+       bool i_size_changed = false;
+
        copied = block_write_end(file, mapping, pos, len, copied, page, fsdata);
-       __generic_write_end(mapping->host, pos, copied, page);
+
+       /*
+        * No need to use i_size_read() here, the i_size cannot change under us
+        * because we hold i_rwsem.
+        *
+        * But it's important to update i_size while still holding page lock:
+        * page writeout could otherwise come in and zero beyond i_size.
+        */
+       if (pos + copied > inode->i_size) {
+               i_size_write(inode, pos + copied);
+               i_size_changed = true;
+       }
+
+       unlock_page(page);
        put_page(page);
+
+       if (old_size < pos)
+               pagecache_isize_extended(inode, old_size, pos);
+       /*
+        * Don't mark the inode dirty under page lock. First, it unnecessarily
+        * makes the holding time of page lock longer. Second, it forces lock
+        * ordering of page lock and transaction start for journaling
+        * filesystems.
+        */
+       if (i_size_changed)
+               mark_inode_dirty(inode);
        return copied;
 }
 EXPORT_SYMBOL(generic_write_end);
index 93ea1d529aa398e68937f3d10fd84b7d2ff7fbdc..f4b895fc632d6cf15a5807e480027ba7549b4667 100644 (file)
@@ -1182,6 +1182,8 @@ static int gfs2_iomap_end(struct inode *inode, loff_t pos, loff_t length,
 
        if (ip->i_qadata && ip->i_qadata->qa_qd_num)
                gfs2_quota_unlock(ip);
+       if (iomap->flags & IOMAP_F_SIZE_CHANGED)
+               mark_inode_dirty(inode);
        gfs2_write_unlock(inode);
 
 out:
index a48ef81be37df123bb7e11c3374820949d4c678a..2f3c3de51fad6eebbd68c1dc349a5171bf986b56 100644 (file)
@@ -40,8 +40,6 @@ static inline int __sync_blockdev(struct block_device *bdev, int wait)
 extern void guard_bio_eod(int rw, struct bio *bio);
 extern int __block_write_begin_int(struct page *page, loff_t pos, unsigned len,
                get_block_t *get_block, struct iomap *iomap);
-void __generic_write_end(struct inode *inode, loff_t pos, unsigned copied,
-               struct page *page);
 
 /*
  * char_dev.c
index 7a147aa0c4d9a09e3015c7ba4890545879351ee0..217c3e5a13d6c435b02284c95cb67a623dd7a6a3 100644 (file)
@@ -777,6 +777,7 @@ 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;
+       loff_t old_size = inode->i_size;
        int ret;
 
        if (iomap->type == IOMAP_INLINE) {
@@ -788,9 +789,21 @@ iomap_write_end(struct inode *inode, loff_t pos, unsigned len,
                ret = __iomap_write_end(inode, pos, len, copied, page, iomap);
        }
 
-       __generic_write_end(inode, pos, ret, page);
+       /*
+        * Update the in-memory inode size after copying the data into the page
+        * cache.  It's up to the file system to write the updated size to disk,
+        * preferably after I/O completion so that no stale data is exposed.
+        */
+       if (pos + ret > old_size) {
+               i_size_write(inode, pos + ret);
+               iomap->flags |= IOMAP_F_SIZE_CHANGED;
+       }
+       unlock_page(page);
+
+       if (old_size < pos)
+               pagecache_isize_extended(inode, old_size, pos);
        if (page_ops && page_ops->page_done)
-               page_ops->page_done(inode, pos, copied, page, iomap);
+               page_ops->page_done(inode, pos, ret, page, iomap);
        put_page(page);
 
        if (ret < len)
index 2103b94cb1bff008e2b3fb47504f068181ae694a..1df9ea187a9a8c0bde4787f3ec41d6df8995043a 100644 (file)
@@ -35,6 +35,7 @@ struct vm_fault;
 #define IOMAP_F_NEW            0x01    /* blocks have been newly allocated */
 #define IOMAP_F_DIRTY          0x02    /* uncommitted metadata */
 #define IOMAP_F_BUFFER_HEAD    0x04    /* file system requires buffer heads */
+#define IOMAP_F_SIZE_CHANGED   0x08    /* file size has changed */
 
 /*
  * Flags that only need to be reported for IOMAP_REPORT requests: