Skip to content

Commit

Permalink
Btrfs: use bit operation for ->fs_state
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Miao Xie authored and Josef Bacik committed Feb 20, 2013
1 parent de98ced commit 87533c4
Show file tree
Hide file tree
Showing 6 changed files with 14 additions and 12 deletions.
4 changes: 3 additions & 1 deletion fs/btrfs/ctree.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down Expand Up @@ -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;

Expand Down
5 changes: 3 additions & 2 deletions fs/btrfs/disk-io.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion fs/btrfs/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion fs/btrfs/scrub.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
4 changes: 2 additions & 2 deletions fs/btrfs/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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");
/*
Expand Down
9 changes: 4 additions & 5 deletions fs/btrfs/transaction.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -113,7 +113,7 @@ static noinline int join_transaction(struct btrfs_root *root, int type)
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;
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit 87533c4

Please sign in to comment.