Skip to content

Commit

Permalink
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel…
Browse files Browse the repository at this point in the history
…/git/mason/linux-btrfs

Pull btrfs fixes from Chris Mason:
 "These are scattered fixes and one performance improvement.  The
  biggest functional change is in how we throttle metadata changes.  The
  new code bumps our average file creation rate up by ~13% in fs_mark,
  and lowers CPU usage.

  Stefan bisected out a regression in our allocation code that made
  balance loop on extents larger than 256MB."

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs:
  Btrfs: improve the delayed inode throttling
  Btrfs: fix a mismerge in btrfs_balance()
  Btrfs: enforce min_bytes parameter during extent allocation
  Btrfs: allow running defrag in parallel to administrative tasks
  Btrfs: avoid deadlock on transaction waiting list
  Btrfs: do not BUG_ON on aborted situation
  Btrfs: do not BUG_ON in prepare_to_reloc
  Btrfs: free all recorded tree blocks on error
  Btrfs: build up error handling for merge_reloc_roots
  Btrfs: check for NULL pointer in updating reloc roots
  Btrfs: fix unclosed transaction handler when the async transaction commitment fails
  Btrfs: fix wrong handle at error path of create_snapshot() when the commit fails
  Btrfs: use set_nlink if our i_nlink is 0
  • Loading branch information
Linus Torvalds committed Mar 9, 2013
2 parents 2ef3920 + de3cb94 commit 0aefda3
Show file tree
Hide file tree
Showing 9 changed files with 221 additions and 130 deletions.
151 changes: 90 additions & 61 deletions fs/btrfs/delayed-inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@
#include "disk-io.h"
#include "transaction.h"

#define BTRFS_DELAYED_WRITEBACK 400
#define BTRFS_DELAYED_BACKGROUND 100
#define BTRFS_DELAYED_WRITEBACK 512
#define BTRFS_DELAYED_BACKGROUND 128
#define BTRFS_DELAYED_BATCH 16

static struct kmem_cache *delayed_node_cache;

Expand Down Expand Up @@ -494,6 +495,15 @@ static int __btrfs_add_delayed_deletion_item(struct btrfs_delayed_node *node,
BTRFS_DELAYED_DELETION_ITEM);
}

static void finish_one_item(struct btrfs_delayed_root *delayed_root)
{
int seq = atomic_inc_return(&delayed_root->items_seq);
if ((atomic_dec_return(&delayed_root->items) <
BTRFS_DELAYED_BACKGROUND || seq % BTRFS_DELAYED_BATCH == 0) &&
waitqueue_active(&delayed_root->wait))
wake_up(&delayed_root->wait);
}

static void __btrfs_remove_delayed_item(struct btrfs_delayed_item *delayed_item)
{
struct rb_root *root;
Expand All @@ -512,10 +522,8 @@ static void __btrfs_remove_delayed_item(struct btrfs_delayed_item *delayed_item)

rb_erase(&delayed_item->rb_node, root);
delayed_item->delayed_node->count--;
if (atomic_dec_return(&delayed_root->items) <
BTRFS_DELAYED_BACKGROUND &&
waitqueue_active(&delayed_root->wait))
wake_up(&delayed_root->wait);

finish_one_item(delayed_root);
}

static void btrfs_release_delayed_item(struct btrfs_delayed_item *item)
Expand Down Expand Up @@ -1056,10 +1064,7 @@ static void btrfs_release_delayed_inode(struct btrfs_delayed_node *delayed_node)
delayed_node->count--;

delayed_root = delayed_node->root->fs_info->delayed_root;
if (atomic_dec_return(&delayed_root->items) <
BTRFS_DELAYED_BACKGROUND &&
waitqueue_active(&delayed_root->wait))
wake_up(&delayed_root->wait);
finish_one_item(delayed_root);
}
}

Expand Down Expand Up @@ -1304,35 +1309,44 @@ void btrfs_remove_delayed_node(struct inode *inode)
btrfs_release_delayed_node(delayed_node);
}

