btrfs: add cancellation points to defrag
authorDavid Sterba <dsterba@suse.cz>
Sat, 9 Feb 2013 23:38:06 +0000 (23:38 +0000)
committerJosef Bacik <jbacik@fusionio.com>
Wed, 20 Feb 2013 17:59:51 +0000 (12:59 -0500)
The defrag operation can take very long, we want to have a way how to
cancel it. The code checks for a pending signal at safe points in the
defrag loops and returns EAGAIN. This means a user can press ^C after
running 'btrfs fi defrag', woks for both defrag modes, files and root.

Returning from the command was instant in my light tests, but may take
longer depending on the aging factor of the filesystem.

Signed-off-by: David Sterba <dsterba@suse.cz>
Signed-off-by: Josef Bacik <jbacik@fusionio.com>
fs/btrfs/ctree.h
fs/btrfs/ioctl.c
fs/btrfs/transaction.c

index f1cc247f31786588c17ee8defa3a03436776b3df..14f01dc70ea63d7d62ddb5bbec6444662f9a02b9 100644 (file)
@@ -3786,4 +3786,11 @@ static inline int is_fstree(u64 rootid)
                return 1;
        return 0;
 }
+
+static inline int btrfs_defrag_cancelled(struct btrfs_fs_info *fs_info)
+{
+       return signal_pending(current);
+}
+
+
 #endif
index 6d6314406e2722813825562fc9c5f636c81159b1..d02ec577f70f53ec461518a9a186400504c27026 100644 (file)
@@ -1202,6 +1202,12 @@ int btrfs_defrag_file(struct inode *inode, struct file *file,
                if (!(inode->i_sb->s_flags & MS_ACTIVE))
                        break;
 
+               if (btrfs_defrag_cancelled(root->fs_info)) {
+                       printk(KERN_DEBUG "btrfs: defrag_file cancelled\n");
+                       ret = -EAGAIN;
+                       break;
+               }
+
                if (!should_defrag_range(inode, (u64)i << PAGE_CACHE_SHIFT,
                                         extent_thresh, &last_len, &skip,
                                         &defrag_end, range->flags &
index 60481a53e004cb0e47a8aa74bc0a07c90adb80af..d574d830a1c4b8ee9d19c67716006bcf0ddd88f8 100644 (file)
@@ -984,6 +984,12 @@ int btrfs_defrag_root(struct btrfs_root *root)
 
                if (btrfs_fs_closing(root->fs_info) || ret != -EAGAIN)
                        break;
+
+               if (btrfs_defrag_cancelled(root->fs_info)) {
+                       printk(KERN_DEBUG "btrfs: defrag_root cancelled\n");
+                       ret = -EAGAIN;
+                       break;
+               }
        }
        root->defrag_running = 0;
        return ret;