Commit 6fffab66 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull dlm updates from David Teigland:
 "This set includes some small fixes, and some big internal changes:

   - Fix a long standing race between the unlock callback for the last
     lkb struct, and removing the rsb that became unused after the final
     unlock. This could lead different nodes to inconsistent info about
     the rsb master node.

   - Remove unnecessary refcounting on callback structs, returning to
     the way things were done in the past.

   - Do message processing in softirq context. This allows dlm messages
     to be cleared more quickly and efficiently, reducing long lists of
     incomplete requests. A future change to run callbacks directly from
     this context will make this more effective.

   - The softirq message processing involved a number of patches
     changing mutexes to spinlocks and rwlocks, and a fair amount of
     code re-org in preparation.

   - Use an rhashtable for rsb structs, rather than our old internal
     hash table implementation. This also required some re-org of lists
     and locks preparation for the change.

   - Drop the dlm_scand kthread, and use timers to clear unused rsb
     structs. Scanning all rsb's periodically was a lot of wasted work.

   - Fix recent regression in logic for copying LVB data in user space
     lock requests"

* tag 'dlm-6.10' of git://git.kernel.org/pub/scm/linux/kernel/git/teigland/linux-dlm: (34 commits)
  dlm: return -ENOMEM if ls_recover_buf fails
  dlm: fix sleep in atomic context
  dlm: use rwlock for lkbidr
  dlm: use rwlock for rsb hash table
  dlm: drop dlm_scand kthread and use timers
  dlm: do not use ref counts for rsb in the toss state
  dlm: switch to use rhashtable for rsbs
  dlm: add rsb lists for iteration
  dlm: merge toss and keep hash table lists into one list
  dlm: change to single hashtable lock
  dlm: increment ls_count for dlm_scand
  dlm: do message processing in softirq context
  dlm: use spin_lock_bh for message processing
  dlm: remove schedule in receive path
  dlm: convert ls_recv_active from rw_semaphore to rwlock
  dlm: avoid blocking receive at the end of recovery
  dlm: convert res_lock to spinlock
  dlm: convert ls_waiters_mutex to spinlock
  dlm: drop mutex use in waiters recovery
  dlm: add new struct to save position in dlm_copy_master_names
  ...
parents a3d1f54d 7b72ab2c
Loading
Loading
Loading
Loading
+86 −132
Original line number Diff line number Diff line
@@ -12,47 +12,50 @@
#include <trace/events/dlm.h>

#include "dlm_internal.h"
#include "lvb_table.h"
#include "memory.h"
#include "lock.h"
#include "user.h"
#include "ast.h"

