Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 97a35d1e authored by David Teigland's avatar David Teigland Committed by Steven Whitehouse
Browse files

[DLM] fix grant_after_purge softlockup



In dlm_grant_after_purge() we were holding a hash table read_lock while
calling put_rsb() which potentially removes the rsb from the hash table,
taking the same lock in write.  Fix this by flagging rsb's ahead of time
that have been purged.  Then iteratively read_lock the hash table, find a
flagged rsb, unlock, process rsb.

Signed-off-by: default avatarDavid Teigland <teigland@redhat.com>
Signed-off-by: default avatarSteven Whitehouse <swhiteho@redhat.com>
parent d2d7b8a2
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -280,6 +280,7 @@ enum rsb_flags {
	RSB_NEW_MASTER,
	RSB_NEW_MASTER2,
	RSB_RECOVER_CONVERT,
	RSB_LOCKS_PURGED,
};

static inline void rsb_set_flag(struct dlm_rsb *r, enum rsb_flags flag)
+28 −14
Original line number Diff line number Diff line
@@ -3278,6 +3278,7 @@ static void purge_queue(struct dlm_rsb *r, struct list_head *queue,

	list_for_each_entry_safe(lkb, safe, queue, lkb_statequeue) {
		if (test(ls, lkb)) {
			rsb_set_flag(r, RSB_LOCKS_PURGED);
			del_lkb(r, lkb);
			/* this put should free the lkb */
			if (!dlm_put_lkb(lkb))
@@ -3334,15 +3335,32 @@ int dlm_purge_locks(struct dlm_ls *ls)
	return 0;
}

int dlm_grant_after_purge(struct dlm_ls *ls)
static struct dlm_rsb *find_purged_rsb(struct dlm_ls *ls, int bucket)
{
	struct dlm_rsb *r, *r_ret = NULL;

	read_lock(&ls->ls_rsbtbl[bucket].lock);
	list_for_each_entry(r, &ls->ls_rsbtbl[bucket].list, res_hashchain) {
		if (!rsb_flag(r, RSB_LOCKS_PURGED))
			continue;
		hold_rsb(r);
		rsb_clear_flag(r, RSB_LOCKS_PURGED);
		r_ret = r;
		break;
	}
	read_unlock(&ls->ls_rsbtbl[bucket].lock);
	return r_ret;
}

void dlm_grant_after_purge(struct dlm_ls *ls)
{
	struct dlm_rsb *r;
	int i;

	for (i = 0; i < ls->ls_rsbtbl_size; i++) {
		read_lock(&ls->ls_rsbtbl[i].lock);
		list_for_each_entry(r, &ls->ls_rsbtbl[i].list, res_hashchain) {
			hold_rsb(r);
		r = find_purged_rsb(ls, i);
		if (!r)
			continue;
		lock_rsb(r);
		if (is_master(r)) {
			grant_pending_locks(r);
@@ -3351,10 +3369,6 @@ int dlm_grant_after_purge(struct dlm_ls *ls)
		unlock_rsb(r);
		put_rsb(r);
	}
		read_unlock(&ls->ls_rsbtbl[i].lock);
	}

	return 0;
}

static struct dlm_lkb *search_remid_list(struct list_head *head, int nodeid,
+1 −1
Original line number Diff line number Diff line
@@ -25,7 +25,7 @@ void dlm_scan_rsbs(struct dlm_ls *ls);

int dlm_purge_locks(struct dlm_ls *ls);
void dlm_purge_mstcpy_locks(struct dlm_rsb *r);
int dlm_grant_after_purge(struct dlm_ls *ls);
void dlm_grant_after_purge(struct dlm_ls *ls);
int dlm_recover_waiters_post(struct dlm_ls *ls);
void dlm_recover_waiters_pre(struct dlm_ls *ls);
int dlm_recover_master_copy(struct dlm_ls *ls, struct dlm_rcom *rc);