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#include "ast.h" 18 19#define WAKE_ASTS 0 20 21static struct list_head ast_queue; 22static spinlock_t ast_queue_lock; 23static struct task_struct * astd_task; 24static unsigned long astd_wakeflags; 25static struct mutex astd_running; 26 27 28void 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 36void dlm_add_ast(struct dlm_lkb *lkb, int type) 37{ 38 if (lkb->lkb_flags & DLM_IFL_USER) { 39 dlm_user_add_ast(lkb, type); 40 return; 41 } 42 DLM_ASSERT(lkb->lkb_astaddr != DLM_FAKE_USER_AST, dlm_print_lkb(lkb);); 43 44 spin_lock(&ast_queue_lock); 45 if (!(lkb->lkb_ast_type & (AST_COMP | AST_BAST))) { 46 kref_get(&lkb->lkb_ref); 47 list_add_tail(&lkb->lkb_astqueue, &ast_queue); 48 } 49 lkb->lkb_ast_type |= type; 50 spin_unlock(&ast_queue_lock); 51 52 set_bit(WAKE_ASTS, &astd_wakeflags); 53 wake_up_process(astd_task); 54} 55 56static void process_asts(void) 57{ 58 struct dlm_ls *ls = NULL; 59 struct dlm_rsb *r = NULL; 60 struct dlm_lkb *lkb; 61 void (*cast) (long param); 62 void (*bast) (long param, int mode); 63 int type = 0, found, bmode; 64 65 for (;;) { 66 found = 0; 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; 71 72 if (dlm_locking_stopped(ls)) 73 continue; 74 75 list_del(&lkb->lkb_astqueue); 76 type = lkb->lkb_ast_type; 77 lkb->lkb_ast_type = 0; 78 found = 1; 79 break; 80 } 81 spin_unlock(&ast_queue_lock); 82 83 if (!found) 84 break; 85 86 cast = lkb->lkb_astaddr; 87 bast = lkb->lkb_bastaddr; 88 bmode = lkb->lkb_bastmode; 89 90 if ((type & AST_COMP) && cast) 91 cast(lkb->lkb_astparam); 92 93 94 if ((type & AST_BAST) && bast) 95 if (!dlm_modes_compat(lkb->lkb_grmode, bmode)) 96 bast(lkb->lkb_astparam, bmode); 97 98 /* this removes the reference added by dlm_add_ast 99 and may result in the lkb being freed */ 100 dlm_put_lkb(lkb); 101 102 schedule(); 103 } 104} 105 106static inline int no_asts(void) 107{ 108 int ret; 109 110 spin_lock(&ast_queue_lock); 111 ret = list_empty(&ast_queue); 112 spin_unlock(&ast_queue_lock); 113 return ret; 114} 115 116static int dlm_astd(void *data) 117{ 118 while (!kthread_should_stop()) { 119 set_current_state(TASK_INTERRUPTIBLE); 120 if (!test_bit(WAKE_ASTS, &astd_wakeflags)) 121 schedule(); 122 set_current_state(TASK_RUNNING); 123 124 mutex_lock(&astd_running); 125 if (test_and_clear_bit(WAKE_ASTS, &astd_wakeflags)) 126 process_asts(); 127 mutex_unlock(&astd_running); 128 } 129 return 0; 130} 131 132void dlm_astd_wake(void) 133{ 134 if (!no_asts()) { 135 set_bit(WAKE_ASTS, &astd_wakeflags); 136 wake_up_process(astd_task); 137 } 138} 139 140int dlm_astd_start(void) 141{ 142 struct task_struct *p; 143 int error = 0; 144 145 INIT_LIST_HEAD(&ast_queue); 146 spin_lock_init(&ast_queue_lock); 147 mutex_init(&astd_running); 148 149 p = kthread_run(dlm_astd, NULL, "dlm_astd"); 150 if (IS_ERR(p)) 151 error = PTR_ERR(p); 152 else 153 astd_task = p; 154 return error; 155} 156 157void dlm_astd_stop(void) 158{ 159 kthread_stop(astd_task); 160} 161 162void dlm_astd_suspend(void) 163{ 164 mutex_lock(&astd_running); 165} 166 167void dlm_astd_resume(void) 168{ 169 mutex_unlock(&astd_running); 170} 171