#include <linux/pagemap.h>
#include <linux/spinlock.h>
#include <linux/page-flags.h>
-#include <linux/bug.h>
+#include <asm/bug.h>
#include "ctree.h"
#include "extent_io.h"
#include "locking.h"
+/*
+ * locks the per buffer mutex in an extent buffer. This uses adaptive locks
+ * and the spin is not tuned very extensively. The spinning does make a big
+ * difference in almost every workload, but spinning for the right amount of
+ * time needs some help.
+ *
+ * In general, we want to spin as long as the lock holder is doing btree searches,
+ * and we should give up if they are in more expensive code.
+ */
int btrfs_tree_lock(struct extent_buffer *eb)
{
- lock_page(eb->first_page);
+ int i;
+
+ if (mutex_trylock(&eb->mutex))
+ return 0;
+ for (i = 0; i < 512; i++) {
+ cpu_relax();
+ if (mutex_trylock(&eb->mutex))
+ return 0;
+ }
+ cpu_relax();
+ mutex_lock_nested(&eb->mutex, BTRFS_MAX_LEVEL - btrfs_header_level(eb));
return 0;
}
int btrfs_try_tree_lock(struct extent_buffer *eb)
{
- return TestSetPageLocked(eb->first_page);
+ return mutex_trylock(&eb->mutex);
}
int btrfs_tree_unlock(struct extent_buffer *eb)
{
- WARN_ON(!PageLocked(eb->first_page));
- unlock_page(eb->first_page);
+ mutex_unlock(&eb->mutex);
return 0;
}
int btrfs_tree_locked(struct extent_buffer *eb)
{
- return PageLocked(eb->first_page);
+ return mutex_is_locked(&eb->mutex);
+}
+
+/*
+ * btrfs_search_slot uses this to decide if it should drop its locks
+ * before doing something expensive like allocating free blocks for cow.
+ */
+int btrfs_path_lock_waiting(struct btrfs_path *path, int level)
+{
+ int i;
+ struct extent_buffer *eb;
+ for (i = level; i <= level + 1 && i < BTRFS_MAX_LEVEL; i++) {
+ eb = path->nodes[i];
+ if (!eb)
+ break;
+ smp_mb();
+ if (!list_empty(&eb->mutex.wait_list))
+ return 1;
+ }
+ return 0;
}