linux/fs/dlm/ast.c
<<
>>
Prefs
   1/******************************************************************************
   2*******************************************************************************
   3**
   4**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
   5**  Copyright (C) 2004-2008 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, int bastmode)
  37{
  38        if (lkb->lkb_flags & DLM_IFL_USER) {
  39                dlm_user_add_ast(lkb, type, bastmode);
  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        }
  48        lkb->lkb_ast_type |= type;
  49        if (bastmode)
  50                lkb->lkb_bastmode = bastmode;
  51        spin_unlock(&ast_queue_lock);
  52
  53        set_bit(WAKE_ASTS, &astd_wakeflags);
  54        wake_up_process(astd_task);
  55}
  56
  57static void process_asts(void)
  58{
  59        struct dlm_ls *ls = NULL;
  60        struct dlm_rsb *r = NULL;
  61        struct dlm_lkb *lkb;
  62        void (*cast) (void *astparam);
  63        void (*bast) (void *astparam, int mode);
  64        int type = 0, bastmode;
  65
  66repeat:
  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                bastmode = lkb->lkb_bastmode;
  79
  80                spin_unlock(&ast_queue_lock);
  81                cast = lkb->lkb_astfn;
  82                bast = lkb->lkb_bastfn;
  83
  84                if ((type & AST_COMP) && cast)
  85                        cast(lkb->lkb_astparam);
  86
  87                if ((type & AST_BAST) && bast)
  88                        bast(lkb->lkb_astparam, bastmode);
  89
  90                /* this removes the reference added by dlm_add_ast
  91                   and may result in the lkb being freed */
  92                dlm_put_lkb(lkb);
  93
  94                cond_resched();
  95                goto repeat;
  96        }
  97        spin_unlock(&ast_queue_lock);
  98}
  99
 100static inline int no_asts(void)
 101{
 102        int ret;
 103
 104        spin_lock(&ast_queue_lock);
 105        ret = list_empty(&ast_queue);
 106        spin_unlock(&ast_queue_lock);
 107        return ret;
 108}
 109
 110static int dlm_astd(void *data)
 111{
 112        while (!kthread_should_stop()) {
 113                set_current_state(TASK_INTERRUPTIBLE);
 114                if (!test_bit(WAKE_ASTS, &astd_wakeflags))
 115                        schedule();
 116                set_current_state(TASK_RUNNING);
 117
 118                mutex_lock(&astd_running);
 119                if (test_and_clear_bit(WAKE_ASTS, &astd_wakeflags))
 120                        process_asts();
 121                mutex_unlock(&astd_running);
 122        }
 123        return 0;
 124}
 125
 126void dlm_astd_wake(void)
 127{
 128        if (!no_asts()) {
 129                set_bit(WAKE_ASTS, &astd_wakeflags);
 130                wake_up_process(astd_task);
 131        }
 132}
 133
 134int dlm_astd_start(void)
 135{
 136        struct task_struct *p;
 137        int error = 0;
 138
 139        INIT_LIST_HEAD(&ast_queue);
 140        spin_lock_init(&ast_queue_lock);
 141        mutex_init(&astd_running);
 142
 143        p = kthread_run(dlm_astd, NULL, "dlm_astd");
 144        if (IS_ERR(p))
 145                error = PTR_ERR(p);
 146        else
 147                astd_task = p;
 148        return error;
 149}
 150
 151void dlm_astd_stop(void)
 152{
 153        kthread_stop(astd_task);
 154}
 155
 156void dlm_astd_suspend(void)
 157{
 158        mutex_lock(&astd_running);
 159}
 160
 161void dlm_astd_resume(void)
 162{
 163        mutex_unlock(&astd_running);
 164}
 165
 166