diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/dlm/ast.c | 257 | ||||
-rw-r--r-- | fs/dlm/ast.h | 7 | ||||
-rw-r--r-- | fs/dlm/debug_fs.c | 4 | ||||
-rw-r--r-- | fs/dlm/dlm_internal.h | 35 | ||||
-rw-r--r-- | fs/dlm/lock.c | 38 | ||||
-rw-r--r-- | fs/dlm/rcom.c | 4 | ||||
-rw-r--r-- | fs/dlm/user.c | 185 | ||||
-rw-r--r-- | fs/dlm/user.h | 3 |
8 files changed, 311 insertions, 222 deletions
diff --git a/fs/dlm/ast.c b/fs/dlm/ast.c index 4314f0d48d85..abc49f292454 100644 --- a/fs/dlm/ast.c +++ b/fs/dlm/ast.c | |||
@@ -18,6 +18,7 @@ | |||
18 | 18 | ||
19 | #define WAKE_ASTS 0 | 19 | #define WAKE_ASTS 0 |
20 | 20 | ||
21 | static uint64_t ast_seq_count; | ||
21 | static struct list_head ast_queue; | 22 | static struct list_head ast_queue; |
22 | static spinlock_t ast_queue_lock; | 23 | static spinlock_t ast_queue_lock; |
23 | static struct task_struct * astd_task; | 24 | static struct task_struct * astd_task; |
@@ -25,40 +26,186 @@ static unsigned long astd_wakeflags; | |||
25 | static struct mutex astd_running; | 26 | static struct mutex astd_running; |
26 | 27 | ||
27 | 28 | ||
29 | static void dlm_dump_lkb_callbacks(struct dlm_lkb *lkb) | ||
30 | { | ||
31 | int i; | ||
32 | |||
33 | log_print("last_bast %x %llu flags %x mode %d sb %d %x", | ||
34 | lkb->lkb_id, | ||
35 | (unsigned long long)lkb->lkb_last_bast.seq, | ||
36 | lkb->lkb_last_bast.flags, | ||
37 | lkb->lkb_last_bast.mode, | ||
38 | lkb->lkb_last_bast.sb_status, | ||
39 | lkb->lkb_last_bast.sb_flags); | ||
40 | |||
41 | log_print("last_cast %x %llu flags %x mode %d sb %d %x", | ||
42 | lkb->lkb_id, | ||
43 | (unsigned long long)lkb->lkb_last_cast.seq, | ||
44 | lkb->lkb_last_cast.flags, | ||
45 | lkb->lkb_last_cast.mode, | ||
46 | lkb->lkb_last_cast.sb_status, | ||
47 | lkb->lkb_last_cast.sb_flags); | ||
48 | |||
49 | for (i = 0; i < DLM_CALLBACKS_SIZE; i++) { | ||
50 | log_print("cb %x %llu flags %x mode %d sb %d %x", | ||
51 | lkb->lkb_id, | ||
52 | (unsigned long long)lkb->lkb_callbacks[i].seq, | ||
53 | lkb->lkb_callbacks[i].flags, | ||
54 | lkb->lkb_callbacks[i].mode, | ||
55 | lkb->lkb_callbacks[i].sb_status, | ||
56 | lkb->lkb_callbacks[i].sb_flags); | ||
57 | } | ||
58 | } | ||
59 | |||
28 | void dlm_del_ast(struct dlm_lkb *lkb) | 60 | void dlm_del_ast(struct dlm_lkb *lkb) |
29 | { | 61 | { |
30 | spin_lock(&ast_queue_lock); | 62 | spin_lock(&ast_queue_lock); |
31 | if (lkb->lkb_ast_type & (AST_COMP | AST_BAST)) | 63 | if (!list_empty(&lkb->lkb_astqueue)) |
32 | list_del(&lkb->lkb_astqueue); | 64 | list_del_init(&lkb->lkb_astqueue); |
33 | spin_unlock(&ast_queue_lock); | 65 | spin_unlock(&ast_queue_lock); |
34 | } | 66 | } |
35 | 67 | ||
36 | void dlm_add_ast(struct dlm_lkb *lkb, int type, int mode) | 68 | int dlm_add_lkb_callback(struct dlm_lkb *lkb, uint32_t flags, int mode, |
69 | int status, uint32_t sbflags, uint64_t seq) | ||
37 | { | 70 | { |
71 | struct dlm_ls *ls = lkb->lkb_resource->res_ls; | ||
72 | uint64_t prev_seq; | ||
73 | int prev_mode; | ||
74 | int i; | ||
75 | |||
76 | for (i = 0; i < DLM_CALLBACKS_SIZE; i++) { | ||
77 | if (lkb->lkb_callbacks[i].seq) | ||
78 | continue; | ||
79 | |||
80 | /* | ||
81 | * Suppress some redundant basts here, do more on removal. | ||
82 | * Don't even add a bast if the callback just before it | ||
83 | * is a bast for the same mode or a more restrictive mode. | ||
84 | * (the addional > PR check is needed for PR/CW inversion) | ||
85 | */ | ||
86 | |||
87 | if ((i > 0) && (flags & DLM_CB_BAST) && | ||
88 | (lkb->lkb_callbacks[i-1].flags & DLM_CB_BAST)) { | ||
89 | |||
90 | prev_seq = lkb->lkb_callbacks[i-1].seq; | ||
91 | prev_mode = lkb->lkb_callbacks[i-1].mode; | ||
92 | |||
93 | if ((prev_mode == mode) || | ||
94 | (prev_mode > mode && prev_mode > DLM_LOCK_PR)) { | ||
95 | |||
96 | log_debug(ls, "skip %x add bast %llu mode %d " | ||
97 | "for bast %llu mode %d", | ||
98 | lkb->lkb_id, | ||
99 | (unsigned long long)seq, | ||
100 | mode, | ||
101 | (unsigned long long)prev_seq, | ||
102 | prev_mode); | ||
103 | return 0; | ||
104 | } | ||
105 | } | ||
106 | |||
107 | lkb->lkb_callbacks[i].seq = seq; | ||
108 | lkb->lkb_callbacks[i].flags = flags; | ||
109 | lkb->lkb_callbacks[i].mode = mode; | ||
110 | lkb->lkb_callbacks[i].sb_status = status; | ||
111 | lkb->lkb_callbacks[i].sb_flags = (sbflags & 0x000000FF); | ||
112 | break; | ||
113 | } | ||
114 | |||
115 | if (i == DLM_CALLBACKS_SIZE) { | ||
116 | log_error(ls, "no callbacks %x %llu flags %x mode %d sb %d %x", | ||
117 | lkb->lkb_id, (unsigned long long)seq, | ||
118 | flags, mode, status, sbflags); | ||
119 | dlm_dump_lkb_callbacks(lkb); | ||
120 | return -1; | ||
121 | } | ||
122 | |||
123 | return 0; | ||
124 | } | ||
125 | |||
126 | int dlm_rem_lkb_callback(struct dlm_ls *ls, struct dlm_lkb *lkb, | ||
127 | struct dlm_callback *cb, int *resid) | ||
128 | { | ||
129 | int i; | ||
130 | |||
131 | *resid = 0; | ||
132 | |||
133 | if (!lkb->lkb_callbacks[0].seq) | ||
134 | return -ENOENT; | ||
135 | |||
136 | /* oldest undelivered cb is callbacks[0] */ | ||
137 | |||
138 | memcpy(cb, &lkb->lkb_callbacks[0], sizeof(struct dlm_callback)); | ||
139 | memset(&lkb->lkb_callbacks[0], 0, sizeof(struct dlm_callback)); | ||
140 | |||
141 | /* shift others down */ | ||
142 | |||
143 | for (i = 1; i < DLM_CALLBACKS_SIZE; i++) { | ||
144 | if (!lkb->lkb_callbacks[i].seq) | ||
145 | break; | ||
146 | memcpy(&lkb->lkb_callbacks[i-1], &lkb->lkb_callbacks[i], | ||
147 | sizeof(struct dlm_callback)); | ||
148 | memset(&lkb->lkb_callbacks[i], 0, sizeof(struct dlm_callback)); | ||
149 | (*resid)++; | ||
150 | } | ||
151 | |||
152 | /* if cb is a bast, it should be skipped if the blocking mode is | ||
153 | compatible with the last granted mode */ | ||
154 | |||
155 | if ((cb->flags & DLM_CB_BAST) && lkb->lkb_last_cast.seq) { | ||
156 | if (dlm_modes_compat(cb->mode, lkb->lkb_last_cast.mode)) { | ||
157 | cb->flags |= DLM_CB_SKIP; | ||
158 | |||
159 | log_debug(ls, "skip %x bast %llu mode %d " | ||
160 | "for cast %llu mode %d", | ||
161 | lkb->lkb_id, | ||
162 | (unsigned long long)cb->seq, | ||
163 | cb->mode, | ||
164 | (unsigned long long)lkb->lkb_last_cast.seq, | ||
165 | lkb->lkb_last_cast.mode); | ||
166 | return 0; | ||
167 | } | ||
168 | } | ||
169 | |||
170 | if (cb->flags & DLM_CB_CAST) { | ||
171 | memcpy(&lkb->lkb_last_cast, cb, sizeof(struct dlm_callback)); | ||
172 | lkb->lkb_last_cast_time = ktime_get(); | ||
173 | } | ||
174 | |||
175 | if (cb->flags & DLM_CB_BAST) { | ||
176 | memcpy(&lkb->lkb_last_bast, cb, sizeof(struct dlm_callback)); | ||
177 | lkb->lkb_last_bast_time = ktime_get(); | ||
178 | } | ||
179 | |||
180 | return 0; | ||
181 | } | ||
182 | |||
183 | void dlm_add_ast(struct dlm_lkb *lkb, uint32_t flags, int mode, int status, | ||
184 | uint32_t sbflags) | ||
185 | { | ||
186 | uint64_t seq; | ||
187 | int rv; | ||
188 | |||
189 | spin_lock(&ast_queue_lock); | ||
190 | |||
191 | seq = ++ast_seq_count; | ||
192 | |||
38 | if (lkb->lkb_flags & DLM_IFL_USER) { | 193 | if (lkb->lkb_flags & DLM_IFL_USER) { |
39 | dlm_user_add_ast(lkb, type, mode); | 194 | spin_unlock(&ast_queue_lock); |
195 | dlm_user_add_ast(lkb, flags, mode, status, sbflags, seq); | ||
40 | return; | 196 | return; |
41 | } | 197 | } |
42 | 198 | ||
43 | spin_lock(&ast_queue_lock); | 199 | rv = dlm_add_lkb_callback(lkb, flags, mode, status, sbflags, seq); |
44 | if (!(lkb->lkb_ast_type & (AST_COMP | AST_BAST))) { | 200 | if (rv < 0) { |
201 | spin_unlock(&ast_queue_lock); | ||
202 | return; | ||
203 | } | ||
204 | |||
205 | if (list_empty(&lkb->lkb_astqueue)) { | ||
45 | kref_get(&lkb->lkb_ref); | 206 | kref_get(&lkb->lkb_ref); |
46 | list_add_tail(&lkb->lkb_astqueue, &ast_queue); | 207 | list_add_tail(&lkb->lkb_astqueue, &ast_queue); |
47 | lkb->lkb_ast_first = type; | ||
48 | } | 208 | } |
49 | |||
50 | /* sanity check, this should not happen */ | ||
51 | |||
52 | if ((type == AST_COMP) && (lkb->lkb_ast_type & AST_COMP)) | ||
53 | log_print("repeat cast %d castmode %d lock %x %s", | ||
54 | mode, lkb->lkb_castmode, | ||
55 | lkb->lkb_id, lkb->lkb_resource->res_name); | ||
56 | |||
57 | lkb->lkb_ast_type |= type; | ||
58 | if (type == AST_BAST) | ||
59 | lkb->lkb_bastmode = mode; | ||
60 | else | ||
61 | lkb->lkb_castmode = mode; | ||
62 | spin_unlock(&ast_queue_lock); | 209 | spin_unlock(&ast_queue_lock); |
63 | 210 | ||
64 | set_bit(WAKE_ASTS, &astd_wakeflags); | 211 | set_bit(WAKE_ASTS, &astd_wakeflags); |
@@ -72,7 +219,8 @@ static void process_asts(void) | |||
72 | struct dlm_lkb *lkb; | 219 | struct dlm_lkb *lkb; |
73 | void (*castfn) (void *astparam); | 220 | void (*castfn) (void *astparam); |
74 | void (*bastfn) (void *astparam, int mode); | 221 | void (*bastfn) (void *astparam, int mode); |
75 | int type, first, bastmode, castmode, do_bast, do_cast, last_castmode; | 222 | struct dlm_callback callbacks[DLM_CALLBACKS_SIZE]; |
223 | int i, rv, resid; | ||
76 | 224 | ||
77 | repeat: | 225 | repeat: |
78 | spin_lock(&ast_queue_lock); | 226 | spin_lock(&ast_queue_lock); |
@@ -83,54 +231,45 @@ repeat: | |||
83 | if (dlm_locking_stopped(ls)) | 231 | if (dlm_locking_stopped(ls)) |
84 | continue; | 232 | continue; |
85 | 233 | ||
86 | list_del(&lkb->lkb_astqueue); | 234 | /* we remove from astqueue list and remove everything in |
87 | type = lkb->lkb_ast_type; | 235 | lkb_callbacks before releasing the spinlock so empty |
88 | lkb->lkb_ast_type = 0; | 236 | lkb_astqueue is always consistent with empty lkb_callbacks */ |
89 | first = lkb->lkb_ast_first; | 237 | |
90 | lkb->lkb_ast_first = 0; | 238 | list_del_init(&lkb->lkb_astqueue); |
91 | bastmode = lkb->lkb_bastmode; | 239 | |
92 | castmode = lkb->lkb_castmode; | ||
93 | castfn = lkb->lkb_astfn; | 240 | castfn = lkb->lkb_astfn; |
94 | bastfn = lkb->lkb_bastfn; | 241 | bastfn = lkb->lkb_bastfn; |
95 | spin_unlock(&ast_queue_lock); | ||
96 | 242 | ||
97 | do_cast = (type & AST_COMP) && castfn; | 243 | memset(&callbacks, 0, sizeof(callbacks)); |
98 | do_bast = (type & AST_BAST) && bastfn; | ||
99 | 244 | ||
100 | /* Skip a bast if its blocking mode is compatible with the | 245 | for (i = 0; i < DLM_CALLBACKS_SIZE; i++) { |
101 | granted mode of the preceding cast. */ | 246 | rv = dlm_rem_lkb_callback(ls, lkb, &callbacks[i], &resid); |
247 | if (rv < 0) | ||
248 | break; | ||
249 | } | ||
250 | spin_unlock(&ast_queue_lock); | ||
102 | 251 | ||
103 | if (do_bast) { | 252 | if (resid) { |
104 | if (first == AST_COMP) | 253 | /* shouldn't happen, for loop should have removed all */ |
105 | last_castmode = castmode; | 254 | log_error(ls, "callback resid %d lkb %x", |
106 | else | 255 | resid, lkb->lkb_id); |
107 | last_castmode = lkb->lkb_castmode_done; | ||
108 | if (dlm_modes_compat(bastmode, last_castmode)) | ||
109 | do_bast = 0; | ||
110 | } | 256 | } |
111 | 257 | ||
112 | if (first == AST_COMP) { | 258 | for (i = 0; i < DLM_CALLBACKS_SIZE; i++) { |
113 | if (do_cast) | 259 | if (!callbacks[i].seq) |
114 | castfn(lkb->lkb_astparam); | 260 | break; |
115 | if (do_bast) | 261 | if (callbacks[i].flags & DLM_CB_SKIP) { |
116 | bastfn(lkb->lkb_astparam, bastmode); | 262 | continue; |
117 | } else if (first == AST_BAST) { | 263 | } else if (callbacks[i].flags & DLM_CB_BAST) { |
118 | if (do_bast) | 264 | bastfn(lkb->lkb_astparam, callbacks[i].mode); |
119 | bastfn(lkb->lkb_astparam, bastmode); | 265 | } else if (callbacks[i].flags & DLM_CB_CAST) { |
120 | if (do_cast) | 266 | lkb->lkb_lksb->sb_status = callbacks[i].sb_status; |
267 | lkb->lkb_lksb->sb_flags = callbacks[i].sb_flags; | ||
121 | castfn(lkb->lkb_astparam); | 268 | castfn(lkb->lkb_astparam); |
122 | } else { | 269 | } |
123 | log_error(ls, "bad ast_first %d ast_type %d", | ||
124 | first, type); | ||
125 | } | 270 | } |
126 | 271 | ||
127 | if (do_cast) | 272 | /* removes ref for ast_queue, may cause lkb to be freed */ |
128 | lkb->lkb_castmode_done = castmode; | ||
129 | if (do_bast) | ||
130 | lkb->lkb_bastmode_done = bastmode; | ||
131 | |||
132 | /* this removes the reference added by dlm_add_ast | ||
133 | and may result in the lkb being freed */ | ||
134 | dlm_put_lkb(lkb); | 273 | dlm_put_lkb(lkb); |
135 | 274 | ||
136 | cond_resched(); | 275 | cond_resched(); |
diff --git a/fs/dlm/ast.h b/fs/dlm/ast.h index bcb1aaba519d..8aa89c9b5611 100644 --- a/fs/dlm/ast.h +++ b/fs/dlm/ast.h | |||
@@ -13,8 +13,13 @@ | |||
13 | #ifndef __ASTD_DOT_H__ | 13 | #ifndef __ASTD_DOT_H__ |
14 | #define __ASTD_DOT_H__ | 14 | #define __ASTD_DOT_H__ |
15 | 15 | ||
16 | void dlm_add_ast(struct dlm_lkb *lkb, int type, int mode); | ||
17 | void dlm_del_ast(struct dlm_lkb *lkb); | 16 | void dlm_del_ast(struct dlm_lkb *lkb); |
17 | int dlm_add_lkb_callback(struct dlm_lkb *lkb, uint32_t flags, int mode, | ||
18 | int status, uint32_t sbflags, uint64_t seq); | ||
19 | int dlm_rem_lkb_callback(struct dlm_ls *ls, struct dlm_lkb *lkb, | ||
20 | struct dlm_callback *cb, int *resid); | ||
21 | void dlm_add_ast(struct dlm_lkb *lkb, uint32_t flags, int mode, int status, | ||
22 | uint32_t sbflags); | ||
18 | 23 | ||
19 | void dlm_astd_wake(void); | 24 | void dlm_astd_wake(void); |
20 | int dlm_astd_start(void); | 25 | int dlm_astd_start(void); |
diff --git a/fs/dlm/debug_fs.c b/fs/dlm/debug_fs.c index 6b42ba807dfd..59779237e2b4 100644 --- a/fs/dlm/debug_fs.c +++ b/fs/dlm/debug_fs.c | |||
@@ -257,12 +257,12 @@ static int print_format3_lock(struct seq_file *s, struct dlm_lkb *lkb, | |||
257 | lkb->lkb_status, | 257 | lkb->lkb_status, |
258 | lkb->lkb_grmode, | 258 | lkb->lkb_grmode, |
259 | lkb->lkb_rqmode, | 259 | lkb->lkb_rqmode, |
260 | lkb->lkb_bastmode, | 260 | lkb->lkb_last_bast.mode, |
261 | rsb_lookup, | 261 | rsb_lookup, |
262 | lkb->lkb_wait_type, | 262 | lkb->lkb_wait_type, |
263 | lkb->lkb_lvbseq, | 263 | lkb->lkb_lvbseq, |
264 | (unsigned long long)ktime_to_ns(lkb->lkb_timestamp), | 264 | (unsigned long long)ktime_to_ns(lkb->lkb_timestamp), |
265 | (unsigned long long)ktime_to_ns(lkb->lkb_time_bast)); | 265 | (unsigned long long)ktime_to_ns(lkb->lkb_last_bast_time)); |
266 | return rv; | 266 | return rv; |
267 | } | 267 | } |
268 | 268 | ||
diff --git a/fs/dlm/dlm_internal.h b/fs/dlm/dlm_internal.h index f632b58cd222..b94204913011 100644 --- a/fs/dlm/dlm_internal.h +++ b/fs/dlm/dlm_internal.h | |||
@@ -192,11 +192,6 @@ struct dlm_args { | |||
192 | * lkb is a process copy, the nodeid specifies the lock master. | 192 | * lkb is a process copy, the nodeid specifies the lock master. |
193 | */ | 193 | */ |
194 | 194 | ||
195 | /* lkb_ast_type */ | ||
196 | |||
197 | #define AST_COMP 1 | ||
198 | #define AST_BAST 2 | ||
199 | |||
200 | /* lkb_status */ | 195 | /* lkb_status */ |
201 | 196 | ||
202 | #define DLM_LKSTS_WAITING 1 | 197 | #define DLM_LKSTS_WAITING 1 |
@@ -217,6 +212,20 @@ struct dlm_args { | |||
217 | #define DLM_IFL_USER 0x00000001 | 212 | #define DLM_IFL_USER 0x00000001 |
218 | #define DLM_IFL_ORPHAN 0x00000002 | 213 | #define DLM_IFL_ORPHAN 0x00000002 |
219 | 214 | ||
215 | #define DLM_CALLBACKS_SIZE 6 | ||
216 | |||
217 | #define DLM_CB_CAST 0x00000001 | ||
218 | #define DLM_CB_BAST 0x00000002 | ||
219 | #define DLM_CB_SKIP 0x00000004 | ||
220 | |||
221 | struct dlm_callback { | ||
222 | uint64_t seq; | ||
223 | uint32_t flags; /* DLM_CBF_ */ | ||
224 | int sb_status; /* copy to lksb status */ | ||
225 | uint8_t sb_flags; /* copy to lksb flags */ | ||
226 | int8_t mode; /* rq mode of bast, gr mode of cast */ | ||
227 | }; | ||
228 | |||
220 | struct dlm_lkb { | 229 | struct dlm_lkb { |
221 | struct dlm_rsb *lkb_resource; /* the rsb */ | 230 | struct dlm_rsb *lkb_resource; /* the rsb */ |
222 | struct kref lkb_ref; | 231 | struct kref lkb_ref; |
@@ -236,13 +245,6 @@ struct dlm_lkb { | |||
236 | 245 | ||
237 | int8_t lkb_wait_type; /* type of reply waiting for */ | 246 | int8_t lkb_wait_type; /* type of reply waiting for */ |
238 | int8_t lkb_wait_count; | 247 | int8_t lkb_wait_count; |
239 | int8_t lkb_ast_type; /* type of ast queued for */ | ||
240 | int8_t lkb_ast_first; /* type of first ast queued */ | ||
241 | |||
242 | int8_t lkb_bastmode; /* req mode of queued bast */ | ||
243 | int8_t lkb_castmode; /* gr mode of queued cast */ | ||
244 | int8_t lkb_bastmode_done; /* last delivered bastmode */ | ||
245 | int8_t lkb_castmode_done; /* last delivered castmode */ | ||
246 | 248 | ||
247 | struct list_head lkb_idtbl_list; /* lockspace lkbtbl */ | 249 | struct list_head lkb_idtbl_list; /* lockspace lkbtbl */ |
248 | struct list_head lkb_statequeue; /* rsb g/c/w list */ | 250 | struct list_head lkb_statequeue; /* rsb g/c/w list */ |
@@ -251,10 +253,15 @@ struct dlm_lkb { | |||
251 | struct list_head lkb_astqueue; /* need ast to be sent */ | 253 | struct list_head lkb_astqueue; /* need ast to be sent */ |
252 | struct list_head lkb_ownqueue; /* list of locks for a process */ | 254 | struct list_head lkb_ownqueue; /* list of locks for a process */ |
253 | struct list_head lkb_time_list; | 255 | struct list_head lkb_time_list; |
254 | ktime_t lkb_time_bast; /* for debugging */ | ||
255 | ktime_t lkb_timestamp; | 256 | ktime_t lkb_timestamp; |
256 | unsigned long lkb_timeout_cs; | 257 | unsigned long lkb_timeout_cs; |
257 | 258 | ||
259 | struct dlm_callback lkb_callbacks[DLM_CALLBACKS_SIZE]; | ||
260 | struct dlm_callback lkb_last_cast; | ||
261 | struct dlm_callback lkb_last_bast; | ||
262 | ktime_t lkb_last_cast_time; /* for debugging */ | ||
263 | ktime_t lkb_last_bast_time; /* for debugging */ | ||
264 | |||
258 | char *lkb_lvbptr; | 265 | char *lkb_lvbptr; |
259 | struct dlm_lksb *lkb_lksb; /* caller's status block */ | 266 | struct dlm_lksb *lkb_lksb; /* caller's status block */ |
260 | void (*lkb_astfn) (void *astparam); | 267 | void (*lkb_astfn) (void *astparam); |
@@ -544,8 +551,6 @@ struct dlm_user_args { | |||
544 | (dlm_user_proc) on the struct file, | 551 | (dlm_user_proc) on the struct file, |
545 | the process's locks point back to it*/ | 552 | the process's locks point back to it*/ |
546 | struct dlm_lksb lksb; | 553 | struct dlm_lksb lksb; |
547 | int old_mode; | ||
548 | int update_user_lvb; | ||
549 | struct dlm_lksb __user *user_lksb; | 554 | struct dlm_lksb __user *user_lksb; |
550 | void __user *castparam; | 555 | void __user *castparam; |
551 | void __user *castaddr; | 556 | void __user *castaddr; |
diff --git a/fs/dlm/lock.c b/fs/dlm/lock.c index 64e5f3efdd81..04b8c449303f 100644 --- a/fs/dlm/lock.c +++ b/fs/dlm/lock.c | |||
@@ -160,10 +160,10 @@ static const int __quecvt_compat_matrix[8][8] = { | |||
160 | void dlm_print_lkb(struct dlm_lkb *lkb) | 160 | void dlm_print_lkb(struct dlm_lkb *lkb) |
161 | { | 161 | { |
162 | printk(KERN_ERR "lkb: nodeid %d id %x remid %x exflags %x flags %x\n" | 162 | printk(KERN_ERR "lkb: nodeid %d id %x remid %x exflags %x flags %x\n" |
163 | " status %d rqmode %d grmode %d wait_type %d ast_type %d\n", | 163 | " status %d rqmode %d grmode %d wait_type %d\n", |
164 | lkb->lkb_nodeid, lkb->lkb_id, lkb->lkb_remid, lkb->lkb_exflags, | 164 | lkb->lkb_nodeid, lkb->lkb_id, lkb->lkb_remid, lkb->lkb_exflags, |
165 | lkb->lkb_flags, lkb->lkb_status, lkb->lkb_rqmode, | 165 | lkb->lkb_flags, lkb->lkb_status, lkb->lkb_rqmode, |
166 | lkb->lkb_grmode, lkb->lkb_wait_type, lkb->lkb_ast_type); | 166 | lkb->lkb_grmode, lkb->lkb_wait_type); |
167 | } | 167 | } |
168 | 168 | ||
169 | static void dlm_print_rsb(struct dlm_rsb *r) | 169 | static void dlm_print_rsb(struct dlm_rsb *r) |
@@ -305,10 +305,7 @@ static void queue_cast(struct dlm_rsb *r, struct dlm_lkb *lkb, int rv) | |||
305 | rv = -EDEADLK; | 305 | rv = -EDEADLK; |
306 | } | 306 | } |
307 | 307 | ||
308 | lkb->lkb_lksb->sb_status = rv; | 308 | dlm_add_ast(lkb, DLM_CB_CAST, lkb->lkb_grmode, rv, lkb->lkb_sbflags); |
309 | lkb->lkb_lksb->sb_flags = lkb->lkb_sbflags; | ||
310 | |||
311 | dlm_add_ast(lkb, AST_COMP, lkb->lkb_grmode); | ||
312 | } | 309 | } |
313 | 310 | ||
314 | static inline void queue_cast_overlap(struct dlm_rsb *r, struct dlm_lkb *lkb) | 311 | static inline void queue_cast_overlap(struct dlm_rsb *r, struct dlm_lkb *lkb) |
@@ -319,13 +316,10 @@ static inline void queue_cast_overlap(struct dlm_rsb *r, struct dlm_lkb *lkb) | |||
319 | 316 | ||
320 | static void queue_bast(struct dlm_rsb *r, struct dlm_lkb *lkb, int rqmode) | 317 | static void queue_bast(struct dlm_rsb *r, struct dlm_lkb *lkb, int rqmode) |
321 | { | 318 | { |
322 | lkb->lkb_time_bast = ktime_get(); | ||
323 | |||
324 | if (is_master_copy(lkb)) { | 319 | if (is_master_copy(lkb)) { |
325 | lkb->lkb_bastmode = rqmode; /* printed by debugfs */ | ||
326 | send_bast(r, lkb, rqmode); | 320 | send_bast(r, lkb, rqmode); |
327 | } else { | 321 | } else { |
328 | dlm_add_ast(lkb, AST_BAST, rqmode); | 322 | dlm_add_ast(lkb, DLM_CB_BAST, rqmode, 0, 0); |
329 | } | 323 | } |
330 | } | 324 | } |
331 | 325 | ||
@@ -600,6 +594,7 @@ static int create_lkb(struct dlm_ls *ls, struct dlm_lkb **lkb_ret) | |||
600 | INIT_LIST_HEAD(&lkb->lkb_ownqueue); | 594 | INIT_LIST_HEAD(&lkb->lkb_ownqueue); |
601 | INIT_LIST_HEAD(&lkb->lkb_rsb_lookup); | 595 | INIT_LIST_HEAD(&lkb->lkb_rsb_lookup); |
602 | INIT_LIST_HEAD(&lkb->lkb_time_list); | 596 | INIT_LIST_HEAD(&lkb->lkb_time_list); |
597 | INIT_LIST_HEAD(&lkb->lkb_astqueue); | ||
603 | 598 | ||
604 | get_random_bytes(&bucket, sizeof(bucket)); | 599 | get_random_bytes(&bucket, sizeof(bucket)); |
605 | bucket &= (ls->ls_lkbtbl_size - 1); | 600 | bucket &= (ls->ls_lkbtbl_size - 1); |
@@ -2819,9 +2814,9 @@ static void send_args(struct dlm_rsb *r, struct dlm_lkb *lkb, | |||
2819 | not from lkb fields */ | 2814 | not from lkb fields */ |
2820 | 2815 | ||
2821 | if (lkb->lkb_bastfn) | 2816 | if (lkb->lkb_bastfn) |
2822 | ms->m_asts |= AST_BAST; | 2817 | ms->m_asts |= DLM_CB_BAST; |
2823 | if (lkb->lkb_astfn) | 2818 | if (lkb->lkb_astfn) |
2824 | ms->m_asts |= AST_COMP; | 2819 | ms->m_asts |= DLM_CB_CAST; |
2825 | 2820 | ||
2826 | /* compare with switch in create_message; send_remove() doesn't | 2821 | /* compare with switch in create_message; send_remove() doesn't |
2827 | use send_args() */ | 2822 | use send_args() */ |
@@ -3122,8 +3117,8 @@ static int receive_request_args(struct dlm_ls *ls, struct dlm_lkb *lkb, | |||
3122 | lkb->lkb_grmode = DLM_LOCK_IV; | 3117 | lkb->lkb_grmode = DLM_LOCK_IV; |
3123 | lkb->lkb_rqmode = ms->m_rqmode; | 3118 | lkb->lkb_rqmode = ms->m_rqmode; |
3124 | 3119 | ||
3125 | lkb->lkb_bastfn = (ms->m_asts & AST_BAST) ? &fake_bastfn : NULL; | 3120 | lkb->lkb_bastfn = (ms->m_asts & DLM_CB_BAST) ? &fake_bastfn : NULL; |
3126 | lkb->lkb_astfn = (ms->m_asts & AST_COMP) ? &fake_astfn : NULL; | 3121 | lkb->lkb_astfn = (ms->m_asts & DLM_CB_CAST) ? &fake_astfn : NULL; |
3127 | 3122 | ||
3128 | if (lkb->lkb_exflags & DLM_LKF_VALBLK) { | 3123 | if (lkb->lkb_exflags & DLM_LKF_VALBLK) { |
3129 | /* lkb was just created so there won't be an lvb yet */ | 3124 | /* lkb was just created so there won't be an lvb yet */ |
@@ -4412,8 +4407,8 @@ static int receive_rcom_lock_args(struct dlm_ls *ls, struct dlm_lkb *lkb, | |||
4412 | lkb->lkb_grmode = rl->rl_grmode; | 4407 | lkb->lkb_grmode = rl->rl_grmode; |
4413 | /* don't set lkb_status because add_lkb wants to itself */ | 4408 | /* don't set lkb_status because add_lkb wants to itself */ |
4414 | 4409 | ||
4415 | lkb->lkb_bastfn = (rl->rl_asts & AST_BAST) ? &fake_bastfn : NULL; | 4410 | lkb->lkb_bastfn = (rl->rl_asts & DLM_CB_BAST) ? &fake_bastfn : NULL; |
4416 | lkb->lkb_astfn = (rl->rl_asts & AST_COMP) ? &fake_astfn : NULL; | 4411 | lkb->lkb_astfn = (rl->rl_asts & DLM_CB_CAST) ? &fake_astfn : NULL; |
4417 | 4412 | ||
4418 | if (lkb->lkb_exflags & DLM_LKF_VALBLK) { | 4413 | if (lkb->lkb_exflags & DLM_LKF_VALBLK) { |
4419 | int lvblen = rc->rc_header.h_length - sizeof(struct dlm_rcom) - | 4414 | int lvblen = rc->rc_header.h_length - sizeof(struct dlm_rcom) - |
@@ -4589,7 +4584,6 @@ int dlm_user_request(struct dlm_ls *ls, struct dlm_user_args *ua, | |||
4589 | error = set_lock_args(mode, &ua->lksb, flags, namelen, timeout_cs, | 4584 | error = set_lock_args(mode, &ua->lksb, flags, namelen, timeout_cs, |
4590 | fake_astfn, ua, fake_bastfn, &args); | 4585 | fake_astfn, ua, fake_bastfn, &args); |
4591 | lkb->lkb_flags |= DLM_IFL_USER; | 4586 | lkb->lkb_flags |= DLM_IFL_USER; |
4592 | ua->old_mode = DLM_LOCK_IV; | ||
4593 | 4587 | ||
4594 | if (error) { | 4588 | if (error) { |
4595 | __put_lkb(ls, lkb); | 4589 | __put_lkb(ls, lkb); |
@@ -4658,7 +4652,6 @@ int dlm_user_convert(struct dlm_ls *ls, struct dlm_user_args *ua_tmp, | |||
4658 | ua->bastparam = ua_tmp->bastparam; | 4652 | ua->bastparam = ua_tmp->bastparam; |
4659 | ua->bastaddr = ua_tmp->bastaddr; | 4653 | ua->bastaddr = ua_tmp->bastaddr; |
4660 | ua->user_lksb = ua_tmp->user_lksb; | 4654 | ua->user_lksb = ua_tmp->user_lksb; |
4661 | ua->old_mode = lkb->lkb_grmode; | ||
4662 | 4655 | ||
4663 | error = set_lock_args(mode, &ua->lksb, flags, 0, timeout_cs, | 4656 | error = set_lock_args(mode, &ua->lksb, flags, 0, timeout_cs, |
4664 | fake_astfn, ua, fake_bastfn, &args); | 4657 | fake_astfn, ua, fake_bastfn, &args); |
@@ -4917,8 +4910,9 @@ void dlm_clear_proc_locks(struct dlm_ls *ls, struct dlm_user_proc *proc) | |||
4917 | } | 4910 | } |
4918 | 4911 | ||
4919 | list_for_each_entry_safe(lkb, safe, &proc->asts, lkb_astqueue) { | 4912 | list_for_each_entry_safe(lkb, safe, &proc->asts, lkb_astqueue) { |
4920 | lkb->lkb_ast_type = 0; | 4913 | memset(&lkb->lkb_callbacks, 0, |
4921 | list_del(&lkb->lkb_astqueue); | 4914 | sizeof(struct dlm_callback) * DLM_CALLBACKS_SIZE); |
4915 | list_del_init(&lkb->lkb_astqueue); | ||
4922 | dlm_put_lkb(lkb); | 4916 | dlm_put_lkb(lkb); |
4923 | } | 4917 | } |
4924 | 4918 | ||
@@ -4958,7 +4952,9 @@ static void purge_proc_locks(struct dlm_ls *ls, struct dlm_user_proc *proc) | |||
4958 | 4952 | ||
4959 | spin_lock(&proc->asts_spin); | 4953 | spin_lock(&proc->asts_spin); |
4960 | list_for_each_entry_safe(lkb, safe, &proc->asts, lkb_astqueue) { | 4954 | list_for_each_entry_safe(lkb, safe, &proc->asts, lkb_astqueue) { |
4961 | list_del(&lkb->lkb_astqueue); | 4955 | memset(&lkb->lkb_callbacks, 0, |
4956 | sizeof(struct dlm_callback) * DLM_CALLBACKS_SIZE); | ||
4957 | list_del_init(&lkb->lkb_astqueue); | ||
4962 | dlm_put_lkb(lkb); | 4958 | dlm_put_lkb(lkb); |
4963 | } | 4959 | } |
4964 | spin_unlock(&proc->asts_spin); | 4960 | spin_unlock(&proc->asts_spin); |
diff --git a/fs/dlm/rcom.c b/fs/dlm/rcom.c index 3c83a49a48a3..f10a50f24e8f 100644 --- a/fs/dlm/rcom.c +++ b/fs/dlm/rcom.c | |||
@@ -321,9 +321,9 @@ static void pack_rcom_lock(struct dlm_rsb *r, struct dlm_lkb *lkb, | |||
321 | rl->rl_wait_type = cpu_to_le16(lkb->lkb_wait_type); | 321 | rl->rl_wait_type = cpu_to_le16(lkb->lkb_wait_type); |
322 | 322 | ||
323 | if (lkb->lkb_bastfn) | 323 | if (lkb->lkb_bastfn) |
324 | rl->rl_asts |= AST_BAST; | 324 | rl->rl_asts |= DLM_CB_BAST; |
325 | if (lkb->lkb_astfn) | 325 | if (lkb->lkb_astfn) |
326 | rl->rl_asts |= AST_COMP; | 326 | rl->rl_asts |= DLM_CB_CAST; |
327 | 327 | ||
328 | rl->rl_namelen = cpu_to_le16(r->res_length); | 328 | rl->rl_namelen = cpu_to_le16(r->res_length); |
329 | memcpy(rl->rl_name, r->res_name, r->res_length); | 329 | memcpy(rl->rl_name, r->res_name, r->res_length); |
diff --git a/fs/dlm/user.c b/fs/dlm/user.c index 66d6c16bf440..d5ab3fe7c198 100644 --- a/fs/dlm/user.c +++ b/fs/dlm/user.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include "lock.h" | 24 | #include "lock.h" |
25 | #include "lvb_table.h" | 25 | #include "lvb_table.h" |
26 | #include "user.h" | 26 | #include "user.h" |
27 | #include "ast.h" | ||
27 | 28 | ||
28 | static const char name_prefix[] = "dlm"; | 29 | static const char name_prefix[] = "dlm"; |
29 | static const struct file_operations device_fops; | 30 | static const struct file_operations device_fops; |
@@ -152,19 +153,16 @@ static void compat_output(struct dlm_lock_result *res, | |||
152 | not related to the lifetime of the lkb struct which is managed | 153 | not related to the lifetime of the lkb struct which is managed |
153 | entirely by refcount. */ | 154 | entirely by refcount. */ |
154 | 155 | ||
155 | static int lkb_is_endoflife(struct dlm_lkb *lkb, int sb_status, int type) | 156 | static int lkb_is_endoflife(int mode, int status) |
156 | { | 157 | { |
157 | switch (sb_status) { | 158 | switch (status) { |
158 | case -DLM_EUNLOCK: | 159 | case -DLM_EUNLOCK: |
159 | return 1; | 160 | return 1; |
160 | case -DLM_ECANCEL: | 161 | case -DLM_ECANCEL: |
161 | case -ETIMEDOUT: | 162 | case -ETIMEDOUT: |
162 | case -EDEADLK: | 163 | case -EDEADLK: |
163 | if (lkb->lkb_grmode == DLM_LOCK_IV) | ||
164 | return 1; | ||
165 | break; | ||
166 | case -EAGAIN: | 164 | case -EAGAIN: |
167 | if (type == AST_COMP && lkb->lkb_grmode == DLM_LOCK_IV) | 165 | if (mode == DLM_LOCK_IV) |
168 | return 1; | 166 | return 1; |
169 | break; | 167 | break; |
170 | } | 168 | } |
@@ -174,12 +172,13 @@ static int lkb_is_endoflife(struct dlm_lkb *lkb, int sb_status, int type) | |||
174 | /* we could possibly check if the cancel of an orphan has resulted in the lkb | 172 | /* we could possibly check if the cancel of an orphan has resulted in the lkb |
175 | being removed and then remove that lkb from the orphans list and free it */ | 173 | being removed and then remove that lkb from the orphans list and free it */ |
176 | 174 | ||
177 | void dlm_user_add_ast(struct dlm_lkb *lkb, int type, int mode) | 175 | void dlm_user_add_ast(struct dlm_lkb *lkb, uint32_t flags, int mode, |
176 | int status, uint32_t sbflags, uint64_t seq) | ||
178 | { | 177 | { |
179 | struct dlm_ls *ls; | 178 | struct dlm_ls *ls; |
180 | struct dlm_user_args *ua; | 179 | struct dlm_user_args *ua; |
181 | struct dlm_user_proc *proc; | 180 | struct dlm_user_proc *proc; |
182 | int eol = 0, ast_type; | 181 | int rv; |
183 | 182 | ||
184 | if (lkb->lkb_flags & (DLM_IFL_ORPHAN | DLM_IFL_DEAD)) | 183 | if (lkb->lkb_flags & (DLM_IFL_ORPHAN | DLM_IFL_DEAD)) |
185 | return; | 184 | return; |
@@ -200,49 +199,29 @@ void dlm_user_add_ast(struct dlm_lkb *lkb, int type, int mode) | |||
200 | ua = lkb->lkb_ua; | 199 | ua = lkb->lkb_ua; |
201 | proc = ua->proc; | 200 | proc = ua->proc; |
202 | 201 | ||
203 | if (type == AST_BAST && ua->bastaddr == NULL) | 202 | if ((flags & DLM_CB_BAST) && ua->bastaddr == NULL) |
204 | goto out; | 203 | goto out; |
205 | 204 | ||
205 | if ((flags & DLM_CB_CAST) && lkb_is_endoflife(mode, status)) | ||
206 | lkb->lkb_flags |= DLM_IFL_ENDOFLIFE; | ||
207 | |||
206 | spin_lock(&proc->asts_spin); | 208 | spin_lock(&proc->asts_spin); |
207 | 209 | ||
208 | ast_type = lkb->lkb_ast_type; | 210 | rv = dlm_add_lkb_callback(lkb, flags, mode, status, sbflags, seq); |
209 | lkb->lkb_ast_type |= type; | 211 | if (rv < 0) { |
210 | if (type == AST_BAST) | 212 | spin_unlock(&proc->asts_spin); |
211 | lkb->lkb_bastmode = mode; | 213 | goto out; |
212 | else | 214 | } |
213 | lkb->lkb_castmode = mode; | ||
214 | 215 | ||
215 | if (!ast_type) { | 216 | if (list_empty(&lkb->lkb_astqueue)) { |
216 | kref_get(&lkb->lkb_ref); | 217 | kref_get(&lkb->lkb_ref); |
217 | list_add_tail(&lkb->lkb_astqueue, &proc->asts); | 218 | list_add_tail(&lkb->lkb_astqueue, &proc->asts); |
218 | lkb->lkb_ast_first = type; | ||
219 | wake_up_interruptible(&proc->wait); | 219 | wake_up_interruptible(&proc->wait); |
220 | } | 220 | } |
221 | if (type == AST_COMP && (ast_type & AST_COMP)) | ||
222 | log_debug(ls, "ast overlap %x status %x %x", | ||
223 | lkb->lkb_id, ua->lksb.sb_status, lkb->lkb_flags); | ||
224 | |||
225 | eol = lkb_is_endoflife(lkb, ua->lksb.sb_status, type); | ||
226 | if (eol) { | ||
227 | lkb->lkb_flags |= DLM_IFL_ENDOFLIFE; | ||
228 | } | ||
229 | |||
230 | /* We want to copy the lvb to userspace when the completion | ||
231 | ast is read if the status is 0, the lock has an lvb and | ||
232 | lvb_ops says we should. We could probably have set_lvb_lock() | ||
233 | set update_user_lvb instead and not need old_mode */ | ||
234 | |||
235 | if ((lkb->lkb_ast_type & AST_COMP) && | ||
236 | (lkb->lkb_lksb->sb_status == 0) && | ||
237 | lkb->lkb_lksb->sb_lvbptr && | ||
238 | dlm_lvb_operations[ua->old_mode + 1][lkb->lkb_grmode + 1]) | ||
239 | ua->update_user_lvb = 1; | ||
240 | else | ||
241 | ua->update_user_lvb = 0; | ||
242 | |||
243 | spin_unlock(&proc->asts_spin); | 221 | spin_unlock(&proc->asts_spin); |
244 | 222 | ||
245 | if (eol) { | 223 | if (lkb->lkb_flags & DLM_IFL_ENDOFLIFE) { |
224 | /* N.B. spin_lock locks_spin, not asts_spin */ | ||
246 | spin_lock(&proc->locks_spin); | 225 | spin_lock(&proc->locks_spin); |
247 | if (!list_empty(&lkb->lkb_ownqueue)) { | 226 | if (!list_empty(&lkb->lkb_ownqueue)) { |
248 | list_del_init(&lkb->lkb_ownqueue); | 227 | list_del_init(&lkb->lkb_ownqueue); |
@@ -705,8 +684,9 @@ static int device_close(struct inode *inode, struct file *file) | |||
705 | return 0; | 684 | return 0; |
706 | } | 685 | } |
707 | 686 | ||
708 | static int copy_result_to_user(struct dlm_user_args *ua, int compat, int type, | 687 | static int copy_result_to_user(struct dlm_user_args *ua, int compat, |
709 | int mode, char __user *buf, size_t count) | 688 | uint32_t flags, int mode, int copy_lvb, |
689 | char __user *buf, size_t count) | ||
710 | { | 690 | { |
711 | #ifdef CONFIG_COMPAT | 691 | #ifdef CONFIG_COMPAT |
712 | struct dlm_lock_result32 result32; | 692 | struct dlm_lock_result32 result32; |
@@ -730,7 +710,7 @@ static int copy_result_to_user(struct dlm_user_args *ua, int compat, int type, | |||
730 | notes that a new blocking AST address and parameter are set even if | 710 | notes that a new blocking AST address and parameter are set even if |
731 | the conversion fails, so maybe we should just do that. */ | 711 | the conversion fails, so maybe we should just do that. */ |
732 | 712 | ||
733 | if (type == AST_BAST) { | 713 | if (flags & DLM_CB_BAST) { |
734 | result.user_astaddr = ua->bastaddr; | 714 | result.user_astaddr = ua->bastaddr; |
735 | result.user_astparam = ua->bastparam; | 715 | result.user_astparam = ua->bastparam; |
736 | result.bast_mode = mode; | 716 | result.bast_mode = mode; |
@@ -750,8 +730,7 @@ static int copy_result_to_user(struct dlm_user_args *ua, int compat, int type, | |||
750 | /* copy lvb to userspace if there is one, it's been updated, and | 730 | /* copy lvb to userspace if there is one, it's been updated, and |
751 | the user buffer has space for it */ | 731 | the user buffer has space for it */ |
752 | 732 | ||
753 | if (ua->update_user_lvb && ua->lksb.sb_lvbptr && | 733 | if (copy_lvb && ua->lksb.sb_lvbptr && count >= len + DLM_USER_LVB_LEN) { |
754 | count >= len + DLM_USER_LVB_LEN) { | ||
755 | if (copy_to_user(buf+len, ua->lksb.sb_lvbptr, | 734 | if (copy_to_user(buf+len, ua->lksb.sb_lvbptr, |
756 | DLM_USER_LVB_LEN)) { | 735 | DLM_USER_LVB_LEN)) { |
757 | error = -EFAULT; | 736 | error = -EFAULT; |
@@ -801,13 +780,12 @@ static ssize_t device_read(struct file *file, char __user *buf, size_t count, | |||
801 | struct dlm_user_proc *proc = file->private_data; | 780 | struct dlm_user_proc *proc = file->private_data; |
802 | struct dlm_lkb *lkb; | 781 | struct dlm_lkb *lkb; |
803 | DECLARE_WAITQUEUE(wait, current); | 782 | DECLARE_WAITQUEUE(wait, current); |
804 | int error = 0, removed; | 783 | struct dlm_callback cb; |
805 | int ret_type, ret_mode; | 784 | int rv, resid, copy_lvb = 0; |
806 | int bastmode, castmode, do_bast, do_cast; | ||
807 | 785 | ||
808 | if (count == sizeof(struct dlm_device_version)) { | 786 | if (count == sizeof(struct dlm_device_version)) { |
809 | error = copy_version_to_user(buf, count); | 787 | rv = copy_version_to_user(buf, count); |
810 | return error; | 788 | return rv; |
811 | } | 789 | } |
812 | 790 | ||
813 | if (!proc) { | 791 | if (!proc) { |
@@ -854,92 +832,57 @@ static ssize_t device_read(struct file *file, char __user *buf, size_t count, | |||
854 | } | 832 | } |
855 | } | 833 | } |
856 | 834 | ||
857 | /* there may be both completion and blocking asts to return for | 835 | /* if we empty lkb_callbacks, we don't want to unlock the spinlock |
858 | the lkb, don't remove lkb from asts list unless no asts remain */ | 836 | without removing lkb_astqueue; so empty lkb_astqueue is always |
837 | consistent with empty lkb_callbacks */ | ||
859 | 838 | ||
860 | lkb = list_entry(proc->asts.next, struct dlm_lkb, lkb_astqueue); | 839 | lkb = list_entry(proc->asts.next, struct dlm_lkb, lkb_astqueue); |
861 | 840 | ||
862 | removed = 0; | 841 | rv = dlm_rem_lkb_callback(lkb->lkb_resource->res_ls, lkb, &cb, &resid); |
863 | ret_type = 0; | 842 | if (rv < 0) { |
864 | ret_mode = 0; | 843 | /* this shouldn't happen; lkb should have been removed from |
865 | do_bast = lkb->lkb_ast_type & AST_BAST; | 844 | list when resid was zero */ |
866 | do_cast = lkb->lkb_ast_type & AST_COMP; | 845 | log_print("dlm_rem_lkb_callback empty %x", lkb->lkb_id); |
867 | bastmode = lkb->lkb_bastmode; | 846 | list_del_init(&lkb->lkb_astqueue); |
868 | castmode = lkb->lkb_castmode; | 847 | spin_unlock(&proc->asts_spin); |
869 | 848 | /* removes ref for proc->asts, may cause lkb to be freed */ | |
870 | /* when both are queued figure out which to do first and | 849 | dlm_put_lkb(lkb); |
871 | switch first so the other goes in the next read */ | 850 | goto try_another; |
872 | |||
873 | if (do_cast && do_bast) { | ||
874 | if (lkb->lkb_ast_first == AST_COMP) { | ||
875 | ret_type = AST_COMP; | ||
876 | ret_mode = castmode; | ||
877 | lkb->lkb_ast_type &= ~AST_COMP; | ||
878 | lkb->lkb_ast_first = AST_BAST; | ||
879 | } else { | ||
880 | ret_type = AST_BAST; | ||
881 | ret_mode = bastmode; | ||
882 | lkb->lkb_ast_type &= ~AST_BAST; | ||
883 | lkb->lkb_ast_first = AST_COMP; | ||
884 | } | ||
885 | } else { | ||
886 | ret_type = lkb->lkb_ast_first; | ||
887 | ret_mode = (ret_type == AST_COMP) ? castmode : bastmode; | ||
888 | lkb->lkb_ast_type &= ~ret_type; | ||
889 | lkb->lkb_ast_first = 0; | ||
890 | } | 851 | } |
852 | if (!resid) | ||
853 | list_del_init(&lkb->lkb_astqueue); | ||
854 | spin_unlock(&proc->asts_spin); | ||
891 | 855 | ||
892 | /* if we're doing a bast but the bast is unnecessary, then | 856 | if (cb.flags & DLM_CB_SKIP) { |
893 | switch to do nothing or do a cast if that was needed next */ | 857 | /* removes ref for proc->asts, may cause lkb to be freed */ |
894 | 858 | if (!resid) | |
895 | if ((ret_type == AST_BAST) && | 859 | dlm_put_lkb(lkb); |
896 | dlm_modes_compat(bastmode, lkb->lkb_castmode_done)) { | 860 | goto try_another; |
897 | ret_type = 0; | ||
898 | ret_mode = 0; | ||
899 | |||
900 | if (do_cast) { | ||
901 | ret_type = AST_COMP; | ||
902 | ret_mode = castmode; | ||
903 | lkb->lkb_ast_type &= ~AST_COMP; | ||
904 | lkb->lkb_ast_first = 0; | ||
905 | } | ||
906 | } | 861 | } |
907 | 862 | ||
908 | if (lkb->lkb_ast_first != lkb->lkb_ast_type) { | 863 | if (cb.flags & DLM_CB_CAST) { |
909 | log_print("device_read %x ast_first %x ast_type %x", | 864 | int old_mode, new_mode; |
910 | lkb->lkb_id, lkb->lkb_ast_first, lkb->lkb_ast_type); | ||
911 | } | ||
912 | 865 | ||
913 | if (!lkb->lkb_ast_type) { | 866 | old_mode = lkb->lkb_last_cast.mode; |
914 | list_del(&lkb->lkb_astqueue); | 867 | new_mode = cb.mode; |
915 | removed = 1; | ||
916 | } | ||
917 | spin_unlock(&proc->asts_spin); | ||
918 | 868 | ||
919 | if (ret_type) { | 869 | if (!cb.sb_status && lkb->lkb_lksb->sb_lvbptr && |
920 | error = copy_result_to_user(lkb->lkb_ua, | 870 | dlm_lvb_operations[old_mode + 1][new_mode + 1]) |
921 | test_bit(DLM_PROC_FLAGS_COMPAT, &proc->flags), | 871 | copy_lvb = 1; |
922 | ret_type, ret_mode, buf, count); | ||
923 | 872 | ||
924 | if (ret_type == AST_COMP) | 873 | lkb->lkb_lksb->sb_status = cb.sb_status; |
925 | lkb->lkb_castmode_done = castmode; | 874 | lkb->lkb_lksb->sb_flags = cb.sb_flags; |
926 | if (ret_type == AST_BAST) | ||
927 | lkb->lkb_bastmode_done = bastmode; | ||
928 | } | 875 | } |
929 | 876 | ||
930 | /* removes reference for the proc->asts lists added by | 877 | rv = copy_result_to_user(lkb->lkb_ua, |
931 | dlm_user_add_ast() and may result in the lkb being freed */ | 878 | test_bit(DLM_PROC_FLAGS_COMPAT, &proc->flags), |
879 | cb.flags, cb.mode, copy_lvb, buf, count); | ||
932 | 880 | ||
933 | if (removed) | 881 | /* removes ref for proc->asts, may cause lkb to be freed */ |
882 | if (!resid) | ||
934 | dlm_put_lkb(lkb); | 883 | dlm_put_lkb(lkb); |
935 | 884 | ||
936 | /* the bast that was queued was eliminated (see unnecessary above), | 885 | return rv; |
937 | leaving nothing to return */ | ||
938 | |||
939 | if (!ret_type) | ||
940 | goto try_another; | ||
941 | |||
942 | return error; | ||
943 | } | 886 | } |
944 | 887 | ||
945 | static unsigned int device_poll(struct file *file, poll_table *wait) | 888 | static unsigned int device_poll(struct file *file, poll_table *wait) |
diff --git a/fs/dlm/user.h b/fs/dlm/user.h index f196091dd7ff..00499ab8835f 100644 --- a/fs/dlm/user.h +++ b/fs/dlm/user.h | |||
@@ -9,7 +9,8 @@ | |||
9 | #ifndef __USER_DOT_H__ | 9 | #ifndef __USER_DOT_H__ |
10 | #define __USER_DOT_H__ | 10 | #define __USER_DOT_H__ |
11 | 11 | ||
12 | void dlm_user_add_ast(struct dlm_lkb *lkb, int type, int mode); | 12 | void dlm_user_add_ast(struct dlm_lkb *lkb, uint32_t flags, int mode, |
13 | int status, uint32_t sbflags, uint64_t seq); | ||
13 | int dlm_user_init(void); | 14 | int dlm_user_init(void); |
14 | void dlm_user_exit(void); | 15 | void dlm_user_exit(void); |
15 | int dlm_device_deregister(struct dlm_ls *ls); | 16 | int dlm_device_deregister(struct dlm_ls *ls); |