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 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; 25 static struct mutex astd_running; 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 36 void dlm_add_ast(struct dlm_lkb *lkb, int type, int mode) 37 { 38 if (lkb->lkb_flags & DLM_IFL_USER) { 39 dlm_user_add_ast(lkb, type, mode); 40 return; 41 } 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 lkb->lkb_ast_first = type; 48 } 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); 63 64 set_bit(WAKE_ASTS, &astd_wakeflags); 65 wake_up_process(astd_task); 66 } 67 68 static void process_asts(void) 69 { 70 struct dlm_ls *ls = NULL; 71 struct dlm_rsb *r = NULL; 72 struct dlm_lkb *lkb; 73 void (*castfn) (void *astparam); 74 void (*bastfn) (void *astparam, int mode); 75 int type, first, bastmode, castmode, do_bast, do_cast, last_castmode; 76 77 repeat: 78 spin_lock(&ast_queue_lock); 79 list_for_each_entry(lkb, &ast_queue, lkb_astqueue) { 80 r = lkb->lkb_resource; 81 ls = r->res_ls; 82 83 if (dlm_locking_stopped(ls)) 84 continue; 85 86 list_del(&lkb->lkb_astqueue); 87 type = lkb->lkb_ast_type; 88 lkb->lkb_ast_type = 0; 89 first = lkb->lkb_ast_first; 90 lkb->lkb_ast_first = 0; 91 bastmode = lkb->lkb_bastmode; 92 castmode = lkb->lkb_castmode; 93 castfn = lkb->lkb_astfn; 94 bastfn = lkb->lkb_bastfn; 95 spin_unlock(&ast_queue_lock); 96 97 do_cast = (type & AST_COMP) && castfn; 98 do_bast = (type & AST_BAST) && bastfn; 99 100 /* Skip a bast if its blocking mode is compatible with the 101 granted mode of the preceding cast. */ 102 103 if (do_bast) { 104 if (first == AST_COMP) 105 last_castmode = castmode; 106 else 107 last_castmode = lkb->lkb_castmode_done; 108 if (dlm_modes_compat(bastmode, last_castmode)) 109 do_bast = 0; 110 } 111 112 if (first == AST_COMP) { 113 if (do_cast) 114 castfn(lkb->lkb_astparam); 115 if (do_bast) 116 bastfn(lkb->lkb_astparam, bastmode); 117 } else if (first == AST_BAST) { 118 if (do_bast) 119 bastfn(lkb->lkb_astparam, bastmode); 120 if (do_cast) 121 castfn(lkb->lkb_astparam); 122 } else { 123 log_error(ls, "bad ast_first %d ast_type %d", 124 first, type); 125 } 126 127 if (do_cast) 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); 135 136 cond_resched(); 137 goto repeat; 138 } 139 spin_unlock(&ast_queue_lock); 140 } 141 142 static inline int no_asts(void) 143 { 144 int ret; 145 146 spin_lock(&ast_queue_lock); 147 ret = list_empty(&ast_queue); 148 spin_unlock(&ast_queue_lock); 149 return ret; 150 } 151 152 static int dlm_astd(void *data) 153 { 154 while (!kthread_should_stop()) { 155 set_current_state(TASK_INTERRUPTIBLE); 156 if (!test_bit(WAKE_ASTS, &astd_wakeflags)) 157 schedule(); 158 set_current_state(TASK_RUNNING); 159 160 mutex_lock(&astd_running); 161 if (test_and_clear_bit(WAKE_ASTS, &astd_wakeflags)) 162 process_asts(); 163 mutex_unlock(&astd_running); 164 } 165 return 0; 166 } 167 168 void dlm_astd_wake(void) 169 { 170 if (!no_asts()) { 171 set_bit(WAKE_ASTS, &astd_wakeflags); 172 wake_up_process(astd_task); 173 } 174 } 175 176 int dlm_astd_start(void) 177 { 178 struct task_struct *p; 179 int error = 0; 180 181 INIT_LIST_HEAD(&ast_queue); 182 spin_lock_init(&ast_queue_lock); 183 mutex_init(&astd_running); 184 185 p = kthread_run(dlm_astd, NULL, "dlm_astd"); 186 if (IS_ERR(p)) 187 error = PTR_ERR(p); 188 else 189 astd_task = p; 190 return error; 191 } 192 193 void dlm_astd_stop(void) 194 { 195 kthread_stop(astd_task); 196 } 197 198 void dlm_astd_suspend(void) 199 { 200 mutex_lock(&astd_running); 201 } 202 203 void dlm_astd_resume(void) 204 { 205 mutex_unlock(&astd_running); 206 } 207 208