* [PATCH v2 1/6] Btrfs: remove residual code in delayed inode async helper
@ 2013-12-26 5:07 Miao Xie
2013-12-26 5:07 ` [PATCH v2 2/6] Btrfs: don't run delayed nodes again after all nodes flush Miao Xie
` (4 more replies)
0 siblings, 5 replies; 11+ messages in thread
From: Miao Xie @ 2013-12-26 5:07 UTC (permalink / raw)
To: linux-btrfs
Before applying the patch
commit de3cb945db4d8eb3b046dc7a5ea89a893372750c
title: Btrfs: improve the delayed inode throttling
We need requeue the async work after the current work was done, it
introduced a deadlock problem. So we wrote the code that this patch
removes to avoid the above problem. But after applying the above
patch, the deadlock problem didn't exist. So we should remove that
fix code.
Signed-off-by: Miao Xie <miaox@cn.fujitsu.com>
---
Changelog v1 -> v2:
- None.
---
fs/btrfs/delayed-inode.c | 27 ---------------------------
1 file changed, 27 deletions(-)
diff --git a/fs/btrfs/delayed-inode.c b/fs/btrfs/delayed-inode.c
index 8d292fb..e832621 100644
--- a/fs/btrfs/delayed-inode.c
+++ b/fs/btrfs/delayed-inode.c
@@ -1300,33 +1300,6 @@ again:
trans->block_rsv = &root->fs_info->delayed_block_rsv;
__btrfs_commit_inode_delayed_items(trans, path, delayed_node);
- /*
- * Maybe new delayed items have been inserted, so we need requeue
- * the work. Besides that, we must dequeue the empty delayed nodes
- * to avoid the race between delayed items balance and the worker.
- * The race like this:
- * Task1 Worker thread
- * count == 0, needn't requeue
- * also needn't insert the
- * delayed node into prepare
- * list again.
- * add lots of delayed items
- * queue the delayed node
- * already in the list,
- * and not in the prepare
- * list, it means the delayed
- * node is being dealt with
- * by the worker.
- * do delayed items balance
- * the delayed node is being
- * dealt with by the worker
- * now, just wait.
- * the worker goto idle.
- * Task1 will sleep until the transaction is commited.
- */
- mutex_lock(&delayed_node->mutex);
- 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);
--
1.8.3.1
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v2 2/6] Btrfs: don't run delayed nodes again after all nodes flush
2013-12-26 5:07 [PATCH v2 1/6] Btrfs: remove residual code in delayed inode async helper Miao Xie
@ 2013-12-26 5:07 ` Miao Xie
2013-12-26 5:07 ` [PATCH v2 3/6] Btrfs: cleanup code of btrfs_balance_delayed_items() Miao Xie
` (3 subsequent siblings)
4 siblings, 0 replies; 11+ messages in thread
From: Miao Xie @ 2013-12-26 5:07 UTC (permalink / raw)
To: linux-btrfs
If the number of the delayed items is greater than the upper limit, we will
try to flush all the delayed items. After that, it is unnecessary to run
them again because they are being dealt with by the wokers or the number of
them is less than the lower limit.
Signed-off-by: Miao Xie <miaox@cn.fujitsu.com>
---
Changelog v1 -> v2:
- None.
---
fs/btrfs/delayed-inode.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/fs/btrfs/delayed-inode.c b/fs/btrfs/delayed-inode.c
index e832621..bb101b0 100644
--- a/fs/btrfs/delayed-inode.c
+++ b/fs/btrfs/delayed-inode.c
@@ -1395,6 +1395,7 @@ void btrfs_balance_delayed_items(struct btrfs_root *root)
break;
}
finish_wait(&delayed_root->wait, &__wait);
+ return;
}
btrfs_wq_run_delayed_node(delayed_root, root, BTRFS_DELAYED_BATCH);
--
1.8.3.1
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v2 3/6] Btrfs: cleanup code of btrfs_balance_delayed_items()
2013-12-26 5:07 [PATCH v2 1/6] Btrfs: remove residual code in delayed inode async helper Miao Xie
2013-12-26 5:07 ` [PATCH v2 2/6] Btrfs: don't run delayed nodes again after all nodes flush Miao Xie
@ 2013-12-26 5:07 ` Miao Xie
2013-12-26 5:07 ` [PATCH v2 4/6] Btrfs: remove btrfs_end_transaction_dmeta() Miao Xie
` (2 subsequent siblings)
4 siblings, 0 replies; 11+ messages in thread
From: Miao Xie @ 2013-12-26 5:07 UTC (permalink / raw)
To: linux-btrfs
- move the condition check for wait into a function
- use wait_event_interruptible instead of prepare-schedule-finish process
Signed-off-by: Miao Xie <miaox@cn.fujitsu.com>
---
Changelog v1 -> v2:
- None.
---
fs/btrfs/delayed-inode.c | 34 +++++++++++-----------------------
1 file changed, 11 insertions(+), 23 deletions(-)
diff --git a/fs/btrfs/delayed-inode.c b/fs/btrfs/delayed-inode.c
index bb101b0..5229106 100644
--- a/fs/btrfs/delayed-inode.c
+++ b/fs/btrfs/delayed-inode.c
@@ -1349,52 +1349,40 @@ 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)
+static int could_end_wait(struct btrfs_delayed_root *delayed_root, int seq)
{
int val = atomic_read(&delayed_root->items_seq);
- if (val < seq || val >= seq + count)
+ if (val < seq || val >= seq + BTRFS_DELAYED_BATCH)
return 1;
+
+ if (atomic_read(&delayed_root->items) < BTRFS_DELAYED_BACKGROUND)
+ 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 seq;
int ret;
- DEFINE_WAIT(__wait);
+
+ seq = atomic_read(&delayed_root->items_seq);
ret = btrfs_wq_run_delayed_node(delayed_root, root, 0);
if (ret)
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);
+ wait_event_interruptible(delayed_root->wait,
+ could_end_wait(delayed_root, seq));
return;
}
--
1.8.3.1
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v2 4/6] Btrfs: remove btrfs_end_transaction_dmeta()
2013-12-26 5:07 [PATCH v2 1/6] Btrfs: remove residual code in delayed inode async helper Miao Xie
2013-12-26 5:07 ` [PATCH v2 2/6] Btrfs: don't run delayed nodes again after all nodes flush Miao Xie
2013-12-26 5:07 ` [PATCH v2 3/6] Btrfs: cleanup code of btrfs_balance_delayed_items() Miao Xie
@ 2013-12-26 5:07 ` Miao Xie
2013-12-26 5:07 ` [PATCH v2 5/6] Btrfs: use flags instead of the bool variants in delayed node Miao Xie
2013-12-26 5:07 ` [PATCH v2 6/6] Btrfs: introduce the delayed inode ref deletion for the single link inode Miao Xie
4 siblings, 0 replies; 11+ messages in thread
From: Miao Xie @ 2013-12-26 5:07 UTC (permalink / raw)
To: linux-btrfs
Two reasons:
- btrfs_end_transaction_dmeta() is the same as btrfs_end_transaction_throttle()
so it is unnecessary.
- All the delayed items should be dealt in the current transaction, so the
workers should not commit the transaction, instead, deal with the delayed
items as many as possible.
So we can remove btrfs_end_transaction_dmeta()
Signed-off-by: Miao Xie <miaox@cn.fujitsu.com>
---
Changelog v1 -> v2:
- Add the detail changelog.
---
fs/btrfs/delayed-inode.c | 2 +-
fs/btrfs/transaction.c | 6 ------
fs/btrfs/transaction.h | 2 --
3 files changed, 1 insertion(+), 9 deletions(-)
diff --git a/fs/btrfs/delayed-inode.c b/fs/btrfs/delayed-inode.c
index 5229106..7d55443 100644
--- a/fs/btrfs/delayed-inode.c
+++ b/fs/btrfs/delayed-inode.c
@@ -1302,7 +1302,7 @@ again:
__btrfs_commit_inode_delayed_items(trans, path, delayed_node);
trans->block_rsv = block_rsv;
- btrfs_end_transaction_dmeta(trans, root);
+ btrfs_end_transaction(trans, root);
btrfs_btree_balance_dirty_nodelay(root);
release_path:
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index c6a872a..df919b4 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -788,12 +788,6 @@ int btrfs_end_transaction_throttle(struct btrfs_trans_handle *trans,
return __btrfs_end_transaction(trans, root, 1);
}
-int btrfs_end_transaction_dmeta(struct btrfs_trans_handle *trans,
- struct btrfs_root *root)
-{
- return __btrfs_end_transaction(trans, root, 1);
-}
-
/*
* when btree blocks are allocated, they have some corresponding bits set for
* them in one of two extent_io trees. This is used to make sure all of
diff --git a/fs/btrfs/transaction.h b/fs/btrfs/transaction.h
index 7657d11..d05b601 100644
--- a/fs/btrfs/transaction.h
+++ b/fs/btrfs/transaction.h
@@ -154,8 +154,6 @@ int btrfs_commit_transaction_async(struct btrfs_trans_handle *trans,
int wait_for_unblock);
int btrfs_end_transaction_throttle(struct btrfs_trans_handle *trans,
struct btrfs_root *root);
-int btrfs_end_transaction_dmeta(struct btrfs_trans_handle *trans,
- struct btrfs_root *root);
int btrfs_should_end_transaction(struct btrfs_trans_handle *trans,
struct btrfs_root *root);
void btrfs_throttle(struct btrfs_root *root);
--
1.8.3.1
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v2 5/6] Btrfs: use flags instead of the bool variants in delayed node
2013-12-26 5:07 [PATCH v2 1/6] Btrfs: remove residual code in delayed inode async helper Miao Xie
` (2 preceding siblings ...)
2013-12-26 5:07 ` [PATCH v2 4/6] Btrfs: remove btrfs_end_transaction_dmeta() Miao Xie
@ 2013-12-26 5:07 ` Miao Xie
2014-01-02 17:49 ` David Sterba
2013-12-26 5:07 ` [PATCH v2 6/6] Btrfs: introduce the delayed inode ref deletion for the single link inode Miao Xie
4 siblings, 1 reply; 11+ messages in thread
From: Miao Xie @ 2013-12-26 5:07 UTC (permalink / raw)
To: linux-btrfs
Signed-off-by: Miao Xie <miaox@cn.fujitsu.com>
---
Changelog v1 -> v2:
- None.
---
fs/btrfs/delayed-inode.c | 33 +++++++++++++++++----------------
fs/btrfs/delayed-inode.h | 6 ++++--
2 files changed, 21 insertions(+), 18 deletions(-)
diff --git a/fs/btrfs/delayed-inode.c b/fs/btrfs/delayed-inode.c
index 7d55443..979db56 100644
--- a/fs/btrfs/delayed-inode.c
+++ b/fs/btrfs/delayed-inode.c
@@ -55,8 +55,7 @@ static inline void btrfs_init_delayed_node(
delayed_node->inode_id = inode_id;
atomic_set(&delayed_node->refs, 0);
delayed_node->count = 0;
- delayed_node->in_list = 0;
- delayed_node->inode_dirty = 0;
+ delayed_node->flags = 0;
delayed_node->ins_root = RB_ROOT;
delayed_node->del_root = RB_ROOT;
mutex_init(&delayed_node->mutex);
@@ -172,7 +171,7 @@ static void btrfs_queue_delayed_node(struct btrfs_delayed_root *root,
int mod)
{
spin_lock(&root->lock);
- if (node->in_list) {
+ if (test_bit(BTRFS_DELAYED_NODE_IN_LIST, &node->flags)) {
if (!list_empty(&node->p_list))
list_move_tail(&node->p_list, &root->prepare_list);
else if (mod)
@@ -182,7 +181,7 @@ static void btrfs_queue_delayed_node(struct btrfs_delayed_root *root,
list_add_tail(&node->p_list, &root->prepare_list);
atomic_inc(&node->refs); /* inserted into list */
root->nodes++;
- node->in_list = 1;
+ set_bit(BTRFS_DELAYED_NODE_IN_LIST, &node->flags);
}
spin_unlock(&root->lock);
}
@@ -192,13 +191,13 @@ static void btrfs_dequeue_delayed_node(struct btrfs_delayed_root *root,
struct btrfs_delayed_node *node)
{
spin_lock(&root->lock);
- if (node->in_list) {
+ if (test_bit(BTRFS_DELAYED_NODE_IN_LIST, &node->flags)) {
root->nodes--;
atomic_dec(&node->refs); /* not in the list */
list_del_init(&node->n_list);
if (!list_empty(&node->p_list))
list_del_init(&node->p_list);
- node->in_list = 0;
+ clear_bit(BTRFS_DELAYED_NODE_IN_LIST, &node->flags);
}
spin_unlock(&root->lock);
}
@@ -231,7 +230,8 @@ static struct btrfs_delayed_node *btrfs_next_delayed_node(
delayed_root = node->root->fs_info->delayed_root;
spin_lock(&delayed_root->lock);
- if (!node->in_list) { /* not in the list */
+ if (!test_bit(BTRFS_DELAYED_NODE_IN_LIST, &node->flags)) {
+ /* not in the list */
if (list_empty(&delayed_root->node_list))
goto out;
p = delayed_root->node_list.next;
@@ -1004,9 +1004,10 @@ static void btrfs_release_delayed_inode(struct btrfs_delayed_node *delayed_node)
{
struct btrfs_delayed_root *delayed_root;
- if (delayed_node && delayed_node->inode_dirty) {
+ if (delayed_node &&
+ test_bit(BTRFS_DELAYED_NODE_INODE_DIRTY, &delayed_node->flags)) {
BUG_ON(!delayed_node->root);
- delayed_node->inode_dirty = 0;
+ clear_bit(BTRFS_DELAYED_NODE_INODE_DIRTY, &delayed_node->flags);
delayed_node->count--;
delayed_root = delayed_node->root->fs_info->delayed_root;
@@ -1059,7 +1060,7 @@ static inline int btrfs_update_delayed_inode(struct btrfs_trans_handle *trans,
int ret;
mutex_lock(&node->mutex);
- if (!node->inode_dirty) {
+ if (!test_bit(BTRFS_DELAYED_NODE_INODE_DIRTY, &node->flags)) {
mutex_unlock(&node->mutex);
return 0;
}
@@ -1203,7 +1204,7 @@ int btrfs_commit_inode_delayed_inode(struct inode *inode)
return 0;
mutex_lock(&delayed_node->mutex);
- if (!delayed_node->inode_dirty) {
+ if (!test_bit(BTRFS_DELAYED_NODE_INODE_DIRTY, &delayed_node->flags)) {
mutex_unlock(&delayed_node->mutex);
btrfs_release_delayed_node(delayed_node);
return 0;
@@ -1227,7 +1228,7 @@ int btrfs_commit_inode_delayed_inode(struct inode *inode)
trans->block_rsv = &delayed_node->root->fs_info->delayed_block_rsv;
mutex_lock(&delayed_node->mutex);
- if (delayed_node->inode_dirty)
+ if (test_bit(BTRFS_DELAYED_NODE_INODE_DIRTY, &delayed_node->flags))
ret = __btrfs_update_delayed_inode(trans, delayed_node->root,
path, delayed_node);
else
@@ -1721,7 +1722,7 @@ int btrfs_fill_inode(struct inode *inode, u32 *rdev)
return -ENOENT;
mutex_lock(&delayed_node->mutex);
- if (!delayed_node->inode_dirty) {
+ if (!test_bit(BTRFS_DELAYED_NODE_INODE_DIRTY, &delayed_node->flags)) {
mutex_unlock(&delayed_node->mutex);
btrfs_release_delayed_node(delayed_node);
return -ENOENT;
@@ -1772,7 +1773,7 @@ int btrfs_delayed_update_inode(struct btrfs_trans_handle *trans,
return PTR_ERR(delayed_node);
mutex_lock(&delayed_node->mutex);
- if (delayed_node->inode_dirty) {
+ if (test_bit(BTRFS_DELAYED_NODE_INODE_DIRTY, &delayed_node->flags)) {
fill_stack_inode_item(trans, &delayed_node->inode_item, inode);
goto release_node;
}
@@ -1783,7 +1784,7 @@ int btrfs_delayed_update_inode(struct btrfs_trans_handle *trans,
goto release_node;
fill_stack_inode_item(trans, &delayed_node->inode_item, inode);
- delayed_node->inode_dirty = 1;
+ set_bit(BTRFS_DELAYED_NODE_INODE_DIRTY, &delayed_node->flags);
delayed_node->count++;
atomic_inc(&root->fs_info->delayed_root->items);
release_node:
@@ -1814,7 +1815,7 @@ static void __btrfs_kill_delayed_node(struct btrfs_delayed_node *delayed_node)
btrfs_release_delayed_item(prev_item);
}
- if (delayed_node->inode_dirty) {
+ if (test_bit(BTRFS_DELAYED_NODE_INODE_DIRTY, &delayed_node->flags)) {
btrfs_delayed_inode_release_metadata(root, delayed_node);
btrfs_release_delayed_inode(delayed_node);
}
diff --git a/fs/btrfs/delayed-inode.h b/fs/btrfs/delayed-inode.h
index a4b38f9..a6a13f7 100644
--- a/fs/btrfs/delayed-inode.h
+++ b/fs/btrfs/delayed-inode.h
@@ -48,6 +48,9 @@ struct btrfs_delayed_root {
wait_queue_head_t wait;
};
+#define BTRFS_DELAYED_NODE_IN_LIST 0
+#define BTRFS_DELAYED_NODE_INODE_DIRTY 1
+
struct btrfs_delayed_node {
u64 inode_id;
u64 bytes_reserved;
@@ -65,8 +68,7 @@ struct btrfs_delayed_node {
struct btrfs_inode_item inode_item;
atomic_t refs;
u64 index_cnt;
- bool in_list;
- bool inode_dirty;
+ unsigned long flags;
int count;
};
--
1.8.3.1
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v2 6/6] Btrfs: introduce the delayed inode ref deletion for the single link inode
2013-12-26 5:07 [PATCH v2 1/6] Btrfs: remove residual code in delayed inode async helper Miao Xie
` (3 preceding siblings ...)
2013-12-26 5:07 ` [PATCH v2 5/6] Btrfs: use flags instead of the bool variants in delayed node Miao Xie
@ 2013-12-26 5:07 ` Miao Xie
4 siblings, 0 replies; 11+ messages in thread
From: Miao Xie @ 2013-12-26 5:07 UTC (permalink / raw)
To: linux-btrfs
The inode reference item is close to inode item, so we insert it simultaneously
with the inode item insertion when we create a file/directory.. In fact, we also
can handle the inode reference deletion by the same way. So we made this patch to
introduce the delayed inode reference deletion for the single link inode(At most
case, the file doesn't has hard link, so we don't take the hard link into account).
This function is based on the delayed inode mechanism. After applying this patch,
we can reduce the time of the file/directory deletion by ~10%.
Signed-off-by: Miao Xie <miaox@cn.fujitsu.com>
---
Changelog v1 -> v2:
- Use ASSERT instead of BUG_ON(), pointed by Josef.
---
fs/btrfs/btrfs_inode.h | 3 ++
fs/btrfs/delayed-inode.c | 103 +++++++++++++++++++++++++++++++++++++++++++++--
fs/btrfs/delayed-inode.h | 2 +
fs/btrfs/inode.c | 55 ++++++++++++++++++++++++-
4 files changed, 157 insertions(+), 6 deletions(-)
diff --git a/fs/btrfs/btrfs_inode.h b/fs/btrfs/btrfs_inode.h
index ac0b39d..661b0ac 100644
--- a/fs/btrfs/btrfs_inode.h
+++ b/fs/btrfs/btrfs_inode.h
@@ -135,6 +135,9 @@ struct btrfs_inode {
*/
u64 index_cnt;
+ /* Cache the directory index number to speed the dir/file remove */
+ u64 dir_index;
+
/* the fsync log has some corner cases that mean we have to check
* directories to see if any unlinks have been done before
* the directory was logged. See tree-log.c for all the
diff --git a/fs/btrfs/delayed-inode.c b/fs/btrfs/delayed-inode.c
index 979db56..a79a363 100644
--- a/fs/btrfs/delayed-inode.c
+++ b/fs/btrfs/delayed-inode.c
@@ -1015,6 +1015,18 @@ static void btrfs_release_delayed_inode(struct btrfs_delayed_node *delayed_node)
}
}
+static void btrfs_release_delayed_iref(struct btrfs_delayed_node *delayed_node)
+{
+ struct btrfs_delayed_root *delayed_root;
+
+ ASSERT(delayed_node->root);
+ clear_bit(BTRFS_DELAYED_NODE_DEL_IREF, &delayed_node->flags);
+ delayed_node->count--;
+
+ delayed_root = delayed_node->root->fs_info->delayed_root;
+ finish_one_item(delayed_root);
+}
+
static int __btrfs_update_delayed_inode(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_path *path,
@@ -1023,13 +1035,19 @@ static int __btrfs_update_delayed_inode(struct btrfs_trans_handle *trans,
struct btrfs_key key;
struct btrfs_inode_item *inode_item;
struct extent_buffer *leaf;
+ int mod;
int ret;
key.objectid = node->inode_id;
btrfs_set_key_type(&key, BTRFS_INODE_ITEM_KEY);
key.offset = 0;
- ret = btrfs_lookup_inode(trans, root, path, &key, 1);
+ if (test_bit(BTRFS_DELAYED_NODE_DEL_IREF, &node->flags))
+ mod = -1;
+ else
+ mod = 1;
+
+ ret = btrfs_lookup_inode(trans, root, path, &key, mod);
if (ret > 0) {
btrfs_release_path(path);
return -ENOENT;
@@ -1037,19 +1055,58 @@ static int __btrfs_update_delayed_inode(struct btrfs_trans_handle *trans,
return ret;
}
- btrfs_unlock_up_safe(path, 1);
leaf = path->nodes[0];
inode_item = btrfs_item_ptr(leaf, path->slots[0],
struct btrfs_inode_item);
write_extent_buffer(leaf, &node->inode_item, (unsigned long)inode_item,
sizeof(struct btrfs_inode_item));
btrfs_mark_buffer_dirty(leaf);
- btrfs_release_path(path);
+ if (!test_bit(BTRFS_DELAYED_NODE_DEL_IREF, &node->flags))
+ goto no_iref;
+
+ path->slots[0]++;
+ if (path->slots[0] >= btrfs_header_nritems(leaf))
+ goto search;
+again:
+ btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
+ if (key.objectid != node->inode_id)
+ goto out;
+
+ if (key.type != BTRFS_INODE_REF_KEY &&
+ key.type != BTRFS_INODE_EXTREF_KEY)
+ goto out;
+
+ /*
+ * Delayed iref deletion is for the inode who has only one link,
+ * so there is only one iref. The case that several irefs are
+ * in the same item doesn't exist.
+ */
+ btrfs_del_item(trans, root, path);
+out:
+ btrfs_release_delayed_iref(node);
+no_iref:
+ btrfs_release_path(path);
+err_out:
btrfs_delayed_inode_release_metadata(root, node);
btrfs_release_delayed_inode(node);
- return 0;
+ return ret;
+
+search:
+ btrfs_release_path(path);
+
+ btrfs_set_key_type(&key, BTRFS_INODE_EXTREF_KEY);
+ key.offset = -1;
+ ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
+ if (ret < 0)
+ goto err_out;
+ ASSERT(ret);
+
+ ret = 0;
+ leaf = path->nodes[0];
+ path->slots[0]--;
+ goto again;
}
static inline int btrfs_update_delayed_inode(struct btrfs_trans_handle *trans,
@@ -1793,6 +1850,41 @@ release_node:
return ret;
}
+int btrfs_delayed_delete_inode_ref(struct inode *inode)
+{
+ struct btrfs_delayed_node *delayed_node;
+
+ delayed_node = btrfs_get_or_create_delayed_node(inode);
+ if (IS_ERR(delayed_node))
+ return PTR_ERR(delayed_node);
+
+ /*
+ * We don't reserve space for inode ref deletion is because:
+ * - We ONLY do async inode ref deletion for the inode who has only
+ * one link(i_nlink == 1), it means there is only one inode ref.
+ * And in most case, the inode ref and the inode item are in the
+ * same leaf, and we will deal with them at the same time.
+ * Since we are sure we will reserve the space for the inode item,
+ * it is unnecessary to reserve space for inode ref deletion.
+ * - If the inode ref and the inode item are not in the same leaf,
+ * We also needn't worry about enospc problem, because we reserve
+ * much more space for the inode update than it needs.
+ * - At the worst, we can steal some space from the global reservation.
+ * It is very rare.
+ */
+ mutex_lock(&delayed_node->mutex);
+ if (test_bit(BTRFS_DELAYED_NODE_DEL_IREF, &delayed_node->flags))
+ goto release_node;
+
+ set_bit(BTRFS_DELAYED_NODE_DEL_IREF, &delayed_node->flags);
+ delayed_node->count++;
+ atomic_inc(&BTRFS_I(inode)->root->fs_info->delayed_root->items);
+release_node:
+ mutex_unlock(&delayed_node->mutex);
+ btrfs_release_delayed_node(delayed_node);
+ return 0;
+}
+
static void __btrfs_kill_delayed_node(struct btrfs_delayed_node *delayed_node)
{
struct btrfs_root *root = delayed_node->root;
@@ -1815,6 +1907,9 @@ static void __btrfs_kill_delayed_node(struct btrfs_delayed_node *delayed_node)
btrfs_release_delayed_item(prev_item);
}
+ if (test_bit(BTRFS_DELAYED_NODE_DEL_IREF, &delayed_node->flags))
+ btrfs_release_delayed_iref(delayed_node);
+
if (test_bit(BTRFS_DELAYED_NODE_INODE_DIRTY, &delayed_node->flags)) {
btrfs_delayed_inode_release_metadata(root, delayed_node);
btrfs_release_delayed_inode(delayed_node);
diff --git a/fs/btrfs/delayed-inode.h b/fs/btrfs/delayed-inode.h
index a6a13f7..f70119f 100644
--- a/fs/btrfs/delayed-inode.h
+++ b/fs/btrfs/delayed-inode.h
@@ -50,6 +50,7 @@ struct btrfs_delayed_root {
#define BTRFS_DELAYED_NODE_IN_LIST 0
#define BTRFS_DELAYED_NODE_INODE_DIRTY 1
+#define BTRFS_DELAYED_NODE_DEL_IREF 2
struct btrfs_delayed_node {
u64 inode_id;
@@ -127,6 +128,7 @@ int btrfs_commit_inode_delayed_inode(struct inode *inode);
int btrfs_delayed_update_inode(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct inode *inode);
int btrfs_fill_inode(struct inode *inode, u32 *rdev);
+int btrfs_delayed_delete_inode_ref(struct inode *inode);
/* Used for drop dead root */
void btrfs_kill_all_delayed_nodes(struct btrfs_root *root);
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index f1a7744..daa1490 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -3315,6 +3315,7 @@ static void btrfs_read_locked_inode(struct inode *inode)
struct btrfs_timespec *tspec;
struct btrfs_root *root = BTRFS_I(inode)->root;
struct btrfs_key location;
+ unsigned long ptr;
int maybe_acls;
u32 rdev;
int ret;
@@ -3338,7 +3339,7 @@ static void btrfs_read_locked_inode(struct inode *inode)
leaf = path->nodes[0];
if (filled)
- goto cache_acl;
+ goto cache_index;
inode_item = btrfs_item_ptr(leaf, path->slots[0],
struct btrfs_inode_item);
@@ -3381,6 +3382,30 @@ static void btrfs_read_locked_inode(struct inode *inode)
BTRFS_I(inode)->index_cnt = (u64)-1;
BTRFS_I(inode)->flags = btrfs_inode_flags(leaf, inode_item);
+
+cache_index:
+ path->slots[0]++;
+ if (inode->i_nlink != 1 ||
+ path->slots[0] >= btrfs_header_nritems(leaf))
+ goto cache_acl;
+
+ btrfs_item_key_to_cpu(leaf, &location, path->slots[0]);
+ if (location.objectid != btrfs_ino(inode))
+ goto cache_acl;
+
+ ptr = btrfs_item_ptr_offset(leaf, path->slots[0]);
+ if (location.type == BTRFS_INODE_REF_KEY) {
+ struct btrfs_inode_ref *ref;
+
+ ref = (struct btrfs_inode_ref *)ptr;
+ BTRFS_I(inode)->dir_index = btrfs_inode_ref_index(leaf, ref);
+ } else if (location.type == BTRFS_INODE_EXTREF_KEY) {
+ struct btrfs_inode_extref *extref;
+
+ extref = (struct btrfs_inode_extref *)ptr;
+ BTRFS_I(inode)->dir_index = btrfs_inode_extref_index(leaf,
+ extref);
+ }
cache_acl:
/*
* try to precache a NULL acl entry for files that don't have
@@ -3593,6 +3618,24 @@ static int __btrfs_unlink_inode(struct btrfs_trans_handle *trans,
goto err;
btrfs_release_path(path);
+ /*
+ * If we don't have dir index, we have to get it by looking up
+ * the inode ref, since we get the inode ref, remove it directly,
+ * it is unnecessary to do delayed deletion.
+ *
+ * But if we have dir index, needn't search inode ref to get it.
+ * Since the inode ref is close to the inode item, it is better
+ * that we delay to delete it, and just do this deletion when
+ * we update the inode item.
+ */
+ if (BTRFS_I(inode)->dir_index) {
+ ret = btrfs_delayed_delete_inode_ref(inode);
+ if (!ret) {
+ index = BTRFS_I(inode)->dir_index;
+ goto skip_backref;
+ }
+ }
+
ret = btrfs_del_inode_ref(trans, root, name, name_len, ino,
dir_ino, &index);
if (ret) {
@@ -3602,7 +3645,7 @@ static int __btrfs_unlink_inode(struct btrfs_trans_handle *trans,
btrfs_abort_transaction(trans, root, ret);
goto err;
}
-
+skip_backref:
ret = btrfs_delete_delayed_dir_index(trans, root, dir, index);
if (ret) {
btrfs_abort_transaction(trans, root, ret);
@@ -5388,6 +5431,7 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
* number
*/
BTRFS_I(inode)->index_cnt = 2;
+ BTRFS_I(inode)->dir_index = *index;
BTRFS_I(inode)->root = root;
BTRFS_I(inode)->generation = trans->transid;
inode->i_generation = BTRFS_I(inode)->generation;
@@ -5737,6 +5781,8 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir,
goto fail;
}
+ /* There are several dir indexes for this inode, clear the cache. */
+ BTRFS_I(inode)->dir_index = 0ULL;
inc_nlink(inode);
inode_inc_iversion(inode);
inode->i_ctime = CURRENT_TIME;
@@ -7776,6 +7822,7 @@ struct inode *btrfs_alloc_inode(struct super_block *sb)
ei->flags = 0;
ei->csum_bytes = 0;
ei->index_cnt = (u64)-1;
+ ei->dir_index = 0;
ei->last_unlink_trans = 0;
ei->last_log_commit = 0;
@@ -8063,6 +8110,7 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry,
if (ret)
goto out_fail;
+ BTRFS_I(old_inode)->dir_index = 0ULL;
if (unlikely(old_ino == BTRFS_FIRST_FREE_OBJECTID)) {
/* force full log commit if subvolume involved. */
root->fs_info->last_trans_log_full_commit = trans->transid;
@@ -8151,6 +8199,9 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry,
goto out_fail;
}
+ if (old_inode->i_nlink == 1)
+ BTRFS_I(old_inode)->dir_index = index;
+
if (old_ino != BTRFS_FIRST_FREE_OBJECTID) {
struct dentry *parent = new_dentry->d_parent;
btrfs_log_new_name(trans, old_inode, old_dir, parent);
--
1.8.3.1
^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH v2 5/6] Btrfs: use flags instead of the bool variants in delayed node
2013-12-26 5:07 ` [PATCH v2 5/6] Btrfs: use flags instead of the bool variants in delayed node Miao Xie
@ 2014-01-02 17:49 ` David Sterba
2014-01-03 9:27 ` Miao Xie
0 siblings, 1 reply; 11+ messages in thread
From: David Sterba @ 2014-01-02 17:49 UTC (permalink / raw)
To: Miao Xie; +Cc: linux-btrfs
On Thu, Dec 26, 2013 at 01:07:05PM +0800, Miao Xie wrote:
> +#define BTRFS_DELAYED_NODE_IN_LIST 0
> +#define BTRFS_DELAYED_NODE_INODE_DIRTY 1
> +
> struct btrfs_delayed_node {
> u64 inode_id;
> u64 bytes_reserved;
> @@ -65,8 +68,7 @@ struct btrfs_delayed_node {
> struct btrfs_inode_item inode_item;
> atomic_t refs;
> u64 index_cnt;
> - bool in_list;
> - bool inode_dirty;
> + unsigned long flags;
> int count;
> };
What's the reason to do that? Replacing 2 bools with a bitfield
does not seem justified, not from saving memory, nor from a performance
gain side. Also some of the bit operations imply the lock instruction
prefix so this affects the surrounding items as well.
I don't think this is needed, unless you have further plans with the
flags item.
david
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v2 5/6] Btrfs: use flags instead of the bool variants in delayed node
2014-01-02 17:49 ` David Sterba
@ 2014-01-03 9:27 ` Miao Xie
2014-01-03 18:36 ` David Sterba
0 siblings, 1 reply; 11+ messages in thread
From: Miao Xie @ 2014-01-03 9:27 UTC (permalink / raw)
To: dsterba, linux-btrfs
On Thu, 2 Jan 2014 18:49:55 +0100, David Sterba wrote:
> On Thu, Dec 26, 2013 at 01:07:05PM +0800, Miao Xie wrote:
>> +#define BTRFS_DELAYED_NODE_IN_LIST 0
>> +#define BTRFS_DELAYED_NODE_INODE_DIRTY 1
>> +
>> struct btrfs_delayed_node {
>> u64 inode_id;
>> u64 bytes_reserved;
>> @@ -65,8 +68,7 @@ struct btrfs_delayed_node {
>> struct btrfs_inode_item inode_item;
>> atomic_t refs;
>> u64 index_cnt;
>> - bool in_list;
>> - bool inode_dirty;
>> + unsigned long flags;
>> int count;
>> };
>
> What's the reason to do that? Replacing 2 bools with a bitfield
> does not seem justified, not from saving memory, nor from a performance
> gain side. Also some of the bit operations imply the lock instruction
> prefix so this affects the surrounding items as well.
>
> I don't think this is needed, unless you have further plans with the
> flags item.
Yes, I introduced a flag in the next patch.
And we can not common bit operation here because we hold different locks when we change
those bits, we have to use the bit operations which implies the lock instruction.
Thanks
Miao
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v2 5/6] Btrfs: use flags instead of the bool variants in delayed node
2014-01-03 9:27 ` Miao Xie
@ 2014-01-03 18:36 ` David Sterba
2014-01-07 3:59 ` Miao Xie
0 siblings, 1 reply; 11+ messages in thread
From: David Sterba @ 2014-01-03 18:36 UTC (permalink / raw)
To: Miao Xie; +Cc: dsterba, linux-btrfs
On Fri, Jan 03, 2014 at 05:27:51PM +0800, Miao Xie wrote:
> On Thu, 2 Jan 2014 18:49:55 +0100, David Sterba wrote:
> > On Thu, Dec 26, 2013 at 01:07:05PM +0800, Miao Xie wrote:
> >> +#define BTRFS_DELAYED_NODE_IN_LIST 0
> >> +#define BTRFS_DELAYED_NODE_INODE_DIRTY 1
> >> +
> >> struct btrfs_delayed_node {
> >> u64 inode_id;
> >> u64 bytes_reserved;
> >> @@ -65,8 +68,7 @@ struct btrfs_delayed_node {
> >> struct btrfs_inode_item inode_item;
> >> atomic_t refs;
> >> u64 index_cnt;
> >> - bool in_list;
> >> - bool inode_dirty;
> >> + unsigned long flags;
> >> int count;
> >> };
> >
> > What's the reason to do that? Replacing 2 bools with a bitfield
> > does not seem justified, not from saving memory, nor from a performance
> > gain side. Also some of the bit operations imply the lock instruction
> > prefix so this affects the surrounding items as well.
> >
> > I don't think this is needed, unless you have further plans with the
> > flags item.
>
> Yes, I introduced a flag in the next patch.
That's still 3 bool flags that are quite independent and consume less
than the unsigned long anyway. Also the bool flags are something that
compiler understands and can use during optimizations unlike the
obfuscated bit access.
I don't mind using bitfields, but it imo starts to make sense to use
them when there are more than a few, like BTRFS_INODE_* or
EXTENT_BUFFER_*. The point of my objections is to establish good coding
patterns to follow.
david
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v2 5/6] Btrfs: use flags instead of the bool variants in delayed node
2014-01-03 18:36 ` David Sterba
@ 2014-01-07 3:59 ` Miao Xie
2014-01-07 21:11 ` David Sterba
0 siblings, 1 reply; 11+ messages in thread
From: Miao Xie @ 2014-01-07 3:59 UTC (permalink / raw)
To: dsterba, linux-btrfs
On Fri, 3 Jan 2014 19:36:10 +0100, David Sterba wrote:
> On Fri, Jan 03, 2014 at 05:27:51PM +0800, Miao Xie wrote:
>> On Thu, 2 Jan 2014 18:49:55 +0100, David Sterba wrote:
>>> On Thu, Dec 26, 2013 at 01:07:05PM +0800, Miao Xie wrote:
>>>> +#define BTRFS_DELAYED_NODE_IN_LIST 0
>>>> +#define BTRFS_DELAYED_NODE_INODE_DIRTY 1
>>>> +
>>>> struct btrfs_delayed_node {
>>>> u64 inode_id;
>>>> u64 bytes_reserved;
>>>> @@ -65,8 +68,7 @@ struct btrfs_delayed_node {
>>>> struct btrfs_inode_item inode_item;
>>>> atomic_t refs;
>>>> u64 index_cnt;
>>>> - bool in_list;
>>>> - bool inode_dirty;
>>>> + unsigned long flags;
>>>> int count;
>>>> };
>>>
>>> What's the reason to do that? Replacing 2 bools with a bitfield
>>> does not seem justified, not from saving memory, nor from a performance
>>> gain side. Also some of the bit operations imply the lock instruction
>>> prefix so this affects the surrounding items as well.
>>>
>>> I don't think this is needed, unless you have further plans with the
>>> flags item.
>>
>> Yes, I introduced a flag in the next patch.
>
> That's still 3 bool flags that are quite independent and consume less
> than the unsigned long anyway. Also the bool flags are something that
> compiler understands and can use during optimizations unlike the
> obfuscated bit access.
I made a mistake at the beginning, I though the size of boolean data type
in the kernel was 4 bytes because I saw it was implemented by the enumeration
type several years ago. But it has been changed for many years. So you are right.
But I read a discuss about the use of boolean type, some developers suggested
us to use bitfields instead of bool, because the bitfields can work better,
and they are more flexible, less misuse than bool.
https://lkml.org/lkml/2013/9/1/154
Furthermore, we may introduce more flags in the future though I have no plan now.
So this patch makes sense I think.
Thanks
Miao
> I don't mind using bitfields, but it imo starts to make sense to use
> them when there are more than a few, like BTRFS_INODE_* or
> EXTENT_BUFFER_*. The point of my objections is to establish good coding
> patterns to follow.
>
> david
>
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v2 5/6] Btrfs: use flags instead of the bool variants in delayed node
2014-01-07 3:59 ` Miao Xie
@ 2014-01-07 21:11 ` David Sterba
0 siblings, 0 replies; 11+ messages in thread
From: David Sterba @ 2014-01-07 21:11 UTC (permalink / raw)
To: Miao Xie; +Cc: linux-btrfs
On Tue, Jan 07, 2014 at 11:59:18AM +0800, Miao Xie wrote:
> But I read a discuss about the use of boolean type, some developers suggested
> us to use bitfields instead of bool, because the bitfields can work better,
> and they are more flexible, less misuse than bool.
> https://lkml.org/lkml/2013/9/1/154
I was searching for pros/cons of the bools but haven't found this one
nor anything useful, though not all of the advantages of bitfields apply
in our case.
I've compared the generated assembly with just this patch, and the
difference is effectively only the lock prefix for set/clear, the read
side has no significant penalty:
old:
mov 0x128(%rbx),%esi
new:
mov 0x120(%rbx),%rax
test $0x1,%al
old set:
movb $0x1,0x120(%rbx)
new:
lock orb $0x1,0x120(%rbx)
The delayed_node structure is relatively short lived, is reused
frequently and I haven't seen any contention points where the lock
prefix would hurt.
So, ok to merge it.
^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2014-01-07 21:11 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-12-26 5:07 [PATCH v2 1/6] Btrfs: remove residual code in delayed inode async helper Miao Xie
2013-12-26 5:07 ` [PATCH v2 2/6] Btrfs: don't run delayed nodes again after all nodes flush Miao Xie
2013-12-26 5:07 ` [PATCH v2 3/6] Btrfs: cleanup code of btrfs_balance_delayed_items() Miao Xie
2013-12-26 5:07 ` [PATCH v2 4/6] Btrfs: remove btrfs_end_transaction_dmeta() Miao Xie
2013-12-26 5:07 ` [PATCH v2 5/6] Btrfs: use flags instead of the bool variants in delayed node Miao Xie
2014-01-02 17:49 ` David Sterba
2014-01-03 9:27 ` Miao Xie
2014-01-03 18:36 ` David Sterba
2014-01-07 3:59 ` Miao Xie
2014-01-07 21:11 ` David Sterba
2013-12-26 5:07 ` [PATCH v2 6/6] Btrfs: introduce the delayed inode ref deletion for the single link inode Miao Xie
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.