|
@@ -1323,8 +1323,25 @@ int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
|
|
int btrfs_extent_post_op(struct btrfs_trans_handle *trans,
|
|
int btrfs_extent_post_op(struct btrfs_trans_handle *trans,
|
|
struct btrfs_root *root)
|
|
struct btrfs_root *root)
|
|
{
|
|
{
|
|
- finish_current_insert(trans, root->fs_info->extent_root, 1);
|
|
|
|
- del_pending_extents(trans, root->fs_info->extent_root, 1);
|
|
|
|
|
|
+ u64 start;
|
|
|
|
+ u64 end;
|
|
|
|
+ int ret;
|
|
|
|
+
|
|
|
|
+ while(1) {
|
|
|
|
+ finish_current_insert(trans, root->fs_info->extent_root, 1);
|
|
|
|
+ del_pending_extents(trans, root->fs_info->extent_root, 1);
|
|
|
|
+
|
|
|
|
+ /* is there more work to do? */
|
|
|
|
+ ret = find_first_extent_bit(&root->fs_info->pending_del,
|
|
|
|
+ 0, &start, &end, EXTENT_WRITEBACK);
|
|
|
|
+ if (!ret)
|
|
|
|
+ continue;
|
|
|
|
+ ret = find_first_extent_bit(&root->fs_info->extent_ins,
|
|
|
|
+ 0, &start, &end, EXTENT_WRITEBACK);
|
|
|
|
+ if (!ret)
|
|
|
|
+ continue;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -2211,13 +2228,12 @@ static int finish_current_insert(struct btrfs_trans_handle *trans,
|
|
u64 end;
|
|
u64 end;
|
|
u64 priv;
|
|
u64 priv;
|
|
u64 search = 0;
|
|
u64 search = 0;
|
|
- u64 skipped = 0;
|
|
|
|
struct btrfs_fs_info *info = extent_root->fs_info;
|
|
struct btrfs_fs_info *info = extent_root->fs_info;
|
|
struct btrfs_path *path;
|
|
struct btrfs_path *path;
|
|
struct pending_extent_op *extent_op, *tmp;
|
|
struct pending_extent_op *extent_op, *tmp;
|
|
struct list_head insert_list, update_list;
|
|
struct list_head insert_list, update_list;
|
|
int ret;
|
|
int ret;
|
|
- int num_inserts = 0, max_inserts;
|
|
|
|
|
|
+ int num_inserts = 0, max_inserts, restart = 0;
|
|
|
|
|
|
path = btrfs_alloc_path();
|
|
path = btrfs_alloc_path();
|
|
INIT_LIST_HEAD(&insert_list);
|
|
INIT_LIST_HEAD(&insert_list);
|
|
@@ -2233,19 +2249,19 @@ again:
|
|
ret = find_first_extent_bit(&info->extent_ins, search, &start,
|
|
ret = find_first_extent_bit(&info->extent_ins, search, &start,
|
|
&end, EXTENT_WRITEBACK);
|
|
&end, EXTENT_WRITEBACK);
|
|
if (ret) {
|
|
if (ret) {
|
|
- if (skipped && all && !num_inserts &&
|
|
|
|
|
|
+ if (restart && !num_inserts &&
|
|
list_empty(&update_list)) {
|
|
list_empty(&update_list)) {
|
|
- skipped = 0;
|
|
|
|
|
|
+ restart = 0;
|
|
search = 0;
|
|
search = 0;
|
|
continue;
|
|
continue;
|
|
}
|
|
}
|
|
- mutex_unlock(&info->extent_ins_mutex);
|
|
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
ret = try_lock_extent(&info->extent_ins, start, end, GFP_NOFS);
|
|
ret = try_lock_extent(&info->extent_ins, start, end, GFP_NOFS);
|
|
if (!ret) {
|
|
if (!ret) {
|
|
- skipped = 1;
|
|
|
|
|
|
+ if (all)
|
|
|
|
+ restart = 1;
|
|
search = end + 1;
|
|
search = end + 1;
|
|
if (need_resched()) {
|
|
if (need_resched()) {
|
|
mutex_unlock(&info->extent_ins_mutex);
|
|
mutex_unlock(&info->extent_ins_mutex);
|
|
@@ -2264,7 +2280,7 @@ again:
|
|
list_add_tail(&extent_op->list, &insert_list);
|
|
list_add_tail(&extent_op->list, &insert_list);
|
|
search = end + 1;
|
|
search = end + 1;
|
|
if (num_inserts == max_inserts) {
|
|
if (num_inserts == max_inserts) {
|
|
- mutex_unlock(&info->extent_ins_mutex);
|
|
|
|
|
|
+ restart = 1;
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
} else if (extent_op->type == PENDING_BACKREF_UPDATE) {
|
|
} else if (extent_op->type == PENDING_BACKREF_UPDATE) {
|
|
@@ -2280,7 +2296,6 @@ again:
|
|
* somebody marked this thing for deletion then just unlock it and be
|
|
* somebody marked this thing for deletion then just unlock it and be
|
|
* done, the free_extents will handle it
|
|
* done, the free_extents will handle it
|
|
*/
|
|
*/
|
|
- mutex_lock(&info->extent_ins_mutex);
|
|
|
|
list_for_each_entry_safe(extent_op, tmp, &update_list, list) {
|
|
list_for_each_entry_safe(extent_op, tmp, &update_list, list) {
|
|
clear_extent_bits(&info->extent_ins, extent_op->bytenr,
|
|
clear_extent_bits(&info->extent_ins, extent_op->bytenr,
|
|
extent_op->bytenr + extent_op->num_bytes - 1,
|
|
extent_op->bytenr + extent_op->num_bytes - 1,
|
|
@@ -2302,6 +2317,10 @@ again:
|
|
if (!list_empty(&update_list)) {
|
|
if (!list_empty(&update_list)) {
|
|
ret = update_backrefs(trans, extent_root, path, &update_list);
|
|
ret = update_backrefs(trans, extent_root, path, &update_list);
|
|
BUG_ON(ret);
|
|
BUG_ON(ret);
|
|
|
|
+
|
|
|
|
+ /* we may have COW'ed new blocks, so lets start over */
|
|
|
|
+ if (all)
|
|
|
|
+ restart = 1;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
/*
|
|
@@ -2309,9 +2328,9 @@ again:
|
|
* need to make sure everything is cleaned then reset everything and
|
|
* need to make sure everything is cleaned then reset everything and
|
|
* go back to the beginning
|
|
* go back to the beginning
|
|
*/
|
|
*/
|
|
- if (!num_inserts && all && skipped) {
|
|
|
|
|
|
+ if (!num_inserts && restart) {
|
|
search = 0;
|
|
search = 0;
|
|
- skipped = 0;
|
|
|
|
|
|
+ restart = 0;
|
|
INIT_LIST_HEAD(&update_list);
|
|
INIT_LIST_HEAD(&update_list);
|
|
INIT_LIST_HEAD(&insert_list);
|
|
INIT_LIST_HEAD(&insert_list);
|
|
goto again;
|
|
goto again;
|
|
@@ -2368,27 +2387,19 @@ again:
|
|
BUG_ON(ret);
|
|
BUG_ON(ret);
|
|
|
|
|
|
/*
|
|
/*
|
|
- * if we broke out of the loop in order to insert stuff because we hit
|
|
|
|
- * the maximum number of inserts at a time we can handle, then loop
|
|
|
|
- * back and pick up where we left off
|
|
|
|
|
|
+ * if restart is set for whatever reason we need to go back and start
|
|
|
|
+ * searching through the pending list again.
|
|
|
|
+ *
|
|
|
|
+ * We just inserted some extents, which could have resulted in new
|
|
|
|
+ * blocks being allocated, which would result in new blocks needing
|
|
|
|
+ * updates, so if all is set we _must_ restart to get the updated
|
|
|
|
+ * blocks.
|
|
*/
|
|
*/
|
|
- if (num_inserts == max_inserts) {
|
|
|
|
- INIT_LIST_HEAD(&insert_list);
|
|
|
|
- INIT_LIST_HEAD(&update_list);
|
|
|
|
- num_inserts = 0;
|
|
|
|
- goto again;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /*
|
|
|
|
- * again, if we need to make absolutely sure there are no more pending
|
|
|
|
- * extent operations left and we know that we skipped some, go back to
|
|
|
|
- * the beginning and do it all again
|
|
|
|
- */
|
|
|
|
- if (all && skipped) {
|
|
|
|
|
|
+ if (restart || all) {
|
|
INIT_LIST_HEAD(&insert_list);
|
|
INIT_LIST_HEAD(&insert_list);
|
|
INIT_LIST_HEAD(&update_list);
|
|
INIT_LIST_HEAD(&update_list);
|
|
search = 0;
|
|
search = 0;
|
|
- skipped = 0;
|
|
|
|
|
|
+ restart = 0;
|
|
num_inserts = 0;
|
|
num_inserts = 0;
|
|
goto again;
|
|
goto again;
|
|
}
|
|
}
|
|
@@ -2709,6 +2720,8 @@ again:
|
|
goto again;
|
|
goto again;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ if (!err)
|
|
|
|
+ finish_current_insert(trans, extent_root, 0);
|
|
return err;
|
|
return err;
|
|
}
|
|
}
|
|
|
|
|