Commit | Line | Data |
---|---|---|
e7fd4179 DT |
1 | /****************************************************************************** |
2 | ******************************************************************************* | |
3 | ** | |
4 | ** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. | |
fd22a51b | 5 | ** Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved. |
e7fd4179 DT |
6 | ** |
7 | ** This copyrighted material is made available to anyone wishing to use, | |
8 | ** modify, copy, or redistribute it subject to the terms and conditions | |
9 | ** of the GNU General Public License v.2. | |
10 | ** | |
11 | ******************************************************************************* | |
12 | ******************************************************************************/ | |
13 | ||
14 | #include "dlm_internal.h" | |
15 | #include "lock.h" | |
597d0cae | 16 | #include "user.h" |
8fa1de38 | 17 | #include "ast.h" |
e7fd4179 DT |
18 | |
19 | #define WAKE_ASTS 0 | |
20 | ||
21 | static struct list_head ast_queue; | |
22 | static spinlock_t ast_queue_lock; | |
23 | static struct task_struct * astd_task; | |
24 | static unsigned long astd_wakeflags; | |
90135925 | 25 | static struct mutex astd_running; |
e7fd4179 DT |
26 | |
27 | ||
28 | void dlm_del_ast(struct dlm_lkb *lkb) | |
29 | { | |
30 | spin_lock(&ast_queue_lock); | |
31 | if (lkb->lkb_ast_type & (AST_COMP | AST_BAST)) | |
32 | list_del(&lkb->lkb_astqueue); | |
33 | spin_unlock(&ast_queue_lock); | |
34 | } | |
35 | ||
fd22a51b | 36 | void dlm_add_ast(struct dlm_lkb *lkb, int type, int bastmode) |
e7fd4179 | 37 | { |
597d0cae | 38 | if (lkb->lkb_flags & DLM_IFL_USER) { |
fd22a51b | 39 | dlm_user_add_ast(lkb, type, bastmode); |
597d0cae DT |
40 | return; |
41 | } | |
42 | ||
e7fd4179 DT |
43 | spin_lock(&ast_queue_lock); |
44 | if (!(lkb->lkb_ast_type & (AST_COMP | AST_BAST))) { | |
45 | kref_get(&lkb->lkb_ref); | |
46 | list_add_tail(&lkb->lkb_astqueue, &ast_queue); | |
47 | } | |
48 | lkb->lkb_ast_type |= type; | |
fd22a51b DT |
49 | if (bastmode) |
50 | lkb->lkb_bastmode = bastmode; | |
e7fd4179 DT |
51 | spin_unlock(&ast_queue_lock); |
52 | ||
53 | set_bit(WAKE_ASTS, &astd_wakeflags); | |
54 | wake_up_process(astd_task); | |
55 | } | |
56 | ||
57 | static void process_asts(void) | |
58 | { | |
59 | struct dlm_ls *ls = NULL; | |
60 | struct dlm_rsb *r = NULL; | |
61 | struct dlm_lkb *lkb; | |
e5dae548 DT |
62 | void (*cast) (void *astparam); |
63 | void (*bast) (void *astparam, int mode); | |
722d7421 AM |
64 | int type = 0, bastmode; |
65 | ||
66 | repeat: | |
67 | spin_lock(&ast_queue_lock); | |
68 | list_for_each_entry(lkb, &ast_queue, lkb_astqueue) { | |
69 | r = lkb->lkb_resource; | |
70 | ls = r->res_ls; | |
e7fd4179 | 71 | |
722d7421 AM |
72 | if (dlm_locking_stopped(ls)) |
73 | continue; | |
e7fd4179 | 74 | |
722d7421 AM |
75 | list_del(&lkb->lkb_astqueue); |
76 | type = lkb->lkb_ast_type; | |
77 | lkb->lkb_ast_type = 0; | |
78 | bastmode = lkb->lkb_bastmode; | |
79 | ||
80 | spin_unlock(&ast_queue_lock); | |
e5dae548 DT |
81 | cast = lkb->lkb_astfn; |
82 | bast = lkb->lkb_bastfn; | |
e7fd4179 DT |
83 | |
84 | if ((type & AST_COMP) && cast) | |
85 | cast(lkb->lkb_astparam); | |
86 | ||
e7fd4179 | 87 | if ((type & AST_BAST) && bast) |
fd22a51b | 88 | bast(lkb->lkb_astparam, bastmode); |
e7fd4179 DT |
89 | |
90 | /* this removes the reference added by dlm_add_ast | |
91 | and may result in the lkb being freed */ | |
92 | dlm_put_lkb(lkb); | |
93 | ||
d61e9aac | 94 | cond_resched(); |
722d7421 | 95 | goto repeat; |
e7fd4179 | 96 | } |
722d7421 | 97 | spin_unlock(&ast_queue_lock); |
e7fd4179 DT |
98 | } |
99 | ||
100 | static inline int no_asts(void) | |
101 | { | |
102 | int ret; | |
103 | ||
104 | spin_lock(&ast_queue_lock); | |
105 | ret = list_empty(&ast_queue); | |
106 | spin_unlock(&ast_queue_lock); | |
107 | return ret; | |
108 | } | |
109 | ||
110 | static int dlm_astd(void *data) | |
111 | { | |
112 | while (!kthread_should_stop()) { | |
113 | set_current_state(TASK_INTERRUPTIBLE); | |
114 | if (!test_bit(WAKE_ASTS, &astd_wakeflags)) | |
115 | schedule(); | |
116 | set_current_state(TASK_RUNNING); | |
117 | ||
90135925 | 118 | mutex_lock(&astd_running); |
e7fd4179 DT |
119 | if (test_and_clear_bit(WAKE_ASTS, &astd_wakeflags)) |
120 | process_asts(); | |
90135925 | 121 | mutex_unlock(&astd_running); |
e7fd4179 DT |
122 | } |
123 | return 0; | |
124 | } | |
125 | ||
126 | void dlm_astd_wake(void) | |
127 | { | |
128 | if (!no_asts()) { | |
129 | set_bit(WAKE_ASTS, &astd_wakeflags); | |
130 | wake_up_process(astd_task); | |
131 | } | |
132 | } | |
133 | ||
134 | int dlm_astd_start(void) | |
135 | { | |
136 | struct task_struct *p; | |
137 | int error = 0; | |
138 | ||
139 | INIT_LIST_HEAD(&ast_queue); | |
140 | spin_lock_init(&ast_queue_lock); | |
90135925 | 141 | mutex_init(&astd_running); |
e7fd4179 DT |
142 | |
143 | p = kthread_run(dlm_astd, NULL, "dlm_astd"); | |
144 | if (IS_ERR(p)) | |
145 | error = PTR_ERR(p); | |
146 | else | |
147 | astd_task = p; | |
148 | return error; | |
149 | } | |
150 | ||
151 | void dlm_astd_stop(void) | |
152 | { | |
153 | kthread_stop(astd_task); | |
154 | } | |
155 | ||
156 | void dlm_astd_suspend(void) | |
157 | { | |
90135925 | 158 | mutex_lock(&astd_running); |
e7fd4179 DT |
159 | } |
160 | ||
161 | void dlm_astd_resume(void) | |
162 | { | |
90135925 | 163 | mutex_unlock(&astd_running); |
e7fd4179 DT |
164 | } |
165 |