struct btrfs_async_delayed_node {
struct btrfs_root *root;
struct btrfs_delayed_node *delayed_node;
struct btrfs_async_delayed_work {
struct btrfs_delayed_root *delayed_root;
int nr;
struct btrfs_work work;
};

static void btrfs_async_run_delayed_node_done(struct btrfs_work *work)
static void btrfs_async_run_delayed_root(struct btrfs_work *work)
{
struct btrfs_async_delayed_node *async_node;
struct btrfs_async_delayed_work *async_work;
struct btrfs_delayed_root *delayed_root;
struct btrfs_trans_handle *trans;
struct btrfs_path *path;
struct btrfs_delayed_node *delayed_node = NULL;
struct btrfs_root *root;
struct btrfs_block_rsv *block_rsv;
int need_requeue = 0;
int total_done = 0;

async_node = container_of(work, struct btrfs_async_delayed_node, work);
async_work = container_of(work, struct btrfs_async_delayed_work, work);
delayed_root = async_work->delayed_root;

path = btrfs_alloc_path();
if (!path)
goto out;
path->leave_spinning = 1;

delayed_node = async_node->delayed_node;
again:
if (atomic_read(&delayed_root->items) < BTRFS_DELAYED_BACKGROUND / 2)
goto free_path;

delayed_node = btrfs_first_prepared_delayed_node(delayed_root);
if (!delayed_node)
goto free_path;

path->leave_spinning = 1;
root = delayed_node->root;

trans = btrfs_join_transaction(root);
if (IS_ERR(trans))
goto free_path;
goto release_path;

block_rsv = trans->block_rsv;
trans->block_rsv = &root->fs_info->delayed_block_rsv;
Expand Down Expand Up @@ -1363,57 +1377,47 @@ static void btrfs_async_run_delayed_node_done(struct btrfs_work *work)
* Task1 will sleep until the transaction is commited.
*/
mutex_lock(&delayed_node->mutex);
if (delayed_node->count)
need_requeue = 1;
else
btrfs_dequeue_delayed_node(root->fs_info->delayed_root,
delayed_node);
btrfs_dequeue_delayed_node(root->fs_info->delayed_root, delayed_node);
mutex_unlock(&delayed_node->mutex);

trans->block_rsv = block_rsv;
btrfs_end_transaction_dmeta(trans, root);
btrfs_btree_balance_dirty_nodelay(root);

release_path:
btrfs_release_path(path);
total_done++;

btrfs_release_prepared_delayed_node(delayed_node);
if (async_work->nr == 0 || total_done < async_work->nr)
goto again;

free_path:
btrfs_free_path(path);
out:
if (need_requeue)
btrfs_requeue_work(&async_node->work);
else {
btrfs_release_prepared_delayed_node(delayed_node);
kfree(async_node);
}
wake_up(&delayed_root->wait);
kfree(async_work);
}


static int btrfs_wq_run_delayed_node(struct btrfs_delayed_root *delayed_root,
struct btrfs_root *root, int all)
struct btrfs_root *root, int nr)
{
struct btrfs_async_delayed_node *async_node;
struct btrfs_delayed_node *curr;
int count = 0;
struct btrfs_async_delayed_work *async_work;

again:
curr = btrfs_first_prepared_delayed_node(delayed_root);
if (!curr)
if (atomic_read(&delayed_root->items) < BTRFS_DELAYED_BACKGROUND)
return 0;

async_node = kmalloc(sizeof(*async_node), GFP_NOFS);
if (!async_node) {
btrfs_release_prepared_delayed_node(curr);
async_work = kmalloc(sizeof(*async_work), GFP_NOFS);
if (!async_work)
return -ENOMEM;
}

async_node->root = root;
async_node->delayed_node = curr;

async_node->work.func = btrfs_async_run_delayed_node_done;
async_node->work.flags = 0;

btrfs_queue_worker(&root->fs_info->delayed_workers, &async_node->work);
count++;

if (all || count < 4)
goto again;
async_work->delayed_root = delayed_root;
async_work->work.func = btrfs_async_run_delayed_root;
async_work->work.flags = 0;
async_work->nr = nr;

btrfs_queue_worker(&root->fs_info->delayed_workers, &async_work->work);
return 0;
}

Expand All @@ -1424,30 +1428,55 @@ void btrfs_assert_delayed_root_empty(struct btrfs_root *root)
WARN_ON(btrfs_first_delayed_node(delayed_root));
}

static int refs_newer(struct btrfs_delayed_root *delayed_root,
int seq, int count)
{
int val = atomic_read(&delayed_root->items_seq);

if (val < seq || val >= seq + count)
return 1;
return 0;
}

void btrfs_balance_delayed_items(struct btrfs_root *root)
{
struct btrfs_delayed_root *delayed_root;
int seq;

delayed_root = btrfs_get_delayed_root(root);

if (atomic_read(&delayed_root->items) < BTRFS_DELAYED_BACKGROUND)
return;

seq = atomic_read(&delayed_root->items_seq);

if (atomic_read(&delayed_root->items) >= BTRFS_DELAYED_WRITEBACK) {
int ret;
ret = btrfs_wq_run_delayed_node(delayed_root, root, 1);
DEFINE_WAIT(__wait);

ret = btrfs_wq_run_delayed_node(delayed_root, root, 0);
if (ret)
return;

wait_event_interruptible_timeout(
delayed_root->wait,
(atomic_read(&delayed_root->items) <
BTRFS_DELAYED_BACKGROUND),
HZ);
return;
while (1) {
prepare_to_wait(&delayed_root->wait, &__wait,
TASK_INTERRUPTIBLE);

if (refs_newer(delayed_root, seq,
BTRFS_DELAYED_BATCH) ||
atomic_read(&delayed_root->items) <
BTRFS_DELAYED_BACKGROUND) {
break;
}
if (!signal_pending(current))
schedule();
else
break;
}
finish_wait(&delayed_root->wait, &__wait);
}

btrfs_wq_run_delayed_node(delayed_root, root, 0);
btrfs_wq_run_delayed_node(delayed_root, root, BTRFS_DELAYED_BATCH);
}

