Merge branch 'for-linus-4.4' of git://git.kernel.org/pub/scm/linux/kernel/git/mason...
[firefly-linux-kernel-4.4.55.git] / fs / btrfs / file.c
index e6df6f1b13dd313afbe75f03b7b9ddbd75b0f6ea..6bd5ce9d75f0ab8eaca5a2f808bfaf5a66132742 100644 (file)
@@ -2493,6 +2493,19 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len)
        }
 
        trans->block_rsv = &root->fs_info->trans_block_rsv;
+       /*
+        * If we are using the NO_HOLES feature we might have had already an
+        * hole that overlaps a part of the region [lockstart, lockend] and
+        * ends at (or beyond) lockend. Since we have no file extent items to
+        * represent holes, drop_end can be less than lockend and so we must
+        * make sure we have an extent map representing the existing hole (the
+        * call to __btrfs_drop_extents() might have dropped the existing extent
+        * map representing the existing hole), otherwise the fast fsync path
+        * will not record the existence of the hole region
+        * [existing_hole_start, lockend].
+        */
+       if (drop_end <= lockend)
+               drop_end = lockend + 1;
        /*
         * Don't insert file hole extent item if it's for a range beyond eof
         * (because it's useless) or if it represents a 0 bytes range (when
@@ -2642,7 +2655,7 @@ static long btrfs_fallocate(struct file *file, int mode,
                                        alloc_start);
                if (ret)
                        goto out;
-       } else {
+       } else if (offset + len > inode->i_size) {
                /*
                 * If we are fallocating from the end of the file onward we
                 * need to zero out the end of the page if i_size lands in the