Commit 93a693d1 authored by Alexander Aring's avatar Alexander Aring Committed by David Teigland
Browse files

dlm: add rsb lists for iteration



To prepare for using rhashtable, add two rsb lists for iterating
through rsb's in two uncommon cases where this is necesssary:
- when dumping rsb state from debugfs, now using seq_list.
- when looking at all rsb's during recovery.

Signed-off-by: default avatarAlexander Aring <aahringo@redhat.com>
Signed-off-by: default avatarDavid Teigland <teigland@redhat.com>
parent 2d903540
Loading
Loading
Loading
Loading
+36 −197
Original line number Diff line number Diff line
@@ -366,12 +366,10 @@ static void print_format4(struct dlm_rsb *r, struct seq_file *s)
	unlock_rsb(r);
}

struct rsbtbl_iter {
	struct dlm_rsb *rsb;
	unsigned bucket;
	int format;
	int header;
};
static const struct seq_operations format1_seq_ops;
static const struct seq_operations format2_seq_ops;
static const struct seq_operations format3_seq_ops;
static const struct seq_operations format4_seq_ops;

/*
 * If the buffer is full, seq_printf can be called again, but it
@@ -382,220 +380,61 @@ struct rsbtbl_iter {

static int table_seq_show(struct seq_file *seq, void *iter_ptr)
{
	struct rsbtbl_iter *ri = iter_ptr;
	struct dlm_rsb *rsb = list_entry(iter_ptr, struct dlm_rsb, res_rsbs_list);

	switch (ri->format) {
	case 1:
		print_format1(ri->rsb, seq);
		break;
	case 2:
		if (ri->header) {
			seq_puts(seq, "id nodeid remid pid xid exflags flags sts grmode rqmode time_ms r_nodeid r_len r_name\n");
			ri->header = 0;
		}
		print_format2(ri->rsb, seq);
		break;
	case 3:
		if (ri->header) {
			seq_puts(seq, "rsb ptr nodeid first_lkid flags !root_list_empty !recover_list_empty recover_locks_count len\n");
			ri->header = 0;
		}
		print_format3(ri->rsb, seq);
		break;
	case 4:
		if (ri->header) {
			seq_puts(seq, "rsb ptr nodeid master_nodeid dir_nodeid our_nodeid toss_time flags len str|hex name\n");
			ri->header = 0;
		}
		print_format4(ri->rsb, seq);
		break;
	}
	if (seq->op == &format1_seq_ops)
		print_format1(rsb, seq);
	else if (seq->op == &format2_seq_ops)
		print_format2(rsb, seq);
	else if (seq->op == &format3_seq_ops)
		print_format3(rsb, seq);
	else if (seq->op == &format4_seq_ops)
		print_format4(rsb, seq);

	return 0;
}

static const struct seq_operations format1_seq_ops;
static const struct seq_operations format2_seq_ops;
static const struct seq_operations format3_seq_ops;
static const struct seq_operations format4_seq_ops;

static void *table_seq_start(struct seq_file *seq, loff_t *pos)
{
	struct rb_root *tree;
	struct rb_node *node;
	struct dlm_ls *ls = seq->private;
	struct rsbtbl_iter *ri;
	struct dlm_rsb *r;
	loff_t n = *pos;
	unsigned bucket, entry;
	int toss = (seq->op == &format4_seq_ops);

	bucket = n >> 32;
	entry = n & ((1LL << 32) - 1);

	if (bucket >= ls->ls_rsbtbl_size)
		return NULL;

	ri = kzalloc(sizeof(*ri), GFP_NOFS);
	if (!ri)
		return NULL;
	if (n == 0)
		ri->header = 1;
	if (seq->op == &format1_seq_ops)
		ri->format = 1;
	if (seq->op == &format2_seq_ops)
		ri->format = 2;
	if (seq->op == &format3_seq_ops)
		ri->format = 3;
	if (seq->op == &format4_seq_ops)
		ri->format = 4;

	tree = &ls->ls_rsbtbl[bucket].r;
	struct list_head *list;

	spin_lock_bh(&ls->ls_rsbtbl_lock);
	if (!RB_EMPTY_ROOT(tree)) {
		for (node = rb_first(tree); node; node = rb_next(node)) {
			r = rb_entry(node, struct dlm_rsb, res_hashnode);
			if (toss) {
				if (!rsb_flag(r, RSB_TOSS))
					continue;
			} else {
				if (rsb_flag(r, RSB_TOSS))
					continue;
			}

			if (!entry--) {
				dlm_hold_rsb(r);
				ri->rsb = r;
				ri->bucket = bucket;
				spin_unlock_bh(&ls->ls_rsbtbl_lock);
				return ri;
			}
		}
	if (!*pos) {
		if (seq->op == &format2_seq_ops)
			seq_puts(seq, "id nodeid remid pid xid exflags flags sts grmode rqmode time_ms r_nodeid r_len r_name\n");
		else if (seq->op == &format3_seq_ops)
			seq_puts(seq, "rsb ptr nodeid first_lkid flags !root_list_empty !recover_list_empty recover_locks_count len\n");
		else if (seq->op == &format4_seq_ops)
			seq_puts(seq, "rsb ptr nodeid master_nodeid dir_nodeid our_nodeid toss_time flags len str|hex name\n");
	}
	spin_unlock_bh(&ls->ls_rsbtbl_lock);

	/*
	 * move to the first rsb in the next non-empty bucket
	 */

	/* zero the entry */
	n &= ~((1LL << 32) - 1);

	while (1) {
		bucket++;
		n += 1LL << 32;

		if (bucket >= ls->ls_rsbtbl_size) {
			kfree(ri);
			return NULL;
		}
		tree = &ls->ls_rsbtbl[bucket].r;
	if (seq->op == &format4_seq_ops)
		list = &ls->ls_toss;
	else
		list = &ls->ls_keep;

	spin_lock_bh(&ls->ls_rsbtbl_lock);
		if (!RB_EMPTY_ROOT(tree)) {
			node = rb_first(tree);
			r = rb_entry(node, struct dlm_rsb, res_hashnode);
			if (toss) {
				if (!rsb_flag(r, RSB_TOSS))
					continue;
			} else {
				if (rsb_flag(r, RSB_TOSS))
					continue;
			}

			dlm_hold_rsb(r);
			ri->rsb = r;
			ri->bucket = bucket;
			spin_unlock_bh(&ls->ls_rsbtbl_lock);
			*pos = n;
			return ri;
		}
		spin_unlock_bh(&ls->ls_rsbtbl_lock);
	}
	return seq_list_start(list, *pos);
}

