summaryrefslogtreecommitdiffstats
path: root/fs/gfs2/locking/dlm/thread.c
blob: f30350abd62fc3a4b6cfcac5b01546279351e1b0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
/*
 * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
 * Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
 *
 * This copyrighted material is made available to anyone wishing to use,
 * modify, copy, or redistribute it subject to the terms and conditions
 * of the GNU General Public License version 2.
 */

#include "lock_dlm.h"

static inline int no_work(struct gdlm_ls *ls)
{
	int ret;

	spin_lock(&ls->async_lock);
	ret = list_empty(&ls->submit);
	spin_unlock(&ls->async_lock);

	return ret;
}

static inline int check_drop(struct gdlm_ls *ls)
{
	if (!ls->drop_locks_count)
		return 0;

	if (time_after(jiffies, ls->drop_time + ls->drop_locks_period * HZ)) {
		ls->drop_time = jiffies;
		if (ls->all_locks_count >= ls->drop_locks_count)
			return 1;
	}
	return 0;
}

static int gdlm_thread(void *data)
{
	struct gdlm_ls *ls = (struct gdlm_ls *) data;
	struct gdlm_lock *lp = NULL;

	while (!kthread_should_stop()) {
		wait_event_interruptible(ls->thread_wait,
				!no_work(ls) || kthread_should_stop());

		spin_lock(&ls->async_lock);

		if (!list_empty(&ls->submit)) {
			lp = list_entry(ls->submit.next, struct gdlm_lock,
					delay_list);
			list_del_init(&lp->delay_list);
			spin_unlock(&ls->async_lock);
			gdlm_do_lock(lp);
			spin_lock(&ls->async_lock);
		}
		/* Does this ever happen these days? I hope not anyway */
		if (check_drop(ls)) {
			spin_unlock(&ls->async_lock);
			ls->fscb(ls->sdp, LM_CB_DROPLOCKS, NULL);
			spin_lock(&ls->async_lock);
		}
		spin_unlock(&ls->async_lock);
	}

	return 0;
}

int gdlm_init_threads(struct gdlm_ls *ls)
{
	struct task_struct *p;
	int error;

	p = kthread_run(gdlm_thread, ls, "lock_dlm");
	error = IS_ERR(p);
	if (error) {
		log_error("can't start lock_dlm thread %d", error);
		return error;
	}
	ls->thread = p;

	return 0;
}

void gdlm_release_threads(struct gdlm_ls *ls)
{
	kthread_stop(ls->thread);
}