linux/fs/gfs2/lock_dlm.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
   3 * Copyright (C) 2004-2009 Red Hat, Inc.  All rights reserved.
   4 *
   5 * This copyrighted material is made available to anyone wishing to use,
   6 * modify, copy, or redistribute it subject to the terms and conditions
   7 * of the GNU General Public License version 2.
   8 */
   9
  10#include <linux/fs.h>
  11#include <linux/dlm.h>
  12#include <linux/types.h>
  13#include <linux/gfs2_ondisk.h>
  14
  15#include "incore.h"
  16#include "glock.h"
  17#include "util.h"
  18
  19
  20static void gdlm_ast(void *arg)
  21{
  22        struct gfs2_glock *gl = arg;
  23        unsigned ret = gl->gl_state;
  24
  25        BUG_ON(gl->gl_lksb.sb_flags & DLM_SBF_DEMOTED);
  26
  27        if (gl->gl_lksb.sb_flags & DLM_SBF_VALNOTVALID)
  28                memset(gl->gl_lvb, 0, GDLM_LVB_SIZE);
  29
  30        switch (gl->gl_lksb.sb_status) {
  31        case -DLM_EUNLOCK: /* Unlocked, so glock can be freed */
  32                kmem_cache_free(gfs2_glock_cachep, gl);
  33                return;
  34        case -DLM_ECANCEL: /* Cancel while getting lock */
  35                ret |= LM_OUT_CANCELED;
  36                goto out;
  37        case -EAGAIN: /* Try lock fails */
  38                goto out;
  39        case -EINVAL: /* Invalid */
  40        case -ENOMEM: /* Out of memory */
  41                ret |= LM_OUT_ERROR;
  42                goto out;
  43        case 0: /* Success */
  44                break;
  45        default: /* Something unexpected */
  46                BUG();
  47        }
  48
  49        ret = gl->gl_req;
  50        if (gl->gl_lksb.sb_flags & DLM_SBF_ALTMODE) {
  51                if (gl->gl_req == LM_ST_SHARED)
  52                        ret = LM_ST_DEFERRED;
  53                else if (gl->gl_req == LM_ST_DEFERRED)
  54                        ret = LM_ST_SHARED;
  55                else
  56                        BUG();
  57        }
  58
  59        set_bit(GLF_INITIAL, &gl->gl_flags);
  60        gfs2_glock_complete(gl, ret);
  61        return;
  62out:
  63        if (!test_bit(GLF_INITIAL, &gl->gl_flags))
  64                gl->gl_lksb.sb_lkid = 0;
  65        gfs2_glock_complete(gl, ret);
  66}
  67
  68static void gdlm_bast(void *arg, int mode)
  69{
  70        struct gfs2_glock *gl = arg;
  71
  72        switch (mode) {
  73        case DLM_LOCK_EX:
  74                gfs2_glock_cb(gl, LM_ST_UNLOCKED);
  75                break;
  76        case DLM_LOCK_CW:
  77                gfs2_glock_cb(gl, LM_ST_DEFERRED);
  78                break;
  79        case DLM_LOCK_PR:
  80                gfs2_glock_cb(gl, LM_ST_SHARED);
  81                break;
  82        default:
  83                printk(KERN_ERR "unknown bast mode %d", mode);
  84                BUG();
  85        }
  86}
  87
  88/* convert gfs lock-state to dlm lock-mode */
  89
  90static int make_mode(const unsigned int lmstate)
  91{
  92        switch (lmstate) {
  93        case LM_ST_UNLOCKED:
  94                return DLM_LOCK_NL;
  95        case LM_ST_EXCLUSIVE:
  96                return DLM_LOCK_EX;
  97        case LM_ST_DEFERRED:
  98                return DLM_LOCK_CW;
  99        case LM_ST_SHARED:
 100                return DLM_LOCK_PR;
 101        }
 102        printk(KERN_ERR "unknown LM state %d", lmstate);
 103        BUG();
 104        return -1;
 105}
 106
 107static u32 make_flags(const u32 lkid, const unsigned int gfs_flags,
 108                      const int req)
 109{
 110        u32 lkf = 0;
 111
 112        if (gfs_flags & LM_FLAG_TRY)
 113                lkf |= DLM_LKF_NOQUEUE;
 114
 115        if (gfs_flags & LM_FLAG_TRY_1CB) {
 116                lkf |= DLM_LKF_NOQUEUE;
 117                lkf |= DLM_LKF_NOQUEUEBAST;
 118        }
 119
 120        if (gfs_flags & LM_FLAG_PRIORITY) {
 121                lkf |= DLM_LKF_NOORDER;
 122                lkf |= DLM_LKF_HEADQUE;
 123        }
 124
 125        if (gfs_flags & LM_FLAG_ANY) {
 126                if (req == DLM_LOCK_PR)
 127                        lkf |= DLM_LKF_ALTCW;
 128                else if (req == DLM_LOCK_CW)
 129                        lkf |= DLM_LKF_ALTPR;
 130                else
 131                        BUG();
 132        }
 133
 134        if (lkid != 0) 
 135                lkf |= DLM_LKF_CONVERT;
 136
 137        lkf |= DLM_LKF_VALBLK;
 138
 139        return lkf;
 140}
 141
 142static unsigned int gdlm_lock(struct gfs2_glock *gl,
 143                              unsigned int req_state, unsigned int flags)
 144{
 145        struct lm_lockstruct *ls = &gl->gl_sbd->sd_lockstruct;
 146        int error;
 147        int req;
 148        u32 lkf;
 149
 150        gl->gl_req = req_state;
 151        req = make_mode(req_state);
 152        lkf = make_flags(gl->gl_lksb.sb_lkid, flags, req);
 153
 154        /*
 155         * Submit the actual lock request.
 156         */
 157
 158        error = dlm_lock(ls->ls_dlm, req, &gl->gl_lksb, lkf, gl->gl_strname,
 159                         GDLM_STRNAME_BYTES - 1, 0, gdlm_ast, gl, gdlm_bast);
 160        if (error == -EAGAIN)
 161                return 0;
 162        if (error)
 163                return LM_OUT_ERROR;
 164        return LM_OUT_ASYNC;
 165}
 166
 167static void gdlm_put_lock(struct kmem_cache *cachep, void *ptr)
 168{
 169        struct gfs2_glock *gl = ptr;
 170        struct lm_lockstruct *ls = &gl->gl_sbd->sd_lockstruct;
 171        int error;
 172
 173        if (gl->gl_lksb.sb_lkid == 0) {
 174                kmem_cache_free(cachep, gl);
 175                return;
 176        }
 177
 178        error = dlm_unlock(ls->ls_dlm, gl->gl_lksb.sb_lkid, DLM_LKF_VALBLK,
 179                           NULL, gl);
 180        if (error) {
 181                printk(KERN_ERR "gdlm_unlock %x,%llx err=%d\n",
 182                       gl->gl_name.ln_type,
 183                       (unsigned long long)gl->gl_name.ln_number, error);
 184                return;
 185        }
 186}
 187
 188static void gdlm_cancel(struct gfs2_glock *gl)
 189{
 190        struct lm_lockstruct *ls = &gl->gl_sbd->sd_lockstruct;
 191        dlm_unlock(ls->ls_dlm, gl->gl_lksb.sb_lkid, DLM_LKF_CANCEL, NULL, gl);
 192}
 193
 194static int gdlm_mount(struct gfs2_sbd *sdp, const char *fsname)
 195{
 196        struct lm_lockstruct *ls = &sdp->sd_lockstruct;
 197        int error;
 198
 199        if (fsname == NULL) {
 200                fs_info(sdp, "no fsname found\n");
 201                return -EINVAL;
 202        }
 203
 204        error = dlm_new_lockspace(fsname, strlen(fsname), &ls->ls_dlm,
 205                                  DLM_LSFL_FS | DLM_LSFL_NEWEXCL |
 206                                  (ls->ls_nodir ? DLM_LSFL_NODIR : 0),
 207                                  GDLM_LVB_SIZE);
 208        if (error)
 209                printk(KERN_ERR "dlm_new_lockspace error %d", error);
 210
 211        return error;
 212}
 213
 214static void gdlm_unmount(struct gfs2_sbd *sdp)
 215{
 216        struct lm_lockstruct *ls = &sdp->sd_lockstruct;
 217
 218        if (ls->ls_dlm) {
 219                dlm_release_lockspace(ls->ls_dlm, 2);
 220                ls->ls_dlm = NULL;
 221        }
 222}
 223
 224static const match_table_t dlm_tokens = {
 225        { Opt_jid, "jid=%d"},
 226        { Opt_id, "id=%d"},
 227        { Opt_first, "first=%d"},
 228        { Opt_nodir, "nodir=%d"},
 229        { Opt_err, NULL },
 230};
 231
 232const struct lm_lockops gfs2_dlm_ops = {
 233        .lm_proto_name = "lock_dlm",
 234        .lm_mount = gdlm_mount,
 235        .lm_unmount = gdlm_unmount,
 236        .lm_put_lock = gdlm_put_lock,
 237        .lm_lock = gdlm_lock,
 238        .lm_cancel = gdlm_cancel,
 239        .lm_tokens = &dlm_tokens,
 240};
 241
 242
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.