/* Will return 0 or -ENOMEM */
Expand Down
2 changes: 2 additions & 0 deletions fs/btrfs/delayed-inode.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ struct btrfs_delayed_root {
*/
struct list_head prepare_list;
atomic_t items; /* for delayed items */
atomic_t items_seq; /* for delayed items */
int nodes; /* for delayed nodes */
wait_queue_head_t wait;
};
Expand Down Expand Up @@ -86,6 +87,7 @@ static inline void btrfs_init_delayed_root(
struct btrfs_delayed_root *delayed_root)
{
atomic_set(&delayed_root->items, 0);
atomic_set(&delayed_root->items_seq, 0);
delayed_root->nodes = 0;
spin_lock_init(&delayed_root->lock);
init_waitqueue_head(&delayed_root->wait);
Expand Down
16 changes: 7 additions & 9 deletions fs/btrfs/disk-io.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ static void btrfs_destroy_ordered_operations(struct btrfs_transaction *t,
static void btrfs_destroy_ordered_extents(struct btrfs_root *root);
static int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans,
struct btrfs_root *root);
static void btrfs_destroy_pending_snapshots(struct btrfs_transaction *t);
static void btrfs_evict_pending_snapshots(struct btrfs_transaction *t);
static void btrfs_destroy_delalloc_inodes(struct btrfs_root *root);
static int btrfs_destroy_marked_extents(struct btrfs_root *root,
struct extent_io_tree *dirty_pages,
Expand Down Expand Up @@ -3687,7 +3687,7 @@ int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans,
return ret;
}

static void btrfs_destroy_pending_snapshots(struct btrfs_transaction *t)
static void btrfs_evict_pending_snapshots(struct btrfs_transaction *t)
{
struct btrfs_pending_snapshot *snapshot;
struct list_head splice;
Expand All @@ -3700,10 +3700,8 @@ static void btrfs_destroy_pending_snapshots(struct btrfs_transaction *t)
snapshot = list_entry(splice.next,
struct btrfs_pending_snapshot,
list);

snapshot->error = -ECANCELED;
list_del_init(&snapshot->list);

kfree(snapshot);
}
}

Expand Down Expand Up @@ -3840,6 +3838,8 @@ void btrfs_cleanup_one_transaction(struct btrfs_transaction *cur_trans,
cur_trans->blocked = 1;
wake_up(&root->fs_info->transaction_blocked_wait);

btrfs_evict_pending_snapshots(cur_trans);

cur_trans->blocked = 0;
wake_up(&root->fs_info->transaction_wait);

Expand All @@ -3849,8 +3849,6 @@ void btrfs_cleanup_one_transaction(struct btrfs_transaction *cur_trans,
btrfs_destroy_delayed_inodes(root);
btrfs_assert_delayed_root_empty(root);

btrfs_destroy_pending_snapshots(cur_trans);

btrfs_destroy_marked_extents(root, &cur_trans->dirty_pages,
EXTENT_DIRTY);
btrfs_destroy_pinned_extent(root,
Expand Down Expand Up @@ -3894,6 +3892,8 @@ int btrfs_cleanup_transaction(struct btrfs_root *root)
if (waitqueue_active(&root->fs_info->transaction_blocked_wait))
wake_up(&root->fs_info->transaction_blocked_wait);

btrfs_evict_pending_snapshots(t);

t->blocked = 0;
smp_mb();
if (waitqueue_active(&root->fs_info->transaction_wait))
Expand All @@ -3907,8 +3907,6 @@ int btrfs_cleanup_transaction(struct btrfs_root *root)
btrfs_destroy_delayed_inodes(root);
btrfs_assert_delayed_root_empty(root);

btrfs_destroy_pending_snapshots(t);

btrfs_destroy_delalloc_inodes(root);

spin_lock(&root->fs_info->trans_lock);
Expand Down
6 changes: 4 additions & 2 deletions fs/btrfs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -8502,6 +8502,7 @@ static int __btrfs_prealloc_file_range(struct inode *inode, int mode,
struct btrfs_key ins;
u64 cur_offset = start;
u64 i_size;
u64 cur_bytes;
int ret = 0;
bool own_trans = true;

Expand All @@ -8516,8 +8517,9 @@ static int __btrfs_prealloc_file_range(struct inode *inode, int mode,
}
}

ret = btrfs_reserve_extent(trans, root,
min(num_bytes, 256ULL * 1024 * 1024),
cur_bytes = min(num_bytes, 256ULL * 1024 * 1024);
cur_bytes = max(cur_bytes, min_size);
ret = btrfs_reserve_extent(trans, root, cur_bytes,
min_size, 0, *alloc_hint, &ins, 1);
if (ret) {
if (own_trans)
Expand Down
Loading

0 comments on commit 0aefda3

Please sign in to comment.