Btrfs: use bit operation for ->fs_state
authorMiao Xie <miaox@cn.fujitsu.com>
Tue, 29 Jan 2013 10:14:48 +0000 (10:14 +0000)
committerJosef Bacik <jbacik@fusionio.com>
Wed, 20 Feb 2013 17:59:09 +0000 (12:59 -0500)
There is no lock to protect fs_info->fs_state, it will introduce
some problems, such as the value may be covered by the other task
when several tasks modify it. For example:
Task0 - CPU0 Task1 - CPU1
mov %fs_state rax
or $0x1 rax
mov %fs_state rax
or $0x2 rax
mov rax %fs_state
mov rax %fs_state
The expected value is 3, but in fact, it is 2.

Though this problem doesn't happen now (because there is only one
flag currently), the code is error prone, if we add other flags,
the above problem will happen to a certainty.

Now we use bit operation for it to fix the above problem.
In this way, we can make the code more robust and be easy to
add new flags.

Signed-off-by: Miao Xie <miaox@cn.fujitsu.com>
Signed-off-by: Josef Bacik <jbacik@fusionio.com>
fs/btrfs/ctree.h
fs/btrfs/disk-io.c
fs/btrfs/file.c
fs/btrfs/scrub.c
fs/btrfs/super.c
fs/btrfs/transaction.c

index 5f5c30aaef360fbb08a403359946568081bbfbb7..78fba44ad3d91771532f316243e715ae77f355ef 100644 (file)
@@ -338,7 +338,9 @@ static inline unsigned long btrfs_chunk_item_size(int num_stripes)
 /*
  * File system states
  */
+#define BTRFS_FS_STATE_ERROR           0
 
+/* Super block flags */
 /* Errors detected */
 #define BTRFS_SUPER_FLAG_ERROR         (1ULL << 2)
 
@@ -1549,7 +1551,7 @@ struct btrfs_fs_info {
        u64 qgroup_seq;
 
        /* filesystem state */
-       u64 fs_state;
+       unsigned long fs_state;
 
        struct btrfs_delayed_root *delayed_root;
 
index 00b6742fdde760336522520177804ef0920676cd..8e58a1f9054697fdf6a4866e4fb738afc97e9a98 100644 (file)
@@ -2201,7 +2201,8 @@ int open_ctree(struct super_block *sb,
                goto fail_alloc;
 
        /* check FS state, whether FS is broken. */
-       fs_info->fs_state |= btrfs_super_flags(disk_super);
+       if (btrfs_super_flags(disk_super) & BTRFS_SUPER_FLAG_ERROR)
+               set_bit(BTRFS_FS_STATE_ERROR, &fs_info->fs_state);
 
        ret = btrfs_check_super_valid(fs_info, sb->s_flags & MS_RDONLY);
        if (ret) {
@@ -3359,7 +3360,7 @@ int close_ctree(struct btrfs_root *root)
                        printk(KERN_ERR "btrfs: commit super ret %d\n", ret);
        }
 
-       if (fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR)
+       if (test_bit(BTRFS_FS_STATE_ERROR, &fs_info->fs_state))
                btrfs_error_commit_super(root);
 
        btrfs_put_block_group_cache(fs_info);
index 13c78ea3ebce686aea83ecb32e625f62f095486f..75d0fe134be31cb6b23e9a0091263cd993a1f48c 100644 (file)
@@ -1545,7 +1545,7 @@ static ssize_t btrfs_file_aio_write(struct kiocb *iocb,
         * although we have opened a file as writable, we have
         * to stop this write operation to ensure FS consistency.
         */
-       if (root->fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR) {
+       if (test_bit(BTRFS_FS_STATE_ERROR, &root->fs_info->fs_state)) {
                mutex_unlock(&inode->i_mutex);
                err = -EROFS;
                goto out;
index 67783e03d1211bdcba1e84a20aa56a528916c370..c78b2a3fc3359e5625ff703f32f4fcc1cb3ae792 100644 (file)
@@ -2708,7 +2708,7 @@ static noinline_for_stack int scrub_supers(struct scrub_ctx *sctx,
        int     ret;
        struct btrfs_root *root = sctx->dev_root;
 
-       if (root->fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR)
+       if (test_bit(BTRFS_FS_STATE_ERROR, &root->fs_info->fs_state))
                return -EIO;
 
        gen = root->fs_info->last_trans_committed;
index eda330df45a4037387aa44606722e886a25aa9f8..4152f9ea34f5484c00f7f62b2acbbee9861ac4c6 100644 (file)
@@ -98,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)
@@ -114,7 +114,7 @@ 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");
                /*
index 34610dc6d140df679b7c5fe2cabcce33260a2e06..baf6d74fd0f29d618d60c15921a482f627d67fe7 100644 (file)
@@ -61,7 +61,7 @@ static noinline int join_transaction(struct btrfs_root *root, int type)
        spin_lock(&fs_info->trans_lock);
 loop:
        /* The file system has been taken offline. No new transactions. */
-       if (fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR) {
+       if (test_bit(BTRFS_FS_STATE_ERROR, &fs_info->fs_state)) {
                spin_unlock(&fs_info->trans_lock);
                return -EROFS;
        }
@@ -113,7 +113,7 @@ loop:
                kmem_cache_free(btrfs_transaction_cachep, cur_trans);
                cur_trans = fs_info->running_transaction;
                goto loop;
-       } else if (fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR) {
+       } else if (test_bit(BTRFS_FS_STATE_ERROR, &fs_info->fs_state)) {
                spin_unlock(&fs_info->trans_lock);
                kmem_cache_free(btrfs_transaction_cachep, cur_trans);
                return -EROFS;
@@ -301,7 +301,7 @@ start_transaction(struct btrfs_root *root, u64 num_items, int type,
        int ret;
        u64 qgroup_reserved = 0;
 
-       if (root->fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR)
+       if (test_bit(BTRFS_FS_STATE_ERROR, &root->fs_info->fs_state))
                return ERR_PTR(-EROFS);
 
        if (current->journal_info) {
@@ -645,9 +645,8 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans,
                btrfs_run_delayed_iputs(root);
 
        if (trans->aborted ||
-           root->fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR) {
+           test_bit(BTRFS_FS_STATE_ERROR, &root->fs_info->fs_state))
                err = -EIO;
-       }
        assert_qgroups_uptodate(trans);
 
        kmem_cache_free(btrfs_trans_handle_cachep, trans);