Btrfs: make sure not to defrag extents past i_size
authorChris Mason <chris.mason@oracle.com>
Tue, 11 Oct 2011 15:41:40 +0000 (11:41 -0400)
committerChris Mason <chris.mason@oracle.com>
Tue, 11 Oct 2011 15:45:55 +0000 (11:45 -0400)
The btrfs file defrag code will loop through the extents and
force COW on them.  But there is a concurrent truncate in the middle of
the defrag, it might end up defragging the same range over and over
again.

The problem is that writepage won't go through and do anything on pages
past i_size, so the cow won't happen, so the file will appear to still
be fragmented.  defrag will end up hitting the same extents again and
again.

In the worst case, the truncate can actually live lock with the defrag
because the defrag keeps creating new ordered extents which the truncate
code keeps waiting on.

The fix here is to make defrag check for i_size inside the main loop,
instead of just once before the looping starts.

Signed-off-by: Chris Mason <chris.mason@oracle.com>
fs/btrfs/ioctl.c

index df40b7c5f06bec231a83e63710a4011d1cbd63d0..efc4e4a85a6988b69bdf7094feacfb00a6ebac11 100644 (file)
@@ -1062,7 +1062,9 @@ int btrfs_defrag_file(struct inode *inode, struct file *file,
        if (i < inode->i_mapping->writeback_index)
                inode->i_mapping->writeback_index = i;
 
-       while (i <= last_index && defrag_count < max_to_defrag) {
+       while (i <= last_index && defrag_count < max_to_defrag &&
+              (i < (i_size_read(inode) + PAGE_CACHE_SIZE - 1) >>
+               PAGE_CACHE_SHIFT)) {
                /*
                 * make sure we stop running if someone unmounts
                 * the FS