Btrfs: fix remount vs autodefrag
authorMiao Xie <miaox@cn.fujitsu.com>
Thu, 21 Feb 2013 06:32:52 +0000 (23:32 -0700)
committerChris Mason <chris.mason@fusionio.com>
Thu, 21 Feb 2013 13:11:43 +0000 (08:11 -0500)
If we remount the fs to close the auto defragment or make the fs R/O,
we should stop the auto defragment.

Signed-off-by: Miao Xie <miaox@cn.fujitsu.com>
Signed-off-by: Chris Mason <chris.mason@fusionio.com>
fs/btrfs/ctree.h
fs/btrfs/file.c
fs/btrfs/super.c

index 3dcedfe4f75945dbc616c4802ffb0f962d1cea0c..ae8dcc406805958ca84f5bd67934b2a21bcf8fd0 100644 (file)
@@ -339,6 +339,7 @@ static inline unsigned long btrfs_chunk_item_size(int num_stripes)
  * File system states
  */
 #define BTRFS_FS_STATE_ERROR           0
+#define BTRFS_FS_STATE_REMOUNTING      1
 
 /* Super block flags */
 /* Errors detected */
@@ -1902,6 +1903,7 @@ struct btrfs_ioctl_defrag_range_args {
 
 #define btrfs_clear_opt(o, opt)                ((o) &= ~BTRFS_MOUNT_##opt)
 #define btrfs_set_opt(o, opt)          ((o) |= BTRFS_MOUNT_##opt)
+#define btrfs_raw_test_opt(o, opt)     ((o) & BTRFS_MOUNT_##opt)
 #define btrfs_test_opt(root, opt)      ((root)->fs_info->mount_opt & \
                                         BTRFS_MOUNT_##opt)
 /*
index 9f67e623206d90c7ef279a6291b116f5211007b4..6e6dd8cdad92201c661dedb9bdbcfe749749ed9e 100644 (file)
@@ -374,6 +374,11 @@ int btrfs_run_defrag_inodes(struct btrfs_fs_info *fs_info)
 
        atomic_inc(&fs_info->defrag_running);
        while(1) {
+               /* Pause the auto defragger. */
+               if (test_bit(BTRFS_FS_STATE_REMOUNTING,
+                            &fs_info->fs_state))
+                       break;
+
                if (!__need_auto_defrag(fs_info->tree_root))
                        break;
 
index db1ba9a2ed64b0336649449d4292012b5406bf68..68a29a1ea0688b868a0b33b8298b38159be5ec80 100644 (file)
@@ -1202,6 +1202,38 @@ static void btrfs_resize_thread_pool(struct btrfs_fs_info *fs_info,
                              new_pool_size);
 }
 
+static inline void btrfs_remount_prepare(struct btrfs_fs_info *fs_info,
+                                        unsigned long old_opts, int flags)
+{
+       set_bit(BTRFS_FS_STATE_REMOUNTING, &fs_info->fs_state);
+
+       if (btrfs_raw_test_opt(old_opts, AUTO_DEFRAG) &&
+           (!btrfs_raw_test_opt(fs_info->mount_opt, AUTO_DEFRAG) ||
+            (flags & MS_RDONLY))) {
+               /* wait for any defraggers to finish */
+               wait_event(fs_info->transaction_wait,
+                          (atomic_read(&fs_info->defrag_running) == 0));
+               if (flags & MS_RDONLY)
+                       sync_filesystem(fs_info->sb);
+       }
+}
+
+static inline void btrfs_remount_cleanup(struct btrfs_fs_info *fs_info,
+                                        unsigned long old_opts)
+{
+       /*
+        * We need cleanup all defragable inodes if the autodefragment is
+        * close or the fs is R/O.
+        */
+       if (btrfs_raw_test_opt(old_opts, AUTO_DEFRAG) &&
+           (!btrfs_raw_test_opt(fs_info->mount_opt, AUTO_DEFRAG) ||
+            (fs_info->sb->s_flags & MS_RDONLY))) {
+               btrfs_cleanup_defrag_inodes(fs_info);
+       }
+
+       clear_bit(BTRFS_FS_STATE_REMOUNTING, &fs_info->fs_state);
+}
+
 static int btrfs_remount(struct super_block *sb, int *flags, char *data)
 {
        struct btrfs_fs_info *fs_info = btrfs_sb(sb);
@@ -1215,6 +1247,8 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data)
        unsigned int old_metadata_ratio = fs_info->metadata_ratio;
        int ret;
 
+       btrfs_remount_prepare(fs_info, old_opts, *flags);
+
        ret = btrfs_parse_options(root, data);
        if (ret) {
                ret = -EINVAL;
@@ -1225,7 +1259,7 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data)
                fs_info->thread_pool_size, old_thread_pool_size);
 
        if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY))
-               return 0;
+               goto out;
 
        if (*flags & MS_RDONLY) {
                /*
@@ -1280,7 +1314,8 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data)
                }
                sb->s_flags &= ~MS_RDONLY;
        }
-
+out:
+       btrfs_remount_cleanup(fs_info, old_opts);
        return 0;
 
 restore:
@@ -1297,6 +1332,7 @@ restore:
        btrfs_resize_thread_pool(fs_info,
                old_thread_pool_size, fs_info->thread_pool_size);
        fs_info->metadata_ratio = old_metadata_ratio;
+       btrfs_remount_cleanup(fs_info, old_opts);
        return ret;
 }