diff options
Diffstat (limited to 'fs/dlm/ast.c')
-rw-r--r-- | fs/dlm/ast.c | 173 |
1 files changed, 173 insertions, 0 deletions
diff --git a/fs/dlm/ast.c b/fs/dlm/ast.c new file mode 100644 index 000000000000..f91d39cb1e0b --- /dev/null +++ b/fs/dlm/ast.c | |||
@@ -0,0 +1,173 @@ | |||
1 | /****************************************************************************** | ||
2 | ******************************************************************************* | ||
3 | ** | ||
4 | ** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. | ||
5 | ** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. | ||
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" | ||
16 | #include "user.h" | ||
17 | |||
18 | #define WAKE_ASTS 0 | ||
19 | |||
20 | static struct list_head ast_queue; | ||
21 | static spinlock_t ast_queue_lock; | ||
22 | static struct task_struct * astd_task; | ||
23 | static unsigned long astd_wakeflags; | ||
24 | static struct mutex astd_running; | ||
25 | |||
26 | |||
27 | void dlm_del_ast(struct dlm_lkb *lkb) | ||
28 | { | ||
29 | spin_lock(&ast_queue_lock); | ||
30 | if (lkb->lkb_ast_type & (AST_COMP | AST_BAST)) | ||
31 | list_del(&lkb->lkb_astqueue); | ||
32 | spin_unlock(&ast_queue_lock); | ||
33 | } | ||
34 | |||
35 | void dlm_add_ast(struct dlm_lkb *lkb, int type) | ||
36 | { | ||
37 | if (lkb->lkb_flags & DLM_IFL_USER) { | ||
38 | dlm_user_add_ast(lkb, type); | ||
39 | return; | ||
40 | } | ||
41 | DLM_ASSERT(lkb->lkb_astaddr != DLM_FAKE_USER_AST, dlm_print_lkb(lkb);); | ||
42 | |||
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; | ||
49 | spin_unlock(&ast_queue_lock); | ||
50 | |||
51 | set_bit(WAKE_ASTS, &astd_wakeflags); | ||
52 | wake_up_process(astd_task); | ||
53 | } | ||
54 | |||
55 | static void process_asts(void) | ||
56 | { | ||
57 | struct dlm_ls *ls = NULL; | ||
58 | struct dlm_rsb *r = NULL; | ||
59 | struct dlm_lkb *lkb; | ||
60 | void (*cast) (long param); | ||
61 | void (*bast) (long param, int mode); | ||
62 | int type = 0, found, bmode; | ||
63 | |||
64 | for (;;) { | ||
65 | found = 0; | ||
66 | spin_lock(&ast_queue_lock); | ||
67 | list_for_each_entry(lkb, &ast_queue, lkb_astqueue) { | ||
68 | r = lkb->lkb_resource; | ||
69 | ls = r->res_ls; | ||
70 | |||
71 | if (dlm_locking_stopped(ls)) | ||
72 | continue; | ||
73 | |||
74 | list_del(&lkb->lkb_astqueue); | ||
75 | type = lkb->lkb_ast_type; | ||
76 | lkb->lkb_ast_type = 0; | ||
77 | found = 1; | ||
78 | break; | ||
79 | } | ||
80 | spin_unlock(&ast_queue_lock); | ||
81 | |||
82 | if (!found) | ||
83 | break; | ||
84 | |||
85 | cast = lkb->lkb_astaddr; | ||
86 | bast = lkb->lkb_bastaddr; | ||
87 | bmode = lkb->lkb_bastmode; | ||
88 | |||
89 | if ((type & AST_COMP) && cast) | ||
90 | cast(lkb->lkb_astparam); | ||
91 | |||
92 | /* FIXME: Is it safe to look at lkb_grmode here | ||
93 | without doing a lock_rsb() ? | ||
94 | Look at other checks in v1 to avoid basts. */ | ||
95 | |||
96 | if ((type & AST_BAST) && bast) | ||
97 | if (!dlm_modes_compat(lkb->lkb_grmode, bmode)) | ||
98 | bast(lkb->lkb_astparam, bmode); | ||
99 | |||
100 | /* this removes the reference added by dlm_add_ast | ||
101 | and may result in the lkb being freed */ | ||
102 | dlm_put_lkb(lkb); | ||
103 | |||
104 | schedule(); | ||
105 | } | ||
106 | } | ||
107 | |||
108 | static inline int no_asts(void) | ||
109 | { | ||
110 | int ret; | ||
111 | |||
112 | spin_lock(&ast_queue_lock); | ||
113 | ret = list_empty(&ast_queue); | ||
114 | spin_unlock(&ast_queue_lock); | ||
115 | return ret; | ||
116 | } | ||
117 | |||
118 | static int dlm_astd(void *data) | ||
119 | { | ||
120 | while (!kthread_should_stop()) { | ||
121 | set_current_state(TASK_INTERRUPTIBLE); | ||
122 | if (!test_bit(WAKE_ASTS, &astd_wakeflags)) | ||
123 | schedule(); | ||
124 | set_current_state(TASK_RUNNING); | ||
125 | |||
126 | mutex_lock(&astd_running); | ||
127 | if (test_and_clear_bit(WAKE_ASTS, &astd_wakeflags)) | ||
128 | process_asts(); | ||
129 | mutex_unlock(&astd_running); | ||
130 | } | ||
131 | return 0; | ||
132 | } | ||
133 | |||
134 | void dlm_astd_wake(void) | ||
135 | { | ||
136 | if (!no_asts()) { | ||
137 | set_bit(WAKE_ASTS, &astd_wakeflags); | ||
138 | wake_up_process(astd_task); | ||
139 | } | ||
140 | } | ||
141 | |||
142 | int dlm_astd_start(void) | ||
143 | { | ||
144 | struct task_struct *p; | ||
145 | int error = 0; | ||
146 | |||
147 | INIT_LIST_HEAD(&ast_queue); | ||
148 | spin_lock_init(&ast_queue_lock); | ||
149 | mutex_init(&astd_running); | ||
150 | |||
151 | p = kthread_run(dlm_astd, NULL, "dlm_astd"); | ||
152 | if (IS_ERR(p)) | ||
153 | error = PTR_ERR(p); | ||
154 | else | ||
155 | astd_task = p; | ||
156 | return error; | ||
157 | } | ||
158 | |||
159 | void dlm_astd_stop(void) | ||
160 | { | ||
161 | kthread_stop(astd_task); | ||
162 | } | ||
163 | |||
164 | void dlm_astd_suspend(void) | ||
165 | { | ||
166 | mutex_lock(&astd_running); | ||
167 | } | ||
168 | |||
169 | void dlm_astd_resume(void) | ||
170 | { | ||
171 | mutex_unlock(&astd_running); | ||
172 | } | ||
173 | |||