Btrfs: use bit operation for ->fs_state
[linux-2.6-block.git] / fs / btrfs / super.c
index 915ac14c20642ec619ec159d90d0fbed2a02b0da..4152f9ea34f5484c00f7f62b2acbbee9861ac4c6 100644 (file)
 #include <linux/slab.h>
 #include <linux/cleancache.h>
 #include <linux/ratelimit.h>
+#include <linux/btrfs.h>
 #include "compat.h"
 #include "delayed-inode.h"
 #include "ctree.h"
 #include "disk-io.h"
 #include "transaction.h"
 #include "btrfs_inode.h"
-#include "ioctl.h"
 #include "print-tree.h"
 #include "xattr.h"
 #include "volumes.h"
@@ -55,6 +55,7 @@
 #include "export.h"
 #include "compression.h"
 #include "rcu-string.h"
+#include "dev-replace.h"
 
 #define CREATE_TRACE_POINTS
 #include <trace/events/btrfs.h>
@@ -97,7 +98,7 @@ static void __save_error_info(struct btrfs_fs_info *fs_info)
         * today we only save the error info into ram.  Long term we'll
         * also send it down to the disk
         */
-       fs_info->fs_state = BTRFS_SUPER_FLAG_ERROR;
+       set_bit(BTRFS_FS_STATE_ERROR, &fs_info->fs_state);
 }
 
 static void save_error_info(struct btrfs_fs_info *fs_info)
@@ -113,10 +114,19 @@ static void btrfs_handle_error(struct btrfs_fs_info *fs_info)
        if (sb->s_flags & MS_RDONLY)
                return;
 
-       if (fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR) {
+       if (test_bit(BTRFS_FS_STATE_ERROR, &fs_info->fs_state)) {
                sb->s_flags |= MS_RDONLY;
                printk(KERN_INFO "btrfs is forced readonly\n");
-               __btrfs_scrub_cancel(fs_info);
+               /*
+                * Note that a running device replace operation is not
+                * canceled here although there is no way to update
+                * the progress. It would add the risk of a deadlock,
+                * therefore the canceling is ommited. The only penalty
+                * is that some I/O remains active until the procedure
+                * completes. The next time when the filesystem is
+                * mounted writeable again, the device replace
+                * operation continues.
+                */
 //             WARN_ON(1);
        }
 }
@@ -257,7 +267,7 @@ void __btrfs_abort_transaction(struct btrfs_trans_handle *trans,
                             function, line, errstr);
                return;
        }
-       trans->transaction->aborted = errno;
+       ACCESS_ONCE(trans->transaction->aborted) = errno;
        __btrfs_std_error(root->fs_info, function, line, errno, NULL);
 }
 /*
@@ -509,7 +519,9 @@ int btrfs_parse_options(struct btrfs_root *root, char *options)
                case Opt_alloc_start:
                        num = match_strdup(&args[0]);
                        if (num) {
+                               mutex_lock(&info->chunk_mutex);
                                info->alloc_start = memparse(num, NULL);
+                               mutex_unlock(&info->chunk_mutex);
                                kfree(num);
                                printk(KERN_INFO
                                        "btrfs: allocations start at %llu\n",
@@ -1186,7 +1198,8 @@ static void btrfs_resize_thread_pool(struct btrfs_fs_info *fs_info,
        btrfs_set_max_workers(&fs_info->endio_freespace_worker, new_pool_size);
        btrfs_set_max_workers(&fs_info->delayed_workers, new_pool_size);
        btrfs_set_max_workers(&fs_info->readahead_workers, new_pool_size);
-       btrfs_set_max_workers(&fs_info->scrub_workers, new_pool_size);
+       btrfs_set_max_workers(&fs_info->scrub_wr_completion_workers,
+                             new_pool_size);
 }
 
 static int btrfs_remount(struct super_block *sb, int *flags, char *data)
@@ -1215,8 +1228,15 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data)
                return 0;
 
        if (*flags & MS_RDONLY) {
+               /*
+                * this also happens on 'umount -rf' or on shutdown, when
+                * the filesystem is busy.
+                */
                sb->s_flags |= MS_RDONLY;
 
+               btrfs_dev_replace_suspend_for_unmount(fs_info);
+               btrfs_scrub_cancel(fs_info);
+
                ret = btrfs_commit_super(root);
                if (ret)
                        goto restore;
@@ -1226,6 +1246,15 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data)
                        goto restore;
                }
 
+               if (fs_info->fs_devices->missing_devices >
+                    fs_info->num_tolerated_disk_barrier_failures &&
+                   !(*flags & MS_RDONLY)) {
+                       printk(KERN_WARNING
+                              "Btrfs: too many missing devices, writeable remount is not allowed\n");
+                       ret = -EACCES;
+                       goto restore;
+               }
+
                if (btrfs_super_log_root(fs_info->super_copy) != 0) {
                        ret = -EINVAL;
                        goto restore;
@@ -1244,6 +1273,11 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data)
                if (ret)
                        goto restore;
 
+               ret = btrfs_resume_dev_replace_async(fs_info);
+               if (ret) {
+                       pr_warn("btrfs: failed to resume dev_replace\n");
+                       goto restore;
+               }
                sb->s_flags &= ~MS_RDONLY;
        }
 
@@ -1257,7 +1291,9 @@ restore:
        fs_info->mount_opt = old_opts;
        fs_info->compress_type = old_compress_type;
        fs_info->max_inline = old_max_inline;
+       mutex_lock(&fs_info->chunk_mutex);
        fs_info->alloc_start = old_alloc_start;
+       mutex_unlock(&fs_info->chunk_mutex);
        btrfs_resize_thread_pool(fs_info,
                old_thread_pool_size, fs_info->thread_pool_size);
        fs_info->metadata_ratio = old_metadata_ratio;
@@ -1336,7 +1372,8 @@ static int btrfs_calc_avail_data_space(struct btrfs_root *root, u64 *free_bytes)
                min_stripe_size = BTRFS_STRIPE_LEN;
 
        list_for_each_entry(device, &fs_devices->devices, dev_list) {
-               if (!device->in_fs_metadata || !device->bdev)
+               if (!device->in_fs_metadata || !device->bdev ||
+                   device->is_tgtdev_for_dev_replace)
                        continue;
 
                avail_space = device->total_bytes - device->bytes_used;
@@ -1647,10 +1684,18 @@ static int __init init_btrfs_fs(void)
        if (err)
                goto free_ordered_data;
 
-       err = btrfs_interface_init();
+       err = btrfs_auto_defrag_init();
        if (err)
                goto free_delayed_inode;
 
+       err = btrfs_delayed_ref_init();
+       if (err)
+               goto free_auto_defrag;
+
+       err = btrfs_interface_init();
+       if (err)
+               goto free_delayed_ref;
+
        err = register_filesystem(&btrfs_fs_type);
        if (err)
                goto unregister_ioctl;
@@ -1662,6 +1707,10 @@ static int __init init_btrfs_fs(void)
 
 unregister_ioctl:
        btrfs_interface_exit();
+free_delayed_ref:
+       btrfs_delayed_ref_exit();
+free_auto_defrag:
+       btrfs_auto_defrag_exit();
 free_delayed_inode:
        btrfs_delayed_inode_exit();
 free_ordered_data:
@@ -1681,6 +1730,8 @@ free_compress:
 static void __exit exit_btrfs_fs(void)
 {
        btrfs_destroy_cachep();
+       btrfs_delayed_ref_exit();
+       btrfs_auto_defrag_exit();
        btrfs_delayed_inode_exit();
        ordered_data_exit();
        extent_map_exit();