|
@@ -56,6 +56,7 @@
|
|
|
L: receive_xxxx_reply() <- R: send_xxxx_reply()
|
|
|
*/
|
|
|
#include <linux/types.h>
|
|
|
+#include <linux/rbtree.h>
|
|
|
#include <linux/slab.h>
|
|
|
#include "dlm_internal.h"
|
|
|
#include <linux/dlm_device.h>
|
|
@@ -380,6 +381,8 @@ static int get_rsb_struct(struct dlm_ls *ls, char *name, int len,
|
|
|
|
|
|
r = list_first_entry(&ls->ls_new_rsb, struct dlm_rsb, res_hashchain);
|
|
|
list_del(&r->res_hashchain);
|
|
|
+ /* Convert the empty list_head to a NULL rb_node for tree usage: */
|
|
|
+ memset(&r->res_hashnode, 0, sizeof(struct rb_node));
|
|
|
ls->ls_new_rsb_count--;
|
|
|
spin_unlock(&ls->ls_new_rsb_spin);
|
|
|
|
|
@@ -388,7 +391,6 @@ static int get_rsb_struct(struct dlm_ls *ls, char *name, int len,
|
|
|
memcpy(r->res_name, name, len);
|
|
|
mutex_init(&r->res_mutex);
|
|
|
|
|
|
- INIT_LIST_HEAD(&r->res_hashchain);
|
|
|
INIT_LIST_HEAD(&r->res_lookup);
|
|
|
INIT_LIST_HEAD(&r->res_grantqueue);
|
|
|
INIT_LIST_HEAD(&r->res_convertqueue);
|
|
@@ -400,14 +402,31 @@ static int get_rsb_struct(struct dlm_ls *ls, char *name, int len,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static int search_rsb_list(struct list_head *head, char *name, int len,
|
|
|
+static int rsb_cmp(struct dlm_rsb *r, const char *name, int nlen)
|
|
|
+{
|
|
|
+ char maxname[DLM_RESNAME_MAXLEN];
|
|
|
+
|
|
|
+ memset(maxname, 0, DLM_RESNAME_MAXLEN);
|
|
|
+ memcpy(maxname, name, nlen);
|
|
|
+ return memcmp(r->res_name, maxname, DLM_RESNAME_MAXLEN);
|
|
|
+}
|
|
|
+
|
|
|
+static int search_rsb_tree(struct rb_root *tree, char *name, int len,
|
|
|
unsigned int flags, struct dlm_rsb **r_ret)
|
|
|
{
|
|
|
+ struct rb_node *node = tree->rb_node;
|
|
|
struct dlm_rsb *r;
|
|
|
int error = 0;
|
|
|
-
|
|
|
- list_for_each_entry(r, head, res_hashchain) {
|
|
|
- if (len == r->res_length && !memcmp(name, r->res_name, len))
|
|
|
+ int rc;
|
|
|
+
|
|
|
+ while (node) {
|
|
|
+ r = rb_entry(node, struct dlm_rsb, res_hashnode);
|
|
|
+ rc = rsb_cmp(r, name, len);
|
|
|
+ if (rc < 0)
|
|
|
+ node = node->rb_left;
|
|
|
+ else if (rc > 0)
|
|
|
+ node = node->rb_right;
|
|
|
+ else
|
|
|
goto found;
|
|
|
}
|
|
|
*r_ret = NULL;
|
|
@@ -420,22 +439,54 @@ static int search_rsb_list(struct list_head *head, char *name, int len,
|
|
|
return error;
|
|
|
}
|
|
|
|
|
|
+static int rsb_insert(struct dlm_rsb *rsb, struct rb_root *tree)
|
|
|
+{
|
|
|
+ struct rb_node **newn = &tree->rb_node;
|
|
|
+ struct rb_node *parent = NULL;
|
|
|
+ int rc;
|
|
|
+
|
|
|
+ while (*newn) {
|
|
|
+ struct dlm_rsb *cur = rb_entry(*newn, struct dlm_rsb,
|
|
|
+ res_hashnode);
|
|
|
+
|
|
|
+ parent = *newn;
|
|
|
+ rc = rsb_cmp(cur, rsb->res_name, rsb->res_length);
|
|
|
+ if (rc < 0)
|
|
|
+ newn = &parent->rb_left;
|
|
|
+ else if (rc > 0)
|
|
|
+ newn = &parent->rb_right;
|
|
|
+ else {
|
|
|
+ log_print("rsb_insert match");
|
|
|
+ dlm_dump_rsb(rsb);
|
|
|
+ dlm_dump_rsb(cur);
|
|
|
+ return -EEXIST;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ rb_link_node(&rsb->res_hashnode, parent, newn);
|
|
|
+ rb_insert_color(&rsb->res_hashnode, tree);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
static int _search_rsb(struct dlm_ls *ls, char *name, int len, int b,
|
|
|
unsigned int flags, struct dlm_rsb **r_ret)
|
|
|
{
|
|
|
struct dlm_rsb *r;
|
|
|
int error;
|
|
|
|
|
|
- error = search_rsb_list(&ls->ls_rsbtbl[b].list, name, len, flags, &r);
|
|
|
+ error = search_rsb_tree(&ls->ls_rsbtbl[b].keep, name, len, flags, &r);
|
|
|
if (!error) {
|
|
|
kref_get(&r->res_ref);
|
|
|
goto out;
|
|
|
}
|
|
|
- error = search_rsb_list(&ls->ls_rsbtbl[b].toss, name, len, flags, &r);
|
|
|
+ error = search_rsb_tree(&ls->ls_rsbtbl[b].toss, name, len, flags, &r);
|
|
|
if (error)
|
|
|
goto out;
|
|
|
|
|
|
- list_move(&r->res_hashchain, &ls->ls_rsbtbl[b].list);
|
|
|
+ rb_erase(&r->res_hashnode, &ls->ls_rsbtbl[b].toss);
|
|
|
+ error = rsb_insert(r, &ls->ls_rsbtbl[b].keep);
|
|
|
+ if (error)
|
|
|
+ return error;
|
|
|
|
|
|
if (dlm_no_directory(ls))
|
|
|
goto out;
|
|
@@ -527,8 +578,7 @@ static int find_rsb(struct dlm_ls *ls, char *name, int namelen,
|
|
|
nodeid = 0;
|
|
|
r->res_nodeid = nodeid;
|
|
|
}
|
|
|
- list_add(&r->res_hashchain, &ls->ls_rsbtbl[bucket].list);
|
|
|
- error = 0;
|
|
|
+ error = rsb_insert(r, &ls->ls_rsbtbl[bucket].keep);
|
|
|
out_unlock:
|
|
|
spin_unlock(&ls->ls_rsbtbl[bucket].lock);
|
|
|
out:
|
|
@@ -556,7 +606,8 @@ static void toss_rsb(struct kref *kref)
|
|
|
|
|
|
DLM_ASSERT(list_empty(&r->res_root_list), dlm_print_rsb(r););
|
|
|
kref_init(&r->res_ref);
|
|
|
- list_move(&r->res_hashchain, &ls->ls_rsbtbl[r->res_bucket].toss);
|
|
|
+ rb_erase(&r->res_hashnode, &ls->ls_rsbtbl[r->res_bucket].keep);
|
|
|
+ rsb_insert(r, &ls->ls_rsbtbl[r->res_bucket].toss);
|
|
|
r->res_toss_time = jiffies;
|
|
|
if (r->res_lvbptr) {
|
|
|
dlm_free_lvb(r->res_lvbptr);
|
|
@@ -1082,19 +1133,19 @@ static void dir_remove(struct dlm_rsb *r)
|
|
|
r->res_name, r->res_length);
|
|
|
}
|
|
|
|
|
|
-/* FIXME: shouldn't this be able to exit as soon as one non-due rsb is
|
|
|
- found since they are in order of newest to oldest? */
|
|
|
+/* FIXME: make this more efficient */
|
|
|
|
|
|
static int shrink_bucket(struct dlm_ls *ls, int b)
|
|
|
{
|
|
|
+ struct rb_node *n;
|
|
|
struct dlm_rsb *r;
|
|
|
int count = 0, found;
|
|
|
|
|
|
for (;;) {
|
|
|
found = 0;
|
|
|
spin_lock(&ls->ls_rsbtbl[b].lock);
|
|
|
- list_for_each_entry_reverse(r, &ls->ls_rsbtbl[b].toss,
|
|
|
- res_hashchain) {
|
|
|
+ for (n = rb_first(&ls->ls_rsbtbl[b].toss); n; n = rb_next(n)) {
|
|
|
+ r = rb_entry(n, struct dlm_rsb, res_hashnode);
|
|
|
if (!time_after_eq(jiffies, r->res_toss_time +
|
|
|
dlm_config.ci_toss_secs * HZ))
|
|
|
continue;
|
|
@@ -1108,7 +1159,7 @@ static int shrink_bucket(struct dlm_ls *ls, int b)
|
|
|
}
|
|
|
|
|
|
if (kref_put(&r->res_ref, kill_rsb)) {
|
|
|
- list_del(&r->res_hashchain);
|
|
|
+ rb_erase(&r->res_hashnode, &ls->ls_rsbtbl[b].toss);
|
|
|
spin_unlock(&ls->ls_rsbtbl[b].lock);
|
|
|
|
|
|
if (is_master(r))
|
|
@@ -4441,10 +4492,12 @@ int dlm_purge_locks(struct dlm_ls *ls)
|
|
|
|
|
|
static struct dlm_rsb *find_purged_rsb(struct dlm_ls *ls, int bucket)
|
|
|
{
|
|
|
+ struct rb_node *n;
|
|
|
struct dlm_rsb *r, *r_ret = NULL;
|
|
|
|
|
|
spin_lock(&ls->ls_rsbtbl[bucket].lock);
|
|
|
- list_for_each_entry(r, &ls->ls_rsbtbl[bucket].list, res_hashchain) {
|
|
|
+ for (n = rb_first(&ls->ls_rsbtbl[bucket].keep); n; n = rb_next(n)) {
|
|
|
+ r = rb_entry(n, struct dlm_rsb, res_hashnode);
|
|
|
if (!rsb_flag(r, RSB_LOCKS_PURGED))
|
|
|
continue;
|
|
|
hold_rsb(r);
|