static void *table_seq_next(struct seq_file *seq, void *iter_ptr, loff_t *pos)
{
	struct dlm_ls *ls = seq->private;
	struct rsbtbl_iter *ri = iter_ptr;
	struct rb_root *tree;
	struct rb_node *next;
	struct dlm_rsb *r, *rp;
	loff_t n = *pos;
	unsigned bucket;
	int toss = (seq->op == &format4_seq_ops);

	bucket = n >> 32;

	/*
	 * move to the next rsb in the same bucket
	 */

	spin_lock_bh(&ls->ls_rsbtbl_lock);
	rp = ri->rsb;
	next = rb_next(&rp->res_hashnode);

	if (next) {
		r = rb_entry(next, struct dlm_rsb, res_hashnode);
		dlm_hold_rsb(r);
		ri->rsb = r;
		spin_unlock_bh(&ls->ls_rsbtbl_lock);
		dlm_put_rsb(rp);
		++*pos;
		return ri;
	}
	spin_unlock_bh(&ls->ls_rsbtbl_lock);
	dlm_put_rsb(rp);

	/*
	 * move to the first rsb in the next non-empty bucket
	 */
	struct list_head *list;

	/* zero the entry */
	n &= ~((1LL << 32) - 1);

	while (1) {
		bucket++;
		n += 1LL << 32;

		if (bucket >= ls->ls_rsbtbl_size) {
			kfree(ri);
			++*pos;
			return NULL;
		}
		tree = &ls->ls_rsbtbl[bucket].r;
	if (seq->op == &format4_seq_ops)
		list = &ls->ls_toss;
	else
		list = &ls->ls_keep;

		spin_lock_bh(&ls->ls_rsbtbl_lock);
		if (!RB_EMPTY_ROOT(tree)) {
			next = rb_first(tree);
			r = rb_entry(next, struct dlm_rsb, res_hashnode);
			if (toss) {
				if (!rsb_flag(r, RSB_TOSS))
					continue;
			} else {
				if (rsb_flag(r, RSB_TOSS))
					continue;
			}
			dlm_hold_rsb(r);
			ri->rsb = r;
			ri->bucket = bucket;
			spin_unlock_bh(&ls->ls_rsbtbl_lock);
			*pos = n;
			return ri;
		}
		spin_unlock_bh(&ls->ls_rsbtbl_lock);
	}
	return seq_list_next(iter_ptr, list, pos);
}

static void table_seq_stop(struct seq_file *seq, void *iter_ptr)
{
	struct rsbtbl_iter *ri = iter_ptr;
	struct dlm_ls *ls = seq->private;

	if (ri) {
		dlm_put_rsb(ri->rsb);
		kfree(ri);
	}
	spin_unlock_bh(&ls->ls_rsbtbl_lock);
}

