瀏覽代碼

Btrfs: adjust the write_lock_level as we unlock

btrfs_search_slot sometimes needs write locks on high levels of
the tree.  It remembers the highest level that needs a write lock
and will use that for all future searches through the tree in a given
call.

But, very often we'll just cow the top level or the level below and we
won't really need write locks on the root again after that.  This patch
changes things to adjust the write lock requirement as it unlocks
levels.

Signed-off-by: Chris Mason <chris.mason@oracle.com>
Chris Mason 13 年之前
父節點
當前提交
f7c79f30cb
共有 1 個文件被更改,包括 17 次插入6 次删除
  1. 17 6
      fs/btrfs/ctree.c

+ 17 - 6
fs/btrfs/ctree.c

@@ -1395,7 +1395,8 @@ static noinline int reada_for_balance(struct btrfs_root *root,
  * if lowest_unlock is 1, level 0 won't be unlocked
  * if lowest_unlock is 1, level 0 won't be unlocked
  */
  */
 static noinline void unlock_up(struct btrfs_path *path, int level,
 static noinline void unlock_up(struct btrfs_path *path, int level,
-			       int lowest_unlock)
+			       int lowest_unlock, int min_write_lock_level,
+			       int *write_lock_level)
 {
 {
 	int i;
 	int i;
 	int skip_level = level;
 	int skip_level = level;
@@ -1427,6 +1428,11 @@ static noinline void unlock_up(struct btrfs_path *path, int level,
 		if (i >= lowest_unlock && i > skip_level && path->locks[i]) {
 		if (i >= lowest_unlock && i > skip_level && path->locks[i]) {
 			btrfs_tree_unlock_rw(t, path->locks[i]);
 			btrfs_tree_unlock_rw(t, path->locks[i]);
 			path->locks[i] = 0;
 			path->locks[i] = 0;
+			if (write_lock_level &&
+			    i > min_write_lock_level &&
+			    i <= *write_lock_level) {
+				*write_lock_level = i - 1;
+			}
 		}
 		}
 	}
 	}
 }
 }
@@ -1650,6 +1656,7 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root
 	/* everything at write_lock_level or lower must be write locked */
 	/* everything at write_lock_level or lower must be write locked */
 	int write_lock_level = 0;
 	int write_lock_level = 0;
 	u8 lowest_level = 0;
 	u8 lowest_level = 0;
+	int min_write_lock_level;
 
 
 	lowest_level = p->lowest_level;
 	lowest_level = p->lowest_level;
 	WARN_ON(lowest_level && ins_len > 0);
 	WARN_ON(lowest_level && ins_len > 0);
@@ -1677,6 +1684,8 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root
 	if (cow && (p->keep_locks || p->lowest_level))
 	if (cow && (p->keep_locks || p->lowest_level))
 		write_lock_level = BTRFS_MAX_LEVEL;
 		write_lock_level = BTRFS_MAX_LEVEL;
 
 
+	min_write_lock_level = write_lock_level;
+
 again:
 again:
 	/*
 	/*
 	 * we try very hard to do read locks on the root
 	 * we try very hard to do read locks on the root
@@ -1808,7 +1817,8 @@ cow_done:
 				goto again;
 				goto again;
 			}
 			}
 
 
-			unlock_up(p, level, lowest_unlock);
+			unlock_up(p, level, lowest_unlock,
+				  min_write_lock_level, &write_lock_level);
 
 
 			if (level == lowest_level) {
 			if (level == lowest_level) {
 				if (dec)
 				if (dec)
@@ -1870,7 +1880,8 @@ cow_done:
 				}
 				}
 			}
 			}
 			if (!p->search_for_split)
 			if (!p->search_for_split)
-				unlock_up(p, level, lowest_unlock);
+				unlock_up(p, level, lowest_unlock,
+					  min_write_lock_level, &write_lock_level);
 			goto done;
 			goto done;
 		}
 		}
 	}
 	}
@@ -4108,7 +4119,7 @@ find_next_key:
 		path->slots[level] = slot;
 		path->slots[level] = slot;
 		if (level == path->lowest_level) {
 		if (level == path->lowest_level) {
 			ret = 0;
 			ret = 0;
-			unlock_up(path, level, 1);
+			unlock_up(path, level, 1, 0, NULL);
 			goto out;
 			goto out;
 		}
 		}
 		btrfs_set_path_blocking(path);
 		btrfs_set_path_blocking(path);
@@ -4119,7 +4130,7 @@ find_next_key:
 
 
 		path->locks[level - 1] = BTRFS_READ_LOCK;
 		path->locks[level - 1] = BTRFS_READ_LOCK;
 		path->nodes[level - 1] = cur;
 		path->nodes[level - 1] = cur;
-		unlock_up(path, level, 1);
+		unlock_up(path, level, 1, 0, NULL);
 		btrfs_clear_path_blocking(path, NULL, 0);
 		btrfs_clear_path_blocking(path, NULL, 0);
 	}
 	}
 out:
 out:
@@ -4355,7 +4366,7 @@ again:
 	}
 	}
 	ret = 0;
 	ret = 0;
 done:
 done:
-	unlock_up(path, 0, 1);
+	unlock_up(path, 0, 1, 0, NULL);
 	path->leave_spinning = old_spinning;
 	path->leave_spinning = old_spinning;
 	if (!old_spinning)
 	if (!old_spinning)
 		btrfs_set_path_blocking(path);
 		btrfs_set_path_blocking(path);