浏览代码

Btrfs: do not pin while under spin lock

When testing a corrupted fs I noticed I was getting sleep while atomic errors
when the transaction aborted.  This is because btrfs_pin_extent may need to
allocate memory and we are calling this under the spin lock.  Fix this by moving
it out and doing the pin after dropping the spin lock but before dropping the
mutex, the same way it works when delayed refs run normally.  Thanks,

Signed-off-by: Josef Bacik <jbacik@fusionio.com>
Josef Bacik 12 年之前
父节点
当前提交
e78417d192
共有 1 个文件被更改,包括 8 次插入4 次删除
  1. 8 4
      fs/btrfs/disk-io.c

+ 8 - 4
fs/btrfs/disk-io.c

@@ -3762,6 +3762,7 @@ int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans,
 
 
 	while ((node = rb_first(&delayed_refs->root)) != NULL) {
 	while ((node = rb_first(&delayed_refs->root)) != NULL) {
 		struct btrfs_delayed_ref_head *head = NULL;
 		struct btrfs_delayed_ref_head *head = NULL;
+		bool pin_bytes = false;
 
 
 		ref = rb_entry(node, struct btrfs_delayed_ref_node, rb_node);
 		ref = rb_entry(node, struct btrfs_delayed_ref_node, rb_node);
 		atomic_set(&ref->refs, 1);
 		atomic_set(&ref->refs, 1);
@@ -3782,8 +3783,7 @@ int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans,
 			}
 			}
 
 
 			if (head->must_insert_reserved)
 			if (head->must_insert_reserved)
-				btrfs_pin_extent(root, ref->bytenr,
-						 ref->num_bytes, 1);
+				pin_bytes = true;
 			btrfs_free_delayed_extent_op(head->extent_op);
 			btrfs_free_delayed_extent_op(head->extent_op);
 			delayed_refs->num_heads--;
 			delayed_refs->num_heads--;
 			if (list_empty(&head->cluster))
 			if (list_empty(&head->cluster))
@@ -3794,9 +3794,13 @@ int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans,
 		ref->in_tree = 0;
 		ref->in_tree = 0;
 		rb_erase(&ref->rb_node, &delayed_refs->root);
 		rb_erase(&ref->rb_node, &delayed_refs->root);
 		delayed_refs->num_entries--;
 		delayed_refs->num_entries--;
-		if (head)
-			mutex_unlock(&head->mutex);
 		spin_unlock(&delayed_refs->lock);
 		spin_unlock(&delayed_refs->lock);
+		if (head) {
+			if (pin_bytes)
+				btrfs_pin_extent(root, ref->bytenr,
+						 ref->num_bytes, 1);
+			mutex_unlock(&head->mutex);
+		}
 		btrfs_put_delayed_ref(ref);
 		btrfs_put_delayed_ref(ref);
 
 
 		cond_resched();
 		cond_resched();