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