static const struct seq_operations format1_seq_ops = {
+4 −0
Original line number Diff line number Diff line
@@ -339,6 +339,7 @@ struct dlm_rsb {
	struct list_head	res_convertqueue;
	struct list_head	res_waitqueue;

	struct list_head	res_rsbs_list;
	struct list_head	res_root_list;	    /* used for recovery */
	struct list_head	res_masters_list;   /* used for recovery */
	struct list_head	res_recover_list;   /* used for recovery */
@@ -595,6 +596,9 @@ struct dlm_ls {
	spinlock_t		ls_rsbtbl_lock;
	uint32_t		ls_rsbtbl_size;

	struct list_head	ls_toss;
	struct list_head	ls_keep;

	spinlock_t		ls_waiters_lock;
	struct list_head	ls_waiters;	/* lkbs needing a reply */

+21 −26
Original line number Diff line number Diff line
@@ -668,6 +668,7 @@ static int find_rsb_dir(struct dlm_ls *ls, const void *name, int len,
		r->res_first_lkid = 0;
	}

	list_move(&r->res_rsbs_list, &ls->ls_keep);
	rsb_clear_flag(r, RSB_TOSS);
	goto out_unlock;

@@ -730,6 +731,8 @@ static int find_rsb_dir(struct dlm_ls *ls, const void *name, int len,

 out_add:
	error = rsb_insert(r, &ls->ls_rsbtbl[b].r);
	if (!error)
		list_add(&r->res_rsbs_list, &ls->ls_keep);
 out_unlock:
	spin_unlock_bh(&ls->ls_rsbtbl_lock);
 out:
@@ -801,6 +804,7 @@ static int find_rsb_nodir(struct dlm_ls *ls, const void *name, int len,
		r->res_nodeid = 0;
	}

	list_move(&r->res_rsbs_list, &ls->ls_keep);
	rsb_clear_flag(r, RSB_TOSS);
	goto out_unlock;

@@ -826,6 +830,8 @@ static int find_rsb_nodir(struct dlm_ls *ls, const void *name, int len,
	kref_init(&r->res_ref);

	error = rsb_insert(r, &ls->ls_rsbtbl[b].r);
	if (!error)
		list_add(&r->res_rsbs_list, &ls->ls_keep);
 out_unlock:
	spin_unlock_bh(&ls->ls_rsbtbl_lock);
 out:
@@ -1110,6 +1116,8 @@ int dlm_master_lookup(struct dlm_ls *ls, int from_nodeid, const char *name,
		goto retry;
	}

	list_add(&r->res_rsbs_list, &ls->ls_toss);

	if (result)
		*result = DLM_LU_ADD;
	*r_nodeid = from_nodeid;
@@ -1120,21 +1128,13 @@ int dlm_master_lookup(struct dlm_ls *ls, int from_nodeid, const char *name,

static void dlm_dump_rsb_hash(struct dlm_ls *ls, uint32_t hash)
{
	struct rb_node *n;
	struct dlm_rsb *r;
	int i;

	spin_lock_bh(&ls->ls_rsbtbl_lock);
	for (i = 0; i < ls->ls_rsbtbl_size; i++) {
		for (n = rb_first(&ls->ls_rsbtbl[i].r); n; n = rb_next(n)) {
			r = rb_entry(n, struct dlm_rsb, res_hashnode);
			if (rsb_flag(r, RSB_TOSS))
				continue;

	list_for_each_entry(r, &ls->ls_keep, res_rsbs_list) {
		if (r->res_hash == hash)
			dlm_dump_rsb(r);
	}
	}
	spin_unlock_bh(&ls->ls_rsbtbl_lock);
}

@@ -1166,6 +1166,7 @@ static void toss_rsb(struct kref *kref)
	kref_init(&r->res_ref);
	WARN_ON(rsb_flag(r, RSB_TOSS));
	rsb_set_flag(r, RSB_TOSS);
	list_move(&r->res_rsbs_list, &ls->ls_toss);
	r->res_toss_time = jiffies;
	set_bit(DLM_RTF_SHRINK_BIT, &ls->ls_rsbtbl[r->res_bucket].flags);
	if (r->res_lvbptr) {
@@ -1672,6 +1673,7 @@ static void shrink_bucket(struct dlm_ls *ls, int b)
			continue;
		}

		list_del(&r->res_rsbs_list);
		rb_erase(&r->res_hashnode, &ls->ls_rsbtbl[b].r);
		dlm_free_rsb(r);
	}
@@ -1740,6 +1742,7 @@ static void shrink_bucket(struct dlm_ls *ls, int b)
			continue;
		}

		list_del(&r->res_rsbs_list);
		rb_erase(&r->res_hashnode, &ls->ls_rsbtbl[b].r);
		send_remove(r);
		spin_unlock_bh(&ls->ls_rsbtbl_lock);
@@ -4243,6 +4246,7 @@ static void receive_remove(struct dlm_ls *ls, const struct dlm_message *ms)
	}

	if (kref_put(&r->res_ref, kill_rsb)) {
		list_del(&r->res_rsbs_list);
		rb_erase(&r->res_hashnode, &ls->ls_rsbtbl[b].r);
		spin_unlock_bh(&ls->ls_rsbtbl_lock);
		dlm_free_rsb(r);
@@ -5313,17 +5317,12 @@ void dlm_recover_purge(struct dlm_ls *ls, const struct list_head *root_list)
			  lkb_count, nodes_count);
}

static struct dlm_rsb *find_grant_rsb(struct dlm_ls *ls, int bucket)
static struct dlm_rsb *find_grant_rsb(struct dlm_ls *ls)
{
	struct rb_node *n;
	struct dlm_rsb *r;

	spin_lock_bh(&ls->ls_rsbtbl_lock);
	for (n = rb_first(&ls->ls_rsbtbl[bucket].r); n; n = rb_next(n)) {
		r = rb_entry(n, struct dlm_rsb, res_hashnode);
		if (rsb_flag(r, RSB_TOSS))
			continue;

	list_for_each_entry(r, &ls->ls_keep, res_rsbs_list) {
		if (!rsb_flag(r, RSB_RECOVER_GRANT))
			continue;
		if (!is_master(r)) {
@@ -5358,19 +5357,15 @@ static struct dlm_rsb *find_grant_rsb(struct dlm_ls *ls, int bucket)
void dlm_recover_grant(struct dlm_ls *ls)
{
	struct dlm_rsb *r;
	int bucket = 0;
	unsigned int count = 0;
	unsigned int rsb_count = 0;
	unsigned int lkb_count = 0;

	while (1) {
		r = find_grant_rsb(ls, bucket);
		if (!r) {
			if (bucket == ls->ls_rsbtbl_size - 1)
		r = find_grant_rsb(ls);
		if (!r)
			break;
			bucket++;
			continue;
		}

		rsb_count++;
		count = 0;
		lock_rsb(r);
+3 −0
Original line number Diff line number Diff line
@@ -495,6 +495,8 @@ static int new_lockspace(const char *name, const char *cluster,
	 */
	ls->ls_exflags = (flags & ~(DLM_LSFL_FS | DLM_LSFL_NEWEXCL));

	INIT_LIST_HEAD(&ls->ls_toss);
	INIT_LIST_HEAD(&ls->ls_keep);
	spin_lock_init(&ls->ls_rsbtbl_lock);
	size = READ_ONCE(dlm_config.ci_rsbtbl_size);
	ls->ls_rsbtbl_size = size;
@@ -838,6 +840,7 @@ static int release_lockspace(struct dlm_ls *ls, int force)
	for (i = 0; i < ls->ls_rsbtbl_size; i++) {
		while ((n = rb_first(&ls->ls_rsbtbl[i].r))) {
			rsb = rb_entry(n, struct dlm_rsb, res_hashnode);
			list_del(&rsb->res_rsbs_list);
			rb_erase(n, &ls->ls_rsbtbl[i].r);
			dlm_free_rsb(rsb);
		}
+8 −16
Original line number Diff line number Diff line
@@ -881,24 +881,16 @@ void dlm_recover_rsbs(struct dlm_ls *ls, const struct list_head *root_list)

void dlm_clear_toss(struct dlm_ls *ls)
{
	struct rb_node *n, *next;
	struct dlm_rsb *r;
	struct dlm_rsb *r, *safe;
	unsigned int count = 0;
	int i;

	spin_lock(&ls->ls_rsbtbl_lock);
	for (i = 0; i < ls->ls_rsbtbl_size; i++) {
		for (n = rb_first(&ls->ls_rsbtbl[i].r); n; n = next) {
			next = rb_next(n);
			r = rb_entry(n, struct dlm_rsb, res_hashnode);
			if (!rsb_flag(r, RSB_TOSS))
				continue;

			rb_erase(n, &ls->ls_rsbtbl[i].r);
	spin_lock_bh(&ls->ls_rsbtbl_lock);
	list_for_each_entry_safe(r, safe, &ls->ls_toss, res_rsbs_list) {
		list_del(&r->res_rsbs_list);
		rb_erase(&r->res_hashnode, &ls->ls_rsbtbl[r->res_bucket].r);
		dlm_free_rsb(r);
		count++;
	}
	}
	spin_unlock_bh(&ls->ls_rsbtbl_lock);

	if (count)
Loading