void dlm_release_callback(struct kref *ref)
static void dlm_callback_work(struct work_struct *work)
{
	struct dlm_callback *cb = container_of(ref, struct dlm_callback, ref);
	struct dlm_callback *cb = container_of(work, struct dlm_callback, work);

	dlm_free_cb(cb);
	if (cb->flags & DLM_CB_BAST) {
		trace_dlm_bast(cb->ls_id, cb->lkb_id, cb->mode, cb->res_name,
			       cb->res_length);
		cb->bastfn(cb->astparam, cb->mode);
	} else if (cb->flags & DLM_CB_CAST) {
		trace_dlm_ast(cb->ls_id, cb->lkb_id, cb->sb_status,
			      cb->sb_flags, cb->res_name, cb->res_length);
		cb->lkb_lksb->sb_status = cb->sb_status;
		cb->lkb_lksb->sb_flags = cb->sb_flags;
		cb->astfn(cb->astparam);
	}

void dlm_callback_set_last_ptr(struct dlm_callback **from,
			       struct dlm_callback *to)
{
	if (*from)
		kref_put(&(*from)->ref, dlm_release_callback);

	if (to)
		kref_get(&to->ref);

	*from = to;
	dlm_free_cb(cb);
}

int dlm_enqueue_lkb_callback(struct dlm_lkb *lkb, uint32_t flags, int mode,
			     int status, uint32_t sbflags)
int dlm_queue_lkb_callback(struct dlm_lkb *lkb, uint32_t flags, int mode,
			   int status, uint32_t sbflags,
			   struct dlm_callback **cb)
{
	struct dlm_ls *ls = lkb->lkb_resource->res_ls;
	struct dlm_rsb *rsb = lkb->lkb_resource;
	int rv = DLM_ENQUEUE_CALLBACK_SUCCESS;
	struct dlm_callback *cb;
	struct dlm_ls *ls = rsb->res_ls;
	int copy_lvb = 0;
	int prev_mode;

	if (flags & DLM_CB_BAST) {
		/* if cb is a bast, it should be skipped if the blocking mode is
		 * compatible with the last granted mode
		 */
		if (lkb->lkb_last_cast) {
			if (dlm_modes_compat(mode, lkb->lkb_last_cast->mode)) {
		if (lkb->lkb_last_cast_cb_mode != -1) {
			if (dlm_modes_compat(mode, lkb->lkb_last_cast_cb_mode)) {
				log_debug(ls, "skip %x bast mode %d for cast mode %d",
					  lkb->lkb_id, mode,
					  lkb->lkb_last_cast->mode);
					  lkb->lkb_last_cast_cb_mode);
				goto out;
			}
		}
@@ -63,8 +66,9 @@ int dlm_enqueue_lkb_callback(struct dlm_lkb *lkb, uint32_t flags, int mode,
		 * is a bast for the same mode or a more restrictive mode.
		 * (the addional > PR check is needed for PR/CW inversion)
		 */
		if (lkb->lkb_last_cb && lkb->lkb_last_cb->flags & DLM_CB_BAST) {
			prev_mode = lkb->lkb_last_cb->mode;
		if (lkb->lkb_last_cb_mode != -1 &&
		    lkb->lkb_last_cb_flags & DLM_CB_BAST) {
			prev_mode = lkb->lkb_last_cb_mode;

			if ((prev_mode == mode) ||
			    (prev_mode > mode && prev_mode > DLM_LOCK_PR)) {
@@ -73,53 +77,55 @@ int dlm_enqueue_lkb_callback(struct dlm_lkb *lkb, uint32_t flags, int mode,
				goto out;
			}
		}

		lkb->lkb_last_bast_time = ktime_get();
		lkb->lkb_last_bast_cb_mode = mode;
	} else if (flags & DLM_CB_CAST) {
		if (test_bit(DLM_DFL_USER_BIT, &lkb->lkb_dflags)) {
			prev_mode = lkb->lkb_last_cast_cb_mode;

			if (!status && lkb->lkb_lksb->sb_lvbptr &&
			    dlm_lvb_operations[prev_mode + 1][mode + 1])
				copy_lvb = 1;
		}

	cb = dlm_allocate_cb();
	if (!cb) {
		lkb->lkb_last_cast_cb_mode = mode;
		lkb->lkb_last_cast_time = ktime_get();
	}

	lkb->lkb_last_cb_mode = mode;
	lkb->lkb_last_cb_flags = flags;

	*cb = dlm_allocate_cb();
	if (!*cb) {
		rv = DLM_ENQUEUE_CALLBACK_FAILURE;
		goto out;
	}

	cb->flags = flags;
	cb->mode = mode;
	cb->sb_status = status;
	cb->sb_flags = (sbflags & 0x000000FF);
	kref_init(&cb->ref);
	if (!test_and_set_bit(DLM_IFL_CB_PENDING_BIT, &lkb->lkb_iflags))
		rv = DLM_ENQUEUE_CALLBACK_NEED_SCHED;
	/* for tracing */
	(*cb)->lkb_id = lkb->lkb_id;
	(*cb)->ls_id = ls->ls_global_id;
	memcpy((*cb)->res_name, rsb->res_name, rsb->res_length);
	(*cb)->res_length = rsb->res_length;

	list_add_tail(&cb->list, &lkb->lkb_callbacks);
	(*cb)->flags = flags;
	(*cb)->mode = mode;
	(*cb)->sb_status = status;
	(*cb)->sb_flags = (sbflags & 0x000000FF);
	(*cb)->copy_lvb = copy_lvb;
	(*cb)->lkb_lksb = lkb->lkb_lksb;

	if (flags & DLM_CB_CAST)
		dlm_callback_set_last_ptr(&lkb->lkb_last_cast, cb);

	dlm_callback_set_last_ptr(&lkb->lkb_last_cb, cb);
	rv = DLM_ENQUEUE_CALLBACK_NEED_SCHED;

out:
	return rv;
}

int dlm_dequeue_lkb_callback(struct dlm_lkb *lkb, struct dlm_callback **cb)
{
	/* oldest undelivered cb is callbacks first entry */
	*cb = list_first_entry_or_null(&lkb->lkb_callbacks,
				       struct dlm_callback, list);
	if (!*cb)
		return DLM_DEQUEUE_CALLBACK_EMPTY;

	/* remove it from callbacks so shift others down */
	list_del(&(*cb)->list);
	if (list_empty(&lkb->lkb_callbacks))
		return DLM_DEQUEUE_CALLBACK_LAST;

	return DLM_DEQUEUE_CALLBACK_SUCCESS;
}

void dlm_add_cb(struct dlm_lkb *lkb, uint32_t flags, int mode, int status,
		  uint32_t sbflags)
{
	struct dlm_ls *ls = lkb->lkb_resource->res_ls;
	struct dlm_callback *cb;
	int rv;

	if (test_bit(DLM_DFL_USER_BIT, &lkb->lkb_dflags)) {
@@ -127,88 +133,36 @@ void dlm_add_cb(struct dlm_lkb *lkb, uint32_t flags, int mode, int status,
		return;
	}

	spin_lock(&lkb->lkb_cb_lock);
	rv = dlm_enqueue_lkb_callback(lkb, flags, mode, status, sbflags);
	rv = dlm_queue_lkb_callback(lkb, flags, mode, status, sbflags,
				    &cb);
	switch (rv) {
	case DLM_ENQUEUE_CALLBACK_NEED_SCHED:
		kref_get(&lkb->lkb_ref);

		spin_lock(&ls->ls_cb_lock);
		if (test_bit(LSFL_CB_DELAY, &ls->ls_flags)) {
			list_add(&lkb->lkb_cb_list, &ls->ls_cb_delay);
		} else {
			queue_work(ls->ls_callback_wq, &lkb->lkb_cb_work);
		}
		spin_unlock(&ls->ls_cb_lock);
		break;
	case DLM_ENQUEUE_CALLBACK_FAILURE:
		WARN_ON_ONCE(1);
		cb->astfn = lkb->lkb_astfn;
		cb->bastfn = lkb->lkb_bastfn;
		cb->astparam = lkb->lkb_astparam;
		INIT_WORK(&cb->work, dlm_callback_work);

		spin_lock_bh(&ls->ls_cb_lock);
		if (test_bit(LSFL_CB_DELAY, &ls->ls_flags))
			list_add(&cb->list, &ls->ls_cb_delay);
		else
			queue_work(ls->ls_callback_wq, &cb->work);
		spin_unlock_bh(&ls->ls_cb_lock);
		break;
	case DLM_ENQUEUE_CALLBACK_SUCCESS:
		break;
	case DLM_ENQUEUE_CALLBACK_FAILURE:
		fallthrough;
	default:
		WARN_ON_ONCE(1);
		break;
	}
	spin_unlock(&lkb->lkb_cb_lock);
}

void dlm_callback_work(struct work_struct *work)
{
	struct dlm_lkb *lkb = container_of(work, struct dlm_lkb, lkb_cb_work);
	struct dlm_ls *ls = lkb->lkb_resource->res_ls;
	void (*castfn) (void *astparam);
	void (*bastfn) (void *astparam, int mode);
	struct dlm_callback *cb;
	int rv;

	spin_lock(&lkb->lkb_cb_lock);
	rv = dlm_dequeue_lkb_callback(lkb, &cb);
	if (WARN_ON_ONCE(rv == DLM_DEQUEUE_CALLBACK_EMPTY)) {
		clear_bit(DLM_IFL_CB_PENDING_BIT, &lkb->lkb_iflags);
		spin_unlock(&lkb->lkb_cb_lock);
		goto out;
	}
	spin_unlock(&lkb->lkb_cb_lock);

	for (;;) {
		castfn = lkb->lkb_astfn;
		bastfn = lkb->lkb_bastfn;

		if (cb->flags & DLM_CB_BAST) {
			trace_dlm_bast(ls, lkb, cb->mode);
			lkb->lkb_last_bast_time = ktime_get();
			lkb->lkb_last_bast_mode = cb->mode;
			bastfn(lkb->lkb_astparam, cb->mode);
		} else if (cb->flags & DLM_CB_CAST) {
			lkb->lkb_lksb->sb_status = cb->sb_status;
			lkb->lkb_lksb->sb_flags = cb->sb_flags;
			trace_dlm_ast(ls, lkb);
			lkb->lkb_last_cast_time = ktime_get();
			castfn(lkb->lkb_astparam);
		}

		kref_put(&cb->ref, dlm_release_callback);

		spin_lock(&lkb->lkb_cb_lock);
		rv = dlm_dequeue_lkb_callback(lkb, &cb);
		if (rv == DLM_DEQUEUE_CALLBACK_EMPTY) {
			clear_bit(DLM_IFL_CB_PENDING_BIT, &lkb->lkb_iflags);
			spin_unlock(&lkb->lkb_cb_lock);
			break;
		}
		spin_unlock(&lkb->lkb_cb_lock);
	}

out:
	/* undo kref_get from dlm_add_callback, may cause lkb to be freed */
	dlm_put_lkb(lkb);
}

int dlm_callback_start(struct dlm_ls *ls)
{
	ls->ls_callback_wq = alloc_workqueue("dlm_callback",
					     WQ_HIGHPRI | WQ_MEM_RECLAIM, 0);
	ls->ls_callback_wq = alloc_ordered_workqueue("dlm_callback",
						     WQ_HIGHPRI | WQ_MEM_RECLAIM);
	if (!ls->ls_callback_wq) {
		log_print("can't start dlm_callback workqueue");
		return -ENOMEM;
@@ -225,9 +179,9 @@ void dlm_callback_stop(struct dlm_ls *ls)
void dlm_callback_suspend(struct dlm_ls *ls)
{
	if (ls->ls_callback_wq) {
		spin_lock(&ls->ls_cb_lock);
		spin_lock_bh(&ls->ls_cb_lock);
		set_bit(LSFL_CB_DELAY, &ls->ls_flags);
		spin_unlock(&ls->ls_cb_lock);
		spin_unlock_bh(&ls->ls_cb_lock);

		flush_workqueue(ls->ls_callback_wq);
	}
@@ -237,7 +191,7 @@ void dlm_callback_suspend(struct dlm_ls *ls)

void dlm_callback_resume(struct dlm_ls *ls)
{
	struct dlm_lkb *lkb, *safe;
	struct dlm_callback *cb, *safe;
	int count = 0, sum = 0;
	bool empty;

@@ -245,10 +199,10 @@ void dlm_callback_resume(struct dlm_ls *ls)
		return;

more:
	spin_lock(&ls->ls_cb_lock);
	list_for_each_entry_safe(lkb, safe, &ls->ls_cb_delay, lkb_cb_list) {
		list_del_init(&lkb->lkb_cb_list);
		queue_work(ls->ls_callback_wq, &lkb->lkb_cb_work);
	spin_lock_bh(&ls->ls_cb_lock);
	list_for_each_entry_safe(cb, safe, &ls->ls_cb_delay, list) {
		list_del(&cb->list);
		queue_work(ls->ls_callback_wq, &cb->work);
		count++;
		if (count == MAX_CB_QUEUE)
			break;
@@ -256,7 +210,7 @@ void dlm_callback_resume(struct dlm_ls *ls)
	empty = list_empty(&ls->ls_cb_delay);
	if (empty)
		clear_bit(LSFL_CB_DELAY, &ls->ls_flags);
	spin_unlock(&ls->ls_cb_lock);
	spin_unlock_bh(&ls->ls_cb_lock);

	sum += count;
	if (!empty) {
+3 −10
Original line number Diff line number Diff line
@@ -14,19 +14,12 @@
#define DLM_ENQUEUE_CALLBACK_NEED_SCHED	1
#define DLM_ENQUEUE_CALLBACK_SUCCESS	0
#define DLM_ENQUEUE_CALLBACK_FAILURE	-1
int dlm_enqueue_lkb_callback(struct dlm_lkb *lkb, uint32_t flags, int mode,
			     int status, uint32_t sbflags);
#define DLM_DEQUEUE_CALLBACK_EMPTY	2
#define DLM_DEQUEUE_CALLBACK_LAST	1
#define DLM_DEQUEUE_CALLBACK_SUCCESS	0
int dlm_dequeue_lkb_callback(struct dlm_lkb *lkb, struct dlm_callback **cb);
int dlm_queue_lkb_callback(struct dlm_lkb *lkb, uint32_t flags, int mode,
			   int status, uint32_t sbflags,
			   struct dlm_callback **cb);
void dlm_add_cb(struct dlm_lkb *lkb, uint32_t flags, int mode, int status,
                uint32_t sbflags);
void dlm_callback_set_last_ptr(struct dlm_callback **from,
			       struct dlm_callback *to);

void dlm_release_callback(struct kref *ref);
void dlm_callback_work(struct work_struct *work);
int dlm_callback_start(struct dlm_ls *ls);
void dlm_callback_stop(struct dlm_ls *ls);
void dlm_callback_suspend(struct dlm_ls *ls);
+8 −0
Original line number Diff line number Diff line
@@ -63,6 +63,14 @@ static void release_node(struct config_item *);
static struct configfs_attribute *comm_attrs[];
static struct configfs_attribute *node_attrs[];

const struct rhashtable_params dlm_rhash_rsb_params = {
	.nelem_hint = 3, /* start small */
	.key_len = DLM_RESNAME_MAXLEN,
	.key_offset = offsetof(struct dlm_rsb, res_name),
	.head_offset = offsetof(struct dlm_rsb, res_node),
	.automatic_shrinking = true,
};

struct dlm_cluster {
	struct config_group group;
	unsigned int cl_tcp_port;
+2 −0
Original line number Diff line number Diff line
@@ -21,6 +21,8 @@ struct dlm_config_node {
	uint32_t comm_seq;
};

extern const struct rhashtable_params dlm_rhash_rsb_params;

#define DLM_MAX_ADDR_COUNT 3

#define DLM_PROTO_TCP	0
+53 −274
Original line number Diff line number Diff line
@@ -247,7 +247,7 @@ static void print_format3_lock(struct seq_file *s, struct dlm_lkb *lkb,
		   lkb->lkb_status,
		   lkb->lkb_grmode,
		   lkb->lkb_rqmode,
		   lkb->lkb_last_bast_mode,
		   lkb->lkb_last_bast_cb_mode,
		   rsb_lookup,
		   lkb->lkb_wait_type,
		   lkb->lkb_lvbseq,
@@ -366,58 +366,10 @@ static void print_format4(struct dlm_rsb *r, struct seq_file *s)
	unlock_rsb(r);
}

static void print_format5_lock(struct seq_file *s, struct dlm_lkb *lkb)
{
	struct dlm_callback *cb;

	/* lkb_id lkb_flags mode flags sb_status sb_flags */

	spin_lock(&lkb->lkb_cb_lock);
	list_for_each_entry(cb, &lkb->lkb_callbacks, list) {
		seq_printf(s, "%x %x %d %x %d %x\n",
			   lkb->lkb_id,
			   dlm_iflags_val(lkb),
			   cb->mode,
			   cb->flags,
			   cb->sb_status,
			   cb->sb_flags);
	}
	spin_unlock(&lkb->lkb_cb_lock);
}

static void print_format5(struct dlm_rsb *r, struct seq_file *s)
{
	struct dlm_lkb *lkb;

	lock_rsb(r);

	list_for_each_entry(lkb, &r->res_grantqueue, lkb_statequeue) {
		print_format5_lock(s, lkb);
		if (seq_has_overflowed(s))
			goto out;
	}

	list_for_each_entry(lkb, &r->res_convertqueue, lkb_statequeue) {
		print_format5_lock(s, lkb);
		if (seq_has_overflowed(s))
			goto out;
	}

	list_for_each_entry(lkb, &r->res_waitqueue, lkb_statequeue) {
		print_format5_lock(s, lkb);
		if (seq_has_overflowed(s))
			goto out;
	}
 out:
	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
@@ -428,207 +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;
	case 5:
		if (ri->header) {
			seq_puts(seq, "lkb_id lkb_flags mode flags sb_status sb_flags\n");
			ri->header = 0;
		}
		print_format5(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 const struct seq_operations format5_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;
	struct list_head *list;

	if (!*pos) {
		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;
	if (seq->op == &format5_seq_ops)
		ri->format = 5;

	tree = toss ? &ls->ls_rsbtbl[bucket].toss : &ls->ls_rsbtbl[bucket].keep;

	spin_lock(&ls->ls_rsbtbl[bucket].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 (!entry--) {
				dlm_hold_rsb(r);
				ri->rsb = r;
				ri->bucket = bucket;
				spin_unlock(&ls->ls_rsbtbl[bucket].lock);
				return ri;
			}
		}
			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(&ls->ls_rsbtbl[bucket].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 (seq->op == &format4_seq_ops)
		list = &ls->ls_toss;
	else
		list = &ls->ls_keep;

		if (bucket >= ls->ls_rsbtbl_size) {
			kfree(ri);
			return NULL;
		}
		tree = toss ? &ls->ls_rsbtbl[bucket].toss : &ls->ls_rsbtbl[bucket].keep;

		spin_lock(&ls->ls_rsbtbl[bucket].lock);
		if (!RB_EMPTY_ROOT(tree)) {
			node = rb_first(tree);
			r = rb_entry(node, struct dlm_rsb, res_hashnode);
			dlm_hold_rsb(r);
			ri->rsb = r;
			ri->bucket = bucket;
			spin_unlock(&ls->ls_rsbtbl[bucket].lock);
			*pos = n;
			return ri;
		}
		spin_unlock(&ls->ls_rsbtbl[bucket].lock);
	}
	read_lock_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(&ls->ls_rsbtbl[bucket].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(&ls->ls_rsbtbl[bucket].lock);
		dlm_put_rsb(rp);
		++*pos;
		return ri;
	}
	spin_unlock(&ls->ls_rsbtbl[bucket].lock);
	dlm_put_rsb(rp);
	struct list_head *list;

	/*
	 * 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 (seq->op == &format4_seq_ops)
		list = &ls->ls_toss;
	else
		list = &ls->ls_keep;

		if (bucket >= ls->ls_rsbtbl_size) {
			kfree(ri);
			++*pos;
			return NULL;
		}
		tree = toss ? &ls->ls_rsbtbl[bucket].toss : &ls->ls_rsbtbl[bucket].keep;

		spin_lock(&ls->ls_rsbtbl[bucket].lock);
		if (!RB_EMPTY_ROOT(tree)) {
			next = rb_first(tree);
			r = rb_entry(next, struct dlm_rsb, res_hashnode);
			dlm_hold_rsb(r);
			ri->rsb = r;
			ri->bucket = bucket;
			spin_unlock(&ls->ls_rsbtbl[bucket].lock);
			*pos = n;
			return ri;
		}
		spin_unlock(&ls->ls_rsbtbl[bucket].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);
	}
	read_unlock_bh(&ls->ls_rsbtbl_lock);
}

static const struct seq_operations format1_seq_ops = {
@@ -659,18 +465,10 @@ static const struct seq_operations format4_seq_ops = {
	.show  = table_seq_show,
};

static const struct seq_operations format5_seq_ops = {
	.start = table_seq_start,
	.next  = table_seq_next,
	.stop  = table_seq_stop,
	.show  = table_seq_show,
};

static const struct file_operations format1_fops;
static const struct file_operations format2_fops;
static const struct file_operations format3_fops;
static const struct file_operations format4_fops;
static const struct file_operations format5_fops;

static int table_open1(struct inode *inode, struct file *file)
{
@@ -757,20 +555,6 @@ static int table_open4(struct inode *inode, struct file *file)
	return 0;
}

static int table_open5(struct inode *inode, struct file *file)
{
	struct seq_file *seq;
	int ret;

	ret = seq_open(file, &format5_seq_ops);
	if (ret)
		return ret;

	seq = file->private_data;
	seq->private = inode->i_private; /* the dlm_ls */
	return 0;
}

static const struct file_operations format1_fops = {
	.owner   = THIS_MODULE,
	.open    = table_open1,
@@ -804,14 +588,6 @@ static const struct file_operations format4_fops = {
	.release = seq_release
};

static const struct file_operations format5_fops = {
	.owner   = THIS_MODULE,
	.open    = table_open5,
	.read    = seq_read,
	.llseek  = seq_lseek,
	.release = seq_release
};

/*
 * dump lkb's on the ls_waiters list
 */
@@ -823,7 +599,13 @@ static ssize_t waiters_read(struct file *file, char __user *userbuf,
	size_t len = DLM_DEBUG_BUF_LEN, pos = 0, ret, rv;

	mutex_lock(&debug_buf_lock);
	mutex_lock(&ls->ls_waiters_mutex);
	ret = dlm_lock_recovery_try(ls);
	if (!ret) {
		rv = -EAGAIN;
		goto out;
	}

	spin_lock_bh(&ls->ls_waiters_lock);
	memset(debug_buf, 0, sizeof(debug_buf));

	list_for_each_entry(lkb, &ls->ls_waiters, lkb_wait_reply) {
@@ -834,9 +616,11 @@ static ssize_t waiters_read(struct file *file, char __user *userbuf,
			break;
		pos += ret;
	}
	mutex_unlock(&ls->ls_waiters_mutex);
	spin_unlock_bh(&ls->ls_waiters_lock);
	dlm_unlock_recovery(ls);

	rv = simple_read_from_buffer(userbuf, count, ppos, debug_buf, pos);
out:
	mutex_unlock(&debug_buf_lock);
	return rv;
}
@@ -858,7 +642,12 @@ static ssize_t waiters_write(struct file *file, const char __user *user_buf,
	if (n != 3)
		return -EINVAL;

	error = dlm_lock_recovery_try(ls);
	if (!error)
		return -EAGAIN;

	error = dlm_debug_add_lkb_to_waiters(ls, lkb_id, mstype, to_nodeid);
	dlm_unlock_recovery(ls);
	if (error)
		return error;

@@ -1021,16 +810,6 @@ void dlm_create_debug_file(struct dlm_ls *ls)
							  dlm_root,
							  ls,
							  &waiters_fops);

	/* format 5 */

	snprintf(name, sizeof(name), "%s_queued_asts", ls->ls_name);

	ls->ls_debug_queued_asts_dentry = debugfs_create_file(name,
							      0644,
							      dlm_root,
							      ls,
							      &format5_fops);
}

void __init dlm_register_debugfs(void)
Loading