Skip to content

Commit

Permalink
Btrfs: fix race with freeze and free space inodes
Browse files Browse the repository at this point in the history
So we start our freeze, somebody comes in and does an fsync() on a file
where we have to commit a transaction for whatever reason, and we will
deadlock because the freeze is waiting on FS_FREEZE people to stop writing
to the file system, but the transaction is waiting for its free space inodes
to be written out, which are in turn waiting on sb_start_intwrite while
trying to write the file extents.  To fix this we'll just skip the
sb_start_intwrite() if we TRANS_JOIN_NOLOCK since we're being waited on by a
transaction commit so we're safe wrt to freeze and this will keep us from
deadlocking.  Thanks,

Signed-off-by: Josef Bacik <jbacik@fusionio.com>
  • Loading branch information
Josef Bacik authored and Chris Mason committed Oct 4, 2012
1 parent 6bbe3a9 commit 9811465
Showing 1 changed file with 11 additions and 2 deletions.
13 changes: 11 additions & 2 deletions fs/btrfs/transaction.c
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,15 @@ static struct btrfs_trans_handle *start_transaction(struct btrfs_root *root,
if (!h)
return ERR_PTR(-ENOMEM);

if (!__sb_start_write(root->fs_info->sb, SB_FREEZE_FS, false)) {
/*
* If we are JOIN_NOLOCK we're already committing a transaction and
* waiting on this guy, so we don't need to do the sb_start_intwrite
* because we're already holding a ref. We need this because we could
* have raced in and did an fsync() on a file which can kick a commit
* and then we deadlock with somebody doing a freeze.
*/
if (type != TRANS_JOIN_NOLOCK &&
!__sb_start_write(root->fs_info->sb, SB_FREEZE_FS, false)) {
if (type == TRANS_JOIN_FREEZE)
return ERR_PTR(-EPERM);
sb_start_intwrite(root->fs_info->sb);
Expand Down Expand Up @@ -601,7 +609,8 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans,
}
}

sb_end_intwrite(root->fs_info->sb);
if (lock)
sb_end_intwrite(root->fs_info->sb);

WARN_ON(cur_trans != info->running_transaction);
WARN_ON(atomic_read(&cur_trans->num_writers) < 1);
Expand Down

0 comments on commit 9811465

Please sign in to comment.