Skip to content

Commit

Permalink
dlm: fix ordering of bast and cast
Browse files Browse the repository at this point in the history
When both blocking and completion callbacks are queued for lock,
the dlm would always deliver the completion callback (cast) first.
In some cases the blocking callback (bast) is queued before the
cast, though, and should be delivered first.  This patch keeps
track of the order in which they were queued and delivers them
in that order.

This patch also keeps track of the granted mode in the last cast
and eliminates the following bast if the bast mode is compatible
with the preceding cast mode.  This happens when a remotely mastered
lock is demoted, e.g. EX->NL, in which case the local node queues
a cast immediately after sending the demote message.  In this way
a cast can be queued for a mode, e.g. NL, that makes an in-transit
bast extraneous.

Signed-off-by: David Teigland <teigland@redhat.com>
  • Loading branch information
David Teigland committed Feb 24, 2010
1 parent b0483e7 commit 7fe2b31
Show file tree
Hide file tree
Showing 6 changed files with 78 additions and 28 deletions.
74 changes: 58 additions & 16 deletions fs/dlm/ast.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
*******************************************************************************
**
** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
** Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved.
** Copyright (C) 2004-2010 Red Hat, Inc. All rights reserved.
**
** This copyrighted material is made available to anyone wishing to use,
** modify, copy, or redistribute it subject to the terms and conditions
Expand Down Expand Up @@ -33,21 +33,32 @@ void dlm_del_ast(struct dlm_lkb *lkb)
spin_unlock(&ast_queue_lock);
}

void dlm_add_ast(struct dlm_lkb *lkb, int type, int bastmode)
void dlm_add_ast(struct dlm_lkb *lkb, int type, int mode)
{
if (lkb->lkb_flags & DLM_IFL_USER) {
dlm_user_add_ast(lkb, type, bastmode);
dlm_user_add_ast(lkb, type, mode);
return;
}

spin_lock(&ast_queue_lock);
if (!(lkb->lkb_ast_type & (AST_COMP | AST_BAST))) {
kref_get(&lkb->lkb_ref);
list_add_tail(&lkb->lkb_astqueue, &ast_queue);
lkb->lkb_ast_first = type;
}

/* sanity check, this should not happen */

if ((type == AST_COMP) && (lkb->lkb_ast_type & AST_COMP))
log_print("repeat cast %d castmode %d lock %x %s",
mode, lkb->lkb_castmode,
lkb->lkb_id, lkb->lkb_resource->res_name);

lkb->lkb_ast_type |= type;
if (bastmode)
lkb->lkb_bastmode = bastmode;
if (type == AST_BAST)
lkb->lkb_bastmode = mode;
else
lkb->lkb_castmode = mode;
spin_unlock(&ast_queue_lock);

set_bit(WAKE_ASTS, &astd_wakeflags);
Expand All @@ -59,9 +70,9 @@ static void process_asts(void)
struct dlm_ls *ls = NULL;
struct dlm_rsb *r = NULL;
struct dlm_lkb *lkb;
void (*cast) (void *astparam);
void (*bast) (void *astparam, int mode);
int type = 0, bastmode;
void (*castfn) (void *astparam);
void (*bastfn) (void *astparam, int mode);
int type, first, bastmode, castmode, do_bast, do_cast, last_castmode;

repeat:
spin_lock(&ast_queue_lock);
Expand All @@ -75,17 +86,48 @@ static void process_asts(void)
list_del(&lkb->lkb_astqueue);
type = lkb->lkb_ast_type;
lkb->lkb_ast_type = 0;
first = lkb->lkb_ast_first;
lkb->lkb_ast_first = 0;
bastmode = lkb->lkb_bastmode;

castmode = lkb->lkb_castmode;
castfn = lkb->lkb_astfn;
bastfn = lkb->lkb_bastfn;
spin_unlock(&ast_queue_lock);
cast = lkb->lkb_astfn;
bast = lkb->lkb_bastfn;

if ((type & AST_COMP) && cast)
cast(lkb->lkb_astparam);

if ((type & AST_BAST) && bast)
bast(lkb->lkb_astparam, bastmode);
do_cast = (type & AST_COMP) && castfn;
do_bast = (type & AST_BAST) && bastfn;

/* Skip a bast if its blocking mode is compatible with the
granted mode of the preceding cast. */

if (do_bast) {
if (first == AST_COMP)
last_castmode = castmode;
else
last_castmode = lkb->lkb_castmode_done;
if (dlm_modes_compat(bastmode, last_castmode))
do_bast = 0;
}

if (first == AST_COMP) {
if (do_cast)
castfn(lkb->lkb_astparam);
if (do_bast)
bastfn(lkb->lkb_astparam, bastmode);
} else if (first == AST_BAST) {
if (do_bast)
bastfn(lkb->lkb_astparam, bastmode);
if (do_cast)
castfn(lkb->lkb_astparam);
} else {
log_error(ls, "bad ast_first %d ast_type %d",
first, type);
}

if (do_cast)
lkb->lkb_castmode_done = castmode;
if (do_bast)
lkb->lkb_bastmode_done = bastmode;

/* this removes the reference added by dlm_add_ast
and may result in the lkb being freed */
Expand Down
4 changes: 2 additions & 2 deletions fs/dlm/ast.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/******************************************************************************
*******************************************************************************
**
** Copyright (C) 2005-2008 Red Hat, Inc. All rights reserved.
** Copyright (C) 2005-2010 Red Hat, Inc. All rights reserved.
**
** This copyrighted material is made available to anyone wishing to use,
** modify, copy, or redistribute it subject to the terms and conditions
Expand All @@ -13,7 +13,7 @@
#ifndef __ASTD_DOT_H__
#define __ASTD_DOT_H__

void dlm_add_ast(struct dlm_lkb *lkb, int type, int bastmode);
void dlm_add_ast(struct dlm_lkb *lkb, int type, int mode);
void dlm_del_ast(struct dlm_lkb *lkb);

void dlm_astd_wake(void);
Expand Down
10 changes: 8 additions & 2 deletions fs/dlm/dlm_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
*******************************************************************************
**
** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
** Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved.
** Copyright (C) 2004-2010 Red Hat, Inc. All rights reserved.
**
** This copyrighted material is made available to anyone wishing to use,
** modify, copy, or redistribute it subject to the terms and conditions
Expand Down Expand Up @@ -232,11 +232,17 @@ struct dlm_lkb {
int8_t lkb_status; /* granted, waiting, convert */
int8_t lkb_rqmode; /* requested lock mode */
int8_t lkb_grmode; /* granted lock mode */
int8_t lkb_bastmode; /* requested mode */
int8_t lkb_highbast; /* highest mode bast sent for */

int8_t lkb_wait_type; /* type of reply waiting for */
int8_t lkb_wait_count;
int8_t lkb_ast_type; /* type of ast queued for */
int8_t lkb_ast_first; /* type of first ast queued */

int8_t lkb_bastmode; /* req mode of queued bast */
int8_t lkb_castmode; /* gr mode of queued cast */
int8_t lkb_bastmode_done; /* last delivered bastmode */
int8_t lkb_castmode_done; /* last delivered castmode */

struct list_head lkb_idtbl_list; /* lockspace lkbtbl */
struct list_head lkb_statequeue; /* rsb g/c/w list */
Expand Down
4 changes: 2 additions & 2 deletions fs/dlm/lock.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/******************************************************************************
*******************************************************************************
**
** Copyright (C) 2005-2008 Red Hat, Inc. All rights reserved.
** Copyright (C) 2005-2010 Red Hat, Inc. All rights reserved.
**
** This copyrighted material is made available to anyone wishing to use,
** modify, copy, or redistribute it subject to the terms and conditions
Expand Down Expand Up @@ -307,7 +307,7 @@ static void queue_cast(struct dlm_rsb *r, struct dlm_lkb *lkb, int rv)
lkb->lkb_lksb->sb_status = rv;
lkb->lkb_lksb->sb_flags = lkb->lkb_sbflags;

dlm_add_ast(lkb, AST_COMP, 0);
dlm_add_ast(lkb, AST_COMP, lkb->lkb_grmode);
}

static inline void queue_cast_overlap(struct dlm_rsb *r, struct dlm_lkb *lkb)
Expand Down
10 changes: 6 additions & 4 deletions fs/dlm/user.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2006-2009 Red Hat, Inc. All rights reserved.
* Copyright (C) 2006-2010 Red Hat, Inc. All rights reserved.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
Expand Down Expand Up @@ -173,7 +173,7 @@ static int lkb_is_endoflife(struct dlm_lkb *lkb, int sb_status, int type)
/* we could possibly check if the cancel of an orphan has resulted in the lkb
being removed and then remove that lkb from the orphans list and free it */

void dlm_user_add_ast(struct dlm_lkb *lkb, int type, int bastmode)
void dlm_user_add_ast(struct dlm_lkb *lkb, int type, int mode)
{
struct dlm_ls *ls;
struct dlm_user_args *ua;
Expand Down Expand Up @@ -206,8 +206,10 @@ void dlm_user_add_ast(struct dlm_lkb *lkb, int type, int bastmode)

ast_type = lkb->lkb_ast_type;
lkb->lkb_ast_type |= type;
if (bastmode)
lkb->lkb_bastmode = bastmode;
if (type == AST_BAST)
lkb->lkb_bastmode = mode;
else
lkb->lkb_castmode = mode;

if (!ast_type) {
kref_get(&lkb->lkb_ref);
Expand Down
4 changes: 2 additions & 2 deletions fs/dlm/user.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2006-2008 Red Hat, Inc. All rights reserved.
* Copyright (C) 2006-2010 Red Hat, Inc. All rights reserved.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
Expand All @@ -9,7 +9,7 @@
#ifndef __USER_DOT_H__
#define __USER_DOT_H__

void dlm_user_add_ast(struct dlm_lkb *lkb, int type, int bastmode);
void dlm_user_add_ast(struct dlm_lkb *lkb, int type, int mode);
int dlm_user_init(void);
void dlm_user_exit(void);
int dlm_device_deregister(struct dlm_ls *ls);
Expand Down

0 comments on commit 7fe2b31

Please sign in to comment.