]> Git Repo - linux.git/blobdiff - fs/ext4/file.c
Merge tag 'ext4_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso...
[linux.git] / fs / ext4 / file.c
index 5332dd3ea7e22d7c9fcb52a6bf158979c03c7da0..816dedcbd541e025432ee5606bea242512397169 100644 (file)
@@ -371,15 +371,32 @@ truncate:
 static int ext4_dio_write_end_io(struct kiocb *iocb, ssize_t size,
                                 int error, unsigned int flags)
 {
-       loff_t offset = iocb->ki_pos;
+       loff_t pos = iocb->ki_pos;
        struct inode *inode = file_inode(iocb->ki_filp);
 
        if (error)
                return error;
 
-       if (size && flags & IOMAP_DIO_UNWRITTEN)
-               return ext4_convert_unwritten_extents(NULL, inode,
-                                                     offset, size);
+       if (size && flags & IOMAP_DIO_UNWRITTEN) {
+               error = ext4_convert_unwritten_extents(NULL, inode, pos, size);
+               if (error < 0)
+                       return error;
+       }
+       /*
+        * If we are extending the file, we have to update i_size here before
+        * page cache gets invalidated in iomap_dio_rw(). Otherwise racing
+        * buffered reads could zero out too much from page cache pages. Update
+        * of on-disk size will happen later in ext4_dio_write_iter() where
+        * we have enough information to also perform orphan list handling etc.
+        * Note that we perform all extending writes synchronously under
+        * i_rwsem held exclusively so i_size update is safe here in that case.
+        * If the write was not extending, we cannot see pos > i_size here
+        * because operations reducing i_size like truncate wait for all
+        * outstanding DIO before updating i_size.
+        */
+       pos += size;
+       if (pos > i_size_read(inode))
+               i_size_write(inode, pos);
 
        return 0;
 }
This page took 0.029703 seconds and 4 git commands to generate.