Commit e62063d6 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs

Pull btrfs fixes from Chris Mason:
 "This is a small collection of fixes, including a regression fix from
  Liu Bo that solves rare crashes with compression on.

  I've merged my for-linus up to 3.12-rc3 because the top commit is only
  meant for 3.12.  The rest of the fixes are also available in my master
  branch on top of my last 3.11 based pull"

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs:
  btrfs: Fix crash due to not allocating integrity data for a bioset
  Btrfs: fix a use-after-free bug in btrfs_dev_replace_finishing
  Btrfs: eliminate races in worker stopping code
  Btrfs: fix crash of compressed writes
  Btrfs: fix transid verify errors when recovering log tree
parents 85f6d2db b208c2f7
...@@ -107,7 +107,8 @@ static void check_idle_worker(struct btrfs_worker_thread *worker) ...@@ -107,7 +107,8 @@ static void check_idle_worker(struct btrfs_worker_thread *worker)
worker->idle = 1; worker->idle = 1;
/* the list may be empty if the worker is just starting */ /* the list may be empty if the worker is just starting */
if (!list_empty(&worker->worker_list)) { if (!list_empty(&worker->worker_list) &&
!worker->workers->stopping) {
list_move(&worker->worker_list, list_move(&worker->worker_list,
&worker->workers->idle_list); &worker->workers->idle_list);
} }
...@@ -127,7 +128,8 @@ static void check_busy_worker(struct btrfs_worker_thread *worker) ...@@ -127,7 +128,8 @@ static void check_busy_worker(struct btrfs_worker_thread *worker)
spin_lock_irqsave(&worker->workers->lock, flags); spin_lock_irqsave(&worker->workers->lock, flags);
worker->idle = 0; worker->idle = 0;
if (!list_empty(&worker->worker_list)) { if (!list_empty(&worker->worker_list) &&
!worker->workers->stopping) {
list_move_tail(&worker->worker_list, list_move_tail(&worker->worker_list,
&worker->workers->worker_list); &worker->workers->worker_list);
} }
...@@ -412,6 +414,7 @@ void btrfs_stop_workers(struct btrfs_workers *workers) ...@@ -412,6 +414,7 @@ void btrfs_stop_workers(struct btrfs_workers *workers)
int can_stop; int can_stop;
spin_lock_irq(&workers->lock); spin_lock_irq(&workers->lock);
workers->stopping = 1;
list_splice_init(&workers->idle_list, &workers->worker_list); list_splice_init(&workers->idle_list, &workers->worker_list);
while (!list_empty(&workers->worker_list)) { while (!list_empty(&workers->worker_list)) {
cur = workers->worker_list.next; cur = workers->worker_list.next;
...@@ -455,6 +458,7 @@ void btrfs_init_workers(struct btrfs_workers *workers, char *name, int max, ...@@ -455,6 +458,7 @@ void btrfs_init_workers(struct btrfs_workers *workers, char *name, int max,
workers->ordered = 0; workers->ordered = 0;
workers->atomic_start_pending = 0; workers->atomic_start_pending = 0;
workers->atomic_worker_start = async_helper; workers->atomic_worker_start = async_helper;
workers->stopping = 0;
} }
/* /*
...@@ -480,15 +484,19 @@ static int __btrfs_start_workers(struct btrfs_workers *workers) ...@@ -480,15 +484,19 @@ static int __btrfs_start_workers(struct btrfs_workers *workers)
atomic_set(&worker->num_pending, 0); atomic_set(&worker->num_pending, 0);
atomic_set(&worker->refs, 1); atomic_set(&worker->refs, 1);
worker->workers = workers; worker->workers = workers;
worker->task = kthread_run(worker_loop, worker, worker->task = kthread_create(worker_loop, worker,
"btrfs-%s-%d", workers->name, "btrfs-%s-%d", workers->name,
workers->num_workers + 1); workers->num_workers + 1);
if (IS_ERR(worker->task)) { if (IS_ERR(worker->task)) {
ret = PTR_ERR(worker->task); ret = PTR_ERR(worker->task);
kfree(worker);
goto fail; goto fail;
} }
spin_lock_irq(&workers->lock); spin_lock_irq(&workers->lock);
if (workers->stopping) {
spin_unlock_irq(&workers->lock);
goto fail_kthread;
}
list_add_tail(&worker->worker_list, &workers->idle_list); list_add_tail(&worker->worker_list, &workers->idle_list);
worker->idle = 1; worker->idle = 1;
workers->num_workers++; workers->num_workers++;
...@@ -496,8 +504,13 @@ static int __btrfs_start_workers(struct btrfs_workers *workers) ...@@ -496,8 +504,13 @@ static int __btrfs_start_workers(struct btrfs_workers *workers)
WARN_ON(workers->num_workers_starting < 0); WARN_ON(workers->num_workers_starting < 0);
spin_unlock_irq(&workers->lock); spin_unlock_irq(&workers->lock);
wake_up_process(worker->task);
return 0; return 0;
fail_kthread:
kthread_stop(worker->task);
fail: fail:
kfree(worker);
spin_lock_irq(&workers->lock); spin_lock_irq(&workers->lock);
workers->num_workers_starting--; workers->num_workers_starting--;
spin_unlock_irq(&workers->lock); spin_unlock_irq(&workers->lock);
......
...@@ -107,6 +107,8 @@ struct btrfs_workers { ...@@ -107,6 +107,8 @@ struct btrfs_workers {
/* extra name for this worker, used for current->name */ /* extra name for this worker, used for current->name */
char *name; char *name;
int stopping;
}; };
void btrfs_queue_worker(struct btrfs_workers *workers, struct btrfs_work *work); void btrfs_queue_worker(struct btrfs_workers *workers, struct btrfs_work *work);
......
...@@ -535,10 +535,7 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info, ...@@ -535,10 +535,7 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info,
list_add(&tgt_device->dev_alloc_list, &fs_info->fs_devices->alloc_list); list_add(&tgt_device->dev_alloc_list, &fs_info->fs_devices->alloc_list);
btrfs_rm_dev_replace_srcdev(fs_info, src_device); btrfs_rm_dev_replace_srcdev(fs_info, src_device);
if (src_device->bdev) {
/* zero out the old super */
btrfs_scratch_superblock(src_device);
}
/* /*
* this is again a consistent state where no dev_replace procedure * this is again a consistent state where no dev_replace procedure
* is running, the target device is part of the filesystem, the * is running, the target device is part of the filesystem, the
......
...@@ -145,8 +145,16 @@ int __init extent_io_init(void) ...@@ -145,8 +145,16 @@ int __init extent_io_init(void)
offsetof(struct btrfs_io_bio, bio)); offsetof(struct btrfs_io_bio, bio));
if (!btrfs_bioset) if (!btrfs_bioset)
goto free_buffer_cache; goto free_buffer_cache;
if (bioset_integrity_create(btrfs_bioset, BIO_POOL_SIZE))
goto free_bioset;
return 0; return 0;
free_bioset:
bioset_free(btrfs_bioset);
btrfs_bioset = NULL;
free_buffer_cache: free_buffer_cache:
kmem_cache_destroy(extent_buffer_cache); kmem_cache_destroy(extent_buffer_cache);
extent_buffer_cache = NULL; extent_buffer_cache = NULL;
...@@ -1614,7 +1622,7 @@ static noinline u64 find_lock_delalloc_range(struct inode *inode, ...@@ -1614,7 +1622,7 @@ static noinline u64 find_lock_delalloc_range(struct inode *inode,
*start = delalloc_start; *start = delalloc_start;
*end = delalloc_end; *end = delalloc_end;
free_extent_state(cached_state); free_extent_state(cached_state);
return found; return 0;
} }
/* /*
......
...@@ -1838,11 +1838,8 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, ...@@ -1838,11 +1838,8 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
assert_qgroups_uptodate(trans); assert_qgroups_uptodate(trans);
update_super_roots(root); update_super_roots(root);
if (!root->fs_info->log_root_recovering) {
btrfs_set_super_log_root(root->fs_info->super_copy, 0); btrfs_set_super_log_root(root->fs_info->super_copy, 0);
btrfs_set_super_log_root_level(root->fs_info->super_copy, 0); btrfs_set_super_log_root_level(root->fs_info->super_copy, 0);
}
memcpy(root->fs_info->super_for_commit, root->fs_info->super_copy, memcpy(root->fs_info->super_for_commit, root->fs_info->super_copy,
sizeof(*root->fs_info->super_copy)); sizeof(*root->fs_info->super_copy));
......
...@@ -1716,6 +1716,7 @@ void btrfs_rm_dev_replace_srcdev(struct btrfs_fs_info *fs_info, ...@@ -1716,6 +1716,7 @@ void btrfs_rm_dev_replace_srcdev(struct btrfs_fs_info *fs_info,
struct btrfs_device *srcdev) struct btrfs_device *srcdev)
{ {
WARN_ON(!mutex_is_locked(&fs_info->fs_devices->device_list_mutex)); WARN_ON(!mutex_is_locked(&fs_info->fs_devices->device_list_mutex));
list_del_rcu(&srcdev->dev_list); list_del_rcu(&srcdev->dev_list);
list_del_rcu(&srcdev->dev_alloc_list); list_del_rcu(&srcdev->dev_alloc_list);
fs_info->fs_devices->num_devices--; fs_info->fs_devices->num_devices--;
...@@ -1725,9 +1726,13 @@ void btrfs_rm_dev_replace_srcdev(struct btrfs_fs_info *fs_info, ...@@ -1725,9 +1726,13 @@ void btrfs_rm_dev_replace_srcdev(struct btrfs_fs_info *fs_info,
} }
if (srcdev->can_discard) if (srcdev->can_discard)
fs_info->fs_devices->num_can_discard--; fs_info->fs_devices->num_can_discard--;
if (srcdev->bdev) if (srcdev->bdev) {
fs_info->fs_devices->open_devices--; fs_info->fs_devices->open_devices--;
/* zero out the old super */
btrfs_scratch_superblock(srcdev);
}
call_rcu(&srcdev->rcu, free_device); call_rcu(&srcdev->rcu, free_device);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment