1 /****************************************************************************** 2 ******************************************************************************* 3 ** 4 ** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. 5 ** Copyright (C) 2004-2010 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 #include "ast.h" 18 19 #define WAKE_ASTS 0 20 21 static uint64_t ast_seq_count; 22 static struct list_head ast_queue; 23 static spinlock_t ast_queue_lock; 24 static struct task_struct * astd_task; 25 static unsigned long astd_wakeflags; 26 static struct mutex astd_running; 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 60 void dlm_del_ast(struct dlm_lkb *lkb) 61 { 62 spin_lock(&ast_queue_lock); 63 if (!list_empty(&lkb->lkb_astqueue)) 64 list_del_init(&lkb->lkb_astqueue); 65 spin_unlock(&ast_queue_lock); 66 } 67 68 int dlm_add_lkb_callback(struct dlm_lkb *lkb, uint32_t flags, int mode, 69 int status, uint32_t sbflags, uint64_t seq) 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 193 if (lkb->lkb_flags & DLM_IFL_USER) { 194 spin_unlock(&ast_queue_lock); 195 dlm_user_add_ast(lkb, flags, mode, status, sbflags, seq); 196 return; 197 } 198 199 rv = dlm_add_lkb_callback(lkb, flags, mode, status, sbflags, seq); 200 if (rv < 0) { 201 spin_unlock(&ast_queue_lock); 202 return; 203 } 204 205 if (list_empty(&lkb->lkb_astqueue)) { 206 kref_get(&lkb->lkb_ref); 207 list_add_tail(&lkb->lkb_astqueue, &ast_queue); 208 } 209 spin_unlock(&ast_queue_lock); 210 211 set_bit(WAKE_ASTS, &astd_wakeflags); 212 wake_up_process(astd_task); 213 } 214 215 static void process_asts(void) 216 { 217 struct dlm_ls *ls = NULL; 218 struct dlm_rsb *r = NULL; 219 struct dlm_lkb *lkb; 220 void (*castfn) (void *astparam); 221 void (*bastfn) (void *astparam, int mode); 222 struct dlm_callback callbacks[DLM_CALLBACKS_SIZE]; 223 int i, rv, resid; 224 225 repeat: 226 spin_lock(&ast_queue_lock); 227 list_for_each_entry(lkb, &ast_queue, lkb_astqueue) { 228 r = lkb->lkb_resource; 229 ls = r->res_ls; 230 231 if (dlm_locking_stopped(ls)) 232 continue; 233 234 /* we remove from astqueue list and remove everything in 235 lkb_callbacks before releasing the spinlock so empty 236 lkb_astqueue is always consistent with empty lkb_callbacks */ 237 238 list_del_init(&lkb->lkb_astqueue); 239 240 castfn = lkb->lkb_astfn; 241 bastfn = lkb->lkb_bastfn; 242 243 memset(&callbacks, 0, sizeof(callbacks)); 244 245 for (i = 0; i < DLM_CALLBACKS_SIZE; i++) { 246 rv = dlm_rem_lkb_callback(ls, lkb, &callbacks[i], &resid); 247 if (rv < 0) 248 break; 249 } 250 spin_unlock(&ast_queue_lock); 251 252 if (resid) { 253 /* shouldn't happen, for loop should have removed all */ 254 log_error(ls, "callback resid %d lkb %x", 255 resid, lkb->lkb_id); 256 } 257 258 for (i = 0; i < DLM_CALLBACKS_SIZE; i++) { 259 if (!callbacks[i].seq) 260 break; 261 if (callbacks[i].flags & DLM_CB_SKIP) { 262 continue; 263 } else if (callbacks[i].flags & DLM_CB_BAST) { 264 bastfn(lkb->lkb_astparam, callbacks[i].mode); 265 } else if (callbacks[i].flags & DLM_CB_CAST) { 266 lkb->lkb_lksb->sb_status = callbacks[i].sb_status; 267 lkb->lkb_lksb->sb_flags = callbacks[i].sb_flags; 268 castfn(lkb->lkb_astparam); 269 } 270 } 271 272 /* removes ref for ast_queue, may cause lkb to be freed */ 273 dlm_put_lkb(lkb); 274 275 cond_resched(); 276 goto repeat; 277 } 278 spin_unlock(&ast_queue_lock); 279 } 280 281 static inline int no_asts(void) 282 { 283 int ret; 284 285 spin_lock(&ast_queue_lock); 286 ret = list_empty(&ast_queue); 287 spin_unlock(&ast_queue_lock); 288 return ret; 289 } 290 291 static int dlm_astd(void *data) 292 { 293 while (!kthread_should_stop()) { 294 set_current_state(TASK_INTERRUPTIBLE); 295 if (!test_bit(WAKE_ASTS, &astd_wakeflags)) 296 schedule(); 297 set_current_state(TASK_RUNNING); 298 299 mutex_lock(&astd_running); 300 if (test_and_clear_bit(WAKE_ASTS, &astd_wakeflags)) 301 process_asts(); 302 mutex_unlock(&astd_running); 303 } 304 return 0; 305 } 306 307 void dlm_astd_wake(void) 308 { 309 if (!no_asts()) { 310 set_bit(WAKE_ASTS, &astd_wakeflags); 311 wake_up_process(astd_task); 312 } 313 } 314 315 int dlm_astd_start(void) 316 { 317 struct task_struct *p; 318 int error = 0; 319 320 INIT_LIST_HEAD(&ast_queue); 321 spin_lock_init(&ast_queue_lock); 322 mutex_init(&astd_running); 323 324 p = kthread_run(dlm_astd, NULL, "dlm_astd"); 325 if (IS_ERR(p)) 326 error = PTR_ERR(p); 327 else 328 astd_task = p; 329 return error; 330 } 331 332 void dlm_astd_stop(void) 333 { 334 kthread_stop(astd_task); 335 } 336 337 void dlm_astd_suspend(void) 338 { 339 mutex_lock(&astd_running); 340 } 341 342 void dlm_astd_resume(void) 343 { 344 mutex_unlock(&astd_running); 345 } 346 347