dlm: Give fs/dlm the notion of ranges

Using the new interval tree code we add a tree for each lock status list to
efficiently track ranged requests. Internally, most operations on a
resources lock status list (granted, waiting, converting) then are turned
into operations within a given range.

There is no API change other than a new call, dlm_lock_range() and a new
structure, 'struct dlm_key' to define our range endpoints. Keys can have
arbitrary lengths and are compared via memcmp. A ranged blocking ast type is
defined so that users of dlm_lock_range() can know which range they are
blocking.

A rudimentary test, dlmtest.ko is included.

TODO:
 - Update userspace entry points, need to add one for new lock call
 - Manage backwards compatibility with network protocol

Signed-off-by: Mark Fasheh <mfasheh@versity.com>
This commit is contained in:
Mark Fasheh
2017-06-23 15:07:10 -05:00
parent 0c1c2691e0
commit 08bf1fea79
16 changed files with 831 additions and 76 deletions
+2 -2
View File
@@ -1,4 +1,4 @@
obj-$(CONFIG_DLM) += dlm.o
obj-$(CONFIG_DLM) += dlm.o dlmtest.o
dlm-y := ast.o \
config.o \
dir.o \
@@ -16,5 +16,5 @@ dlm-y := ast.o \
recoverd.o \
requestqueue.o \
user.o \
util.o
util.o
dlm-$(CONFIG_DLM_DEBUG) += debug_fs.o
+68 -9
View File
@@ -49,13 +49,35 @@ static void dlm_dump_lkb_callbacks(struct dlm_lkb *lkb)
}
}
static void fixup_cb_pointers(struct dlm_callback *cb)
{
struct dlm_key *start = &cb->start;
struct dlm_key *end = &cb->end;
cb->range.start = start;
cb->range.end = end;
start->val = &cb->startval;
end->val = &cb->endval;
}
/*
* Range must not be NULL for DLM_CB_BAST.
*/
int dlm_add_lkb_callback(struct dlm_lkb *lkb, uint32_t flags, int mode,
int status, uint32_t sbflags, uint64_t seq)
struct dlm_range *range, int status, uint32_t sbflags,
uint64_t seq)
{
struct dlm_ls *ls = lkb->lkb_resource->res_ls;
uint64_t prev_seq;
int prev_mode;
int i, rv;
struct dlm_range *prev_range;
if ((flags & DLM_CB_BAST) && !range) {
/* XXX: user.c doesn't handle this yet, fail for now */
WARN_ON_ONCE(1);
return -EINVAL;
}
for (i = 0; i < DLM_CALLBACKS_SIZE; i++) {
if (lkb->lkb_callbacks[i].seq)
@@ -73,9 +95,12 @@ int dlm_add_lkb_callback(struct dlm_lkb *lkb, uint32_t flags, int mode,
prev_seq = lkb->lkb_callbacks[i-1].seq;
prev_mode = lkb->lkb_callbacks[i-1].mode;
prev_range = &lkb->lkb_callbacks[i-1].range;
if ((prev_mode == mode) ||
(prev_mode > mode && prev_mode > DLM_LOCK_PR)) {
/* Below check needs to look at range */
if (ranges_overlap(prev_range, range) &&
((prev_mode == mode) ||
(prev_mode > mode && prev_mode > DLM_LOCK_PR))) {
log_debug(ls, "skip %x add bast %llu mode %d "
"for bast %llu mode %d",
@@ -94,6 +119,21 @@ int dlm_add_lkb_callback(struct dlm_lkb *lkb, uint32_t flags, int mode,
lkb->lkb_callbacks[i].mode = mode;
lkb->lkb_callbacks[i].sb_status = status;
lkb->lkb_callbacks[i].sb_flags = (sbflags & 0x000000FF);
if (range) {
struct dlm_key *start = &lkb->lkb_callbacks[i].start;
struct dlm_key *end = &lkb->lkb_callbacks[i].end;
lkb->lkb_callbacks[i].range.start = start;
lkb->lkb_callbacks[i].range.end = end;
start->len = range->start->len;
start->val = &lkb->lkb_callbacks[i].startval;
end->len = range->end->len;
end->val = &lkb->lkb_callbacks[i].endval;
memcpy(start->val, range->start->val, range->start->len);
memcpy(end->val, range->end->val, range->end->len);
}
rv = 0;
break;
}
@@ -126,6 +166,7 @@ int dlm_rem_lkb_callback(struct dlm_ls *ls, struct dlm_lkb *lkb,
memcpy(cb, &lkb->lkb_callbacks[0], sizeof(struct dlm_callback));
memset(&lkb->lkb_callbacks[0], 0, sizeof(struct dlm_callback));
fixup_cb_pointers(cb);
/* shift others down */
@@ -171,8 +212,8 @@ int dlm_rem_lkb_callback(struct dlm_ls *ls, struct dlm_lkb *lkb,
return rv;
}
void dlm_add_cb(struct dlm_lkb *lkb, uint32_t flags, int mode, int status,
uint32_t sbflags)
void dlm_add_cb(struct dlm_lkb *lkb, uint32_t flags, int mode,
struct dlm_range *range, int status, uint32_t sbflags)
{
struct dlm_ls *ls = lkb->lkb_resource->res_ls;
uint64_t new_seq, prev_seq;
@@ -190,7 +231,8 @@ void dlm_add_cb(struct dlm_lkb *lkb, uint32_t flags, int mode, int status,
mutex_lock(&lkb->lkb_cb_mutex);
prev_seq = lkb->lkb_callbacks[0].seq;
rv = dlm_add_lkb_callback(lkb, flags, mode, status, sbflags, new_seq);
rv = dlm_add_lkb_callback(lkb, flags, mode, range, status, sbflags,
new_seq);
if (rv < 0)
goto out;
@@ -215,10 +257,21 @@ void dlm_callback_work(struct work_struct *work)
struct dlm_ls *ls = lkb->lkb_resource->res_ls;
void (*castfn) (void *astparam);
void (*bastfn) (void *astparam, int mode);
struct dlm_callback callbacks[DLM_CALLBACKS_SIZE];
void (*rbastfn) (void *astarg, int mode, struct dlm_key *start,
struct dlm_key *end);
/*
* XXX: This used to be on the stack, but the inline buffers
* added for range support blow out our stack.
*
* struct dlm_callback callbacks[DLM_CALLBACKS_SIZE];
*/
struct dlm_callback *callbacks;
int i, rv, resid;
memset(&callbacks, 0, sizeof(callbacks));
callbacks = kcalloc(DLM_CALLBACKS_SIZE, sizeof(*callbacks), GFP_NOFS);
WARN_ON_ONCE(!callbacks);
if (!callbacks)
return;
mutex_lock(&lkb->lkb_cb_mutex);
if (!lkb->lkb_callbacks[0].seq) {
@@ -245,6 +298,7 @@ void dlm_callback_work(struct work_struct *work)
castfn = lkb->lkb_astfn;
bastfn = lkb->lkb_bastfn;
rbastfn = lkb->lkb_rbastfn;
for (i = 0; i < DLM_CALLBACKS_SIZE; i++) {
if (!callbacks[i].seq)
@@ -252,7 +306,11 @@ void dlm_callback_work(struct work_struct *work)
if (callbacks[i].flags & DLM_CB_SKIP) {
continue;
} else if (callbacks[i].flags & DLM_CB_BAST) {
bastfn(lkb->lkb_astparam, callbacks[i].mode);
if (rbastfn)
rbastfn(lkb->lkb_astparam, callbacks[i].mode,
&callbacks[i].start, &callbacks[i].end);
else
bastfn(lkb->lkb_astparam, callbacks[i].mode);
} else if (callbacks[i].flags & DLM_CB_CAST) {
lkb->lkb_lksb->sb_status = callbacks[i].sb_status;
lkb->lkb_lksb->sb_flags = callbacks[i].sb_flags;
@@ -262,6 +320,7 @@ void dlm_callback_work(struct work_struct *work)
/* undo kref_get from dlm_add_callback, may cause lkb to be freed */
dlm_put_lkb(lkb);
kfree(callbacks);
}
int dlm_callback_start(struct dlm_ls *ls)
+4 -3
View File
@@ -15,11 +15,12 @@
void dlm_del_ast(struct dlm_lkb *lkb);
int dlm_add_lkb_callback(struct dlm_lkb *lkb, uint32_t flags, int mode,
int status, uint32_t sbflags, uint64_t seq);
struct dlm_range *range, int status, uint32_t sbflags,
uint64_t seq);
int dlm_rem_lkb_callback(struct dlm_ls *ls, struct dlm_lkb *lkb,
struct dlm_callback *cb, int *resid);
void dlm_add_cb(struct dlm_lkb *lkb, uint32_t flags, int mode, int status,
uint32_t sbflags);
void dlm_add_cb(struct dlm_lkb *lkb, uint32_t flags, int mode,
struct dlm_range *range, int status, uint32_t sbflags);
void dlm_callback_work(struct work_struct *work);
int dlm_callback_start(struct dlm_ls *ls);
+1 -1
View File
@@ -999,7 +999,7 @@ int dlm_our_addr(struct sockaddr_storage *addr, int num)
#define DEFAULT_RECOVER_TIMER 5
#define DEFAULT_TOSS_SECS 10
#define DEFAULT_SCAN_SECS 5
#define DEFAULT_LOG_DEBUG 0
#define DEFAULT_LOG_DEBUG 1
#define DEFAULT_PROTOCOL 0
#define DEFAULT_TIMEWARN_CS 500 /* 5 sec = 500 centiseconds */
#define DEFAULT_WAITWARN_US 0
+50 -1
View File
@@ -40,8 +40,9 @@
#include <linux/idr.h>
#include <linux/ratelimit.h>
#include <asm/uaccess.h>
#include <linux/rbtree.h>
#include <linux/dlm.h>
#include "include/linux/dlm.h"
#include "config.h"
/* Size of the temp buffer midcomms allocates on the stack.
@@ -95,6 +96,10 @@ do { \
} \
}
struct dlm_range {
struct dlm_key *start;
struct dlm_key *end;
};
#define DLM_RTF_SHRINK 0x00000001
@@ -140,7 +145,11 @@ struct dlm_args {
void (*astfn) (void *astparam);
void *astparam;
void (*bastfn) (void *astparam, int mode);
void (*rbastfn) (void *astarg, int mode,
struct dlm_key *start,
struct dlm_key *end);
int mode;
struct dlm_range range;
struct dlm_lksb *lksb;
unsigned long timeout;
};
@@ -213,12 +222,22 @@ struct dlm_args {
#define DLM_CB_BAST 0x00000002
#define DLM_CB_SKIP 0x00000004
#define DLM_KEY_LEN 296
struct dlm_callback {
uint64_t seq;
uint32_t flags; /* DLM_CBF_ */
int sb_status; /* copy to lksb status */
uint8_t sb_flags; /* copy to lksb flags */
int8_t mode; /* rq mode of bast, gr mode of cast */
struct dlm_range range;
/* XXX: This should be dynamically allocated */
struct dlm_key start;
struct dlm_key end;
char startval[DLM_KEY_LEN];
char endval[DLM_KEY_LEN];
};
struct dlm_lkb {
@@ -237,12 +256,18 @@ struct dlm_lkb {
int8_t lkb_rqmode; /* requested lock mode */
int8_t lkb_grmode; /* granted lock mode */
int8_t lkb_highbast; /* highest mode bast sent for */
/* XXX: Keep some history of bast ranges here? */
struct dlm_range lkb_rqrange;
struct dlm_range lkb_grrange;
int8_t lkb_wait_type; /* type of reply waiting for */
int8_t lkb_wait_count;
int lkb_wait_nodeid; /* for debugging */
struct list_head lkb_statequeue; /* rsb g/c/w list */
struct rb_node lkb_statenode; /* rsb g/c/w interval tree */
struct dlm_key *lkb_subtree_last; /* rsb g/c/w interval tree */
struct list_head lkb_rsb_lookup; /* waiting for rsb lookup */
struct list_head lkb_wait_reply; /* waiting for remote reply */
struct list_head lkb_ownqueue; /* list of locks for a process */
@@ -266,6 +291,9 @@ struct dlm_lkb {
struct dlm_lksb *lkb_lksb; /* caller's status block */
void (*lkb_astfn) (void *astparam);
void (*lkb_bastfn) (void *astparam, int mode);
void (*lkb_rbastfn) (void *astparam, int mode,
struct dlm_key *start,
struct dlm_key *end);
union {
void *lkb_astparam; /* caller's ast arg */
struct dlm_user_args *lkb_ua;
@@ -303,7 +331,9 @@ struct dlm_rsb {
struct rb_node res_hashnode; /* rsbtbl */
};
struct list_head res_grantqueue;
struct rb_root res_grantroot;
struct list_head res_convertqueue;
struct rb_root res_convertroot;
struct list_head res_waitqueue;
struct list_head res_root_list; /* used for recovery */
@@ -414,6 +444,25 @@ struct dlm_message {
int m_bastmode;
int m_asts;
int m_result; /* 0 or -EXXX */
/*
* XXX: These should start *after* m_extra to preserve
* compatibility with the old message format
*/
char m_grstart[DLM_KEY_LEN];
char m_grend[DLM_KEY_LEN];
uint16_t m_grstart_len;
uint16_t m_grend_len;
char m_rqstart[DLM_KEY_LEN];
char m_rqend[DLM_KEY_LEN];
uint16_t m_rqstart_len;
uint16_t m_rqend_len;
char m_baststart[DLM_KEY_LEN];
char m_bastend[DLM_KEY_LEN];
uint16_t m_baststart_len;
uint16_t m_bastend_len;
char m_extra[0]; /* name or lvb */
};
+307
View File
@@ -0,0 +1,307 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/atomic.h>
#include "include/linux/dlm.h"
static atomic_t granted;
static atomic_t blocking;
static int val = 1;
static dlm_lockspace_t *ls;
static char *lockres_name = "test_resource";
struct lockinfo {
char *lockname;
int unlocking;
u64 start;
u64 end;
struct dlm_key startkey;
struct dlm_key endkey;
struct dlm_lksb lksb;
};
static inline void set_lock_endpoints(struct lockinfo *lock, u64 start, u64 end)
{
lock->start = cpu_to_be64(start);
lock->startkey.val = &lock->start;
lock->startkey.len = sizeof(lock->start);
lock->end = cpu_to_be64(end);
lock->endkey.val = &lock->end;
lock->endkey.len = sizeof(lock->end);
}
#define NUM_LOCKS 3
static struct lockinfo locks[NUM_LOCKS] = {
{ "lock0", },
{ "lock1", },
{ "lock2", },
};
static int glbl_exmode = 0;
module_param(glbl_exmode, int, 0);
MODULE_PARM_DESC(glbl_exmode, "Take global lock exclusively.");
static void init_counters(void)
{
atomic_set(&granted, 0);
atomic_set(&blocking, 0);
val = 1;
}
static void wait_for_blocking_asts(int count)
{
printk("wait for %d blocking asts\n", count);
while (atomic_read(&blocking) != count) {
printk("blocking: %d\n", atomic_read(&blocking));
msleep_interruptible(2000);
}
}
static void wait_for_lock_grants(int count)
{
printk("wait for %d grants\n", count);
while (atomic_read(&granted) != count) {
printk("granted: %d\n", atomic_read(&granted));
msleep_interruptible(2000);
}
}
static void grant_function(void *arg)
{
char *name = arg;
printk("lock %s granted\n", name);
atomic_add(val, &granted);
}
static void blocking_function(void *arg, int mode, struct dlm_key *start,
struct dlm_key *end)
{
char *name = arg;
BUG_ON(!start);
BUG_ON(!end);
printk("lock %s blocking mode %d, range (%llu, %llu)\n", name, mode,
be64_to_cpu(*((u64 *)start->val)), be64_to_cpu(*((u64 *)end->val)));
atomic_inc(&blocking);
}
static int _test_lock(unsigned int lockidx, unsigned int mode,
unsigned long long start, unsigned long long end,
unsigned int flags)
{
struct lockinfo *lock = &locks[lockidx];
BUG_ON(lockidx > NUM_LOCKS);
set_lock_endpoints(lock, start, end);
printk("lock %s (%u, %llu, %llu)\n", lock->lockname, mode, start, end);
return dlm_lock_range(ls, mode, &lock->startkey, &lock->endkey,
&lock->lksb, flags, lockres_name,
strlen(lockres_name), 0, grant_function,
lock->lockname, blocking_function);
}
static inline int test_lock(unsigned int lockidx, unsigned int mode,
unsigned long long start, unsigned long long end)
{
return _test_lock(lockidx, mode, start, end, 0);
}
static inline int test_convert(unsigned int lockidx, unsigned int mode,
unsigned long long start,
unsigned long long end)
{
return _test_lock(lockidx, mode, start, end, DLM_LKF_CONVERT);
}
static int test_unlock(int lockidx)
{
struct lockinfo *lock = &locks[lockidx];
printk("unlock %s (%llu, %llu)\n", lock->lockname,
be64_to_cpu(lock->start), be64_to_cpu(lock->end));
return dlm_unlock(ls, lock->lksb.sb_lkid, 0, &lock->lksb, lock->lockname);
}
static int test_locking(void)
{
int ret;
printk("Test basic lock/unlock.\n");
init_counters();
ret = test_lock(0, DLM_LOCK_EX, 0, 16384);
if (ret)
goto out;
ret = test_lock(1, DLM_LOCK_EX, 16385, 32768);
if (ret)
goto out;
wait_for_lock_grants(2);
ret = test_lock(2, DLM_LOCK_EX, 0, 32768);
if (ret)
goto out;
wait_for_blocking_asts(2);
val = -1;
ret = test_unlock(0);
if (ret)
goto out;
ret = test_unlock(1);
if (ret)
goto out;
wait_for_lock_grants(-1);
ret = test_unlock(2);
if (ret)
goto out;
wait_for_lock_grants(-2);
out:
return ret;
}
static int test_lock_conversions(void)
{
int ret;
printk("Test lock conversions\n");
init_counters();
ret = test_lock(0, DLM_LOCK_PR, 0, 16384);
if (ret)
goto out;
ret = test_lock(1, DLM_LOCK_PR, 16385, 32768);
if (ret)
goto out;
ret = test_lock(2, DLM_LOCK_PR, 0, 32768);
if (ret)
goto out;
wait_for_lock_grants(3);
ret = test_convert(0, DLM_LOCK_EX, 0, 16384);
if (ret)
goto out;
wait_for_blocking_asts(2);
init_counters();
ret = test_convert(1, DLM_LOCK_NL, 16385, 32768);
if (ret)
goto out;
ret = test_convert(2, DLM_LOCK_NL, 0, 32768);
if (ret)
goto out;
wait_for_lock_grants(3);
init_counters();
ret = test_unlock(1);
if (ret)
goto out;
ret = test_unlock(2);
if (ret)
goto out;
ret = test_unlock(0);
if (ret)
goto out;
wait_for_lock_grants(3);
out:
return ret;
}
#define glbl_res "global"
#define glbl_res_len strlen(glbl_res)
static atomic_t glbl_grants;
static struct dlm_lksb glbl_lksb;
static void glbl_granted(void *arg)
{
printk("Got global lock at %d mode\n", *((int *) arg));
atomic_set(&glbl_grants, 1);
}
static void glbl_blocking(void *arg, int mode)
{
printk("Global lock at %d mode blocking %d lock\n", *((int *)arg), mode);
}
static int test_multinode(void)
{
int ret;
int mode = DLM_LOCK_EX;
printk("Test a global lock\n");
ret = dlm_lock(ls, mode, &glbl_lksb, 0, glbl_res, glbl_res_len, 0,
glbl_granted, &mode, glbl_blocking);
if (ret)
return ret;
while (!atomic_read(&glbl_grants))
msleep_interruptible(5000);
mode = 0;
ret = dlm_unlock(ls, glbl_lksb.sb_lkid, 0, &glbl_lksb, &mode);
return ret;
}
static int __init init_dlm_test(void)
{
int ret;
printk("dlmtest loaded!\n");
ret = dlm_new_lockspace("lockspace", "scoutfs",
DLM_LSFL_FS|DLM_LSFL_NEWEXCL, 8, NULL, NULL,
NULL, &ls);
if (ret) {
printk("new_lockspace returns %d\n", ret);
return ret;
}
ret = test_multinode();
if (!ret)
ret = test_locking();
if (!ret)
ret = test_lock_conversions();
if (ret)
printk("FAILURE: Locking test returns %d\n", ret);
else
printk("Locking test completed with no errors.\n");
return 0;
}
static void __exit exit_dlm_test(void)
{
int ret;
ret = dlm_release_lockspace(ls, 1);
printk("dlmtest unloaded (ret=%d)!\n", ret);
}
module_init(init_dlm_test);
module_exit(exit_dlm_test);
MODULE_DESCRIPTION("dlmtest");
MODULE_AUTHOR("Mark Fasheh");
MODULE_LICENSE("GPL");
+21
View File
@@ -169,4 +169,25 @@ int dlm_unlock(dlm_lockspace_t *lockspace,
struct dlm_lksb *lksb,
void *astarg);
struct dlm_key {
void *val;
int len;
};
int dlm_lock_range(dlm_lockspace_t *lockspace,
int mode,
struct dlm_key *start,
struct dlm_key *end,
struct dlm_lksb *lksb,
uint32_t flags,
void *name,
unsigned int namelen,
uint32_t parent_lkid,
void (*lockast) (void *astarg),
void *astarg,
void (*rbast) (void *astarg, int mode,
struct dlm_key *start, struct dlm_key *end));
#define dlm_unlock_range dlm_unlock
#endif /* __DLM_DOT_H__ */
+351 -54
View File
@@ -60,6 +60,7 @@
#include <linux/slab.h>
#include "dlm_internal.h"
#include <linux/dlm_device.h>
#include "interval_tree_generic.h"
#include "memory.h"
#include "lowcomms.h"
#include "requestqueue.h"
@@ -92,6 +93,7 @@ static void do_purge(struct dlm_ls *ls, int nodeid, int pid);
static void del_timeout(struct dlm_lkb *lkb);
static void toss_rsb(struct kref *kref);
/*
* Lock compatibilty matrix - thanks Steve
* UN = Unlocked state. Not really a state, used as a flag
@@ -133,11 +135,106 @@ const int dlm_lvb_operations[8][8] = {
{ -1, 0, 0, 0, 0, 0, 0, 0 } /* PD */
};
#define modes_compat(gr, rq) \
#define _modes_compat(gr, rq) \
__dlm_compat_matrix[(gr)->lkb_grmode + 1][(rq)->lkb_rqmode + 1]
/*
* Define start and end for a range that covers all possible
* values. Use these as defaults (instead of NULL pointers) for lkbs
* created by non ranged lock requests. Without these we'd have to
* implement switches or alternative algorithms each time a NULL key
* was encountered.
*/
static unsigned long long default_start = 0ULL;
#define default_start_len sizeof(default_start)
static struct dlm_key default_start_key = { &default_start,
default_start_len };
static char default_end[DLM_KEY_LEN] = { [ 0 ... (DLM_KEY_LEN-1) ] = -1 };
#define default_end_len DLM_KEY_LEN
static struct dlm_key default_end_key = { default_end, default_end_len };
static struct dlm_range default_range = { .start = &default_start_key,
.end = &default_end_key };
/* Fast debug printing */
#define debug_range_to_ull(ENDPOINT) \
static inline u64 ENDPOINT ## _to_ull(struct dlm_range *range) \
{ \
u64 val = 0ULL; \
\
if (range->ENDPOINT && range->ENDPOINT->len > sizeof(u64)) { \
memcpy(&val, range->ENDPOINT->val, min((int)sizeof(val),\
range->ENDPOINT->len)); \
return val; \
} \
return 0; \
}
debug_range_to_ull(start);
debug_range_to_ull(end);
static struct dlm_key *alloc_key(char *val, int len, gfp_t gfp)
{
struct dlm_key *ret = kmalloc(sizeof(*ret), gfp);
if (ret) {
ret->len = len;
ret->val = kmalloc(len, gfp);
if (!ret->val) {
kfree(ret);
return NULL;
}
memcpy(ret->val, val, len);
}
return ret;
}
static int cmp_range_keys(char *a, int a_len, char *b, int b_len)
{
return memcmp(a, b, min(a_len, b_len)) ?:
a_len < b_len ? -1 : a_len > b_len ? 1 : 0;
}
static inline int cmp_dlm_keys(struct dlm_key *a, struct dlm_key *b)
{
return cmp_range_keys(a->val, a->len, b->val, b->len);
}
/*
* Define our interval tree nodes to index by granted start/end
* values. We might want a tree sorted by requested start/end in the
* future if walking the converting list winds up being costly.
*/
#define START(lkb) ((lkb)->lkb_grrange.start)
#define LAST(lkb) ((lkb)->lkb_grrange.end)
KEYED_INTERVAL_TREE_DEFINE(struct dlm_lkb, lkb_statenode, struct dlm_key *,
lkb_subtree_last, START, LAST, cmp_dlm_keys,
static, rsb_interval);
int ranges_overlap(struct dlm_range *range1, struct dlm_range *range2)
{
int ret1, ret2;
ret1 = cmp_range_keys(range1->start->val, range1->start->len,
range2->end->val, range2->end->len);
ret2 = cmp_range_keys(range1->end->val, range1->end->len,
range2->start->val, range2->start->len);
if (ret1 <= 0 && ret2 >= 0)
return 1;
return 0;
}
static int modes_compat(struct dlm_lkb *gr, struct dlm_lkb *rq)
{
if (cmp_dlm_keys(rq->lkb_rqrange.start, gr->lkb_grrange.end) <= 0 &&
cmp_dlm_keys(rq->lkb_rqrange.end, gr->lkb_grrange.start) >= 0)
return _modes_compat(gr, rq);
return 0;
}
int dlm_modes_compat(int mode1, int mode2)
{
/* XXX: This needs to be fixed up to take ranges into account */
return __dlm_compat_matrix[mode1 + 1][mode2 + 1];
}
@@ -308,7 +405,7 @@ static void queue_cast(struct dlm_rsb *r, struct dlm_lkb *lkb, int rv)
rv = -EDEADLK;
}
dlm_add_cb(lkb, DLM_CB_CAST, lkb->lkb_grmode, rv, lkb->lkb_sbflags);
dlm_add_cb(lkb, DLM_CB_CAST, lkb->lkb_grmode, NULL, rv, lkb->lkb_sbflags);
}
static inline void queue_cast_overlap(struct dlm_rsb *r, struct dlm_lkb *lkb)
@@ -317,12 +414,13 @@ static inline void queue_cast_overlap(struct dlm_rsb *r, struct dlm_lkb *lkb)
is_overlap_unlock(lkb) ? -DLM_EUNLOCK : -DLM_ECANCEL);
}
static void queue_bast(struct dlm_rsb *r, struct dlm_lkb *lkb, int rqmode)
static void queue_bast(struct dlm_rsb *r, struct dlm_lkb *lkb, int rqmode,
struct dlm_range *rqrange)
{
if (is_master_copy(lkb)) {
send_bast(r, lkb, rqmode);
} else {
dlm_add_cb(lkb, DLM_CB_BAST, rqmode, 0, 0);
dlm_add_cb(lkb, DLM_CB_BAST, rqmode, rqrange, 0, 0);
}
}
@@ -1198,6 +1296,7 @@ static int create_lkb(struct dlm_ls *ls, struct dlm_lkb **lkb_ret)
INIT_LIST_HEAD(&lkb->lkb_cb_list);
mutex_init(&lkb->lkb_cb_mutex);
INIT_WORK(&lkb->lkb_cb_work, dlm_callback_work);
RB_CLEAR_NODE(&lkb->lkb_statenode);
idr_preload(GFP_NOFS);
spin_lock(&ls->ls_lkbidr_spin);
@@ -1240,6 +1339,11 @@ static void kill_lkb(struct kref *kref)
DLM_ASSERT(!lkb->lkb_status, dlm_print_lkb(lkb););
}
static void free_range_keys(struct dlm_range *range)
{
kfree(range->start);
kfree(range->end);
}
/* __put_lkb() is used when an lkb may not have an rsb attached to
it so we need to provide the lockspace explicitly */
@@ -1254,6 +1358,9 @@ static int __put_lkb(struct dlm_ls *ls, struct dlm_lkb *lkb)
detach_lkb(lkb);
free_range_keys(&lkb->lkb_rqrange);
free_range_keys(&lkb->lkb_grrange);
/* for local/process lkbs, lvbptr points to caller's lksb */
if (lkb->lkb_lvbptr && is_master_copy(lkb))
dlm_free_lvb(lkb->lkb_lvbptr);
@@ -1315,6 +1422,8 @@ static void add_lkb(struct dlm_rsb *r, struct dlm_lkb *lkb, int status)
kref_get(&lkb->lkb_ref);
DLM_ASSERT(!lkb->lkb_status, dlm_print_lkb(lkb););
BUG_ON(status != DLM_LKSTS_WAITING && !START(lkb));
BUG_ON(status != DLM_LKSTS_WAITING && !LAST(lkb));
lkb->lkb_timestamp = ktime_get();
@@ -1331,6 +1440,7 @@ static void add_lkb(struct dlm_rsb *r, struct dlm_lkb *lkb, int status)
/* convention says granted locks kept in order of grmode */
lkb_add_ordered(&lkb->lkb_statequeue, &r->res_grantqueue,
lkb->lkb_grmode);
rsb_interval_insert(lkb, &r->res_grantroot);
break;
case DLM_LKSTS_CONVERT:
if (lkb->lkb_exflags & DLM_LKF_HEADQUE)
@@ -1338,16 +1448,45 @@ static void add_lkb(struct dlm_rsb *r, struct dlm_lkb *lkb, int status)
else
list_add_tail(&lkb->lkb_statequeue,
&r->res_convertqueue);
rsb_interval_insert(lkb, &r->res_convertroot);
break;
default:
DLM_ASSERT(0, dlm_print_lkb(lkb); printk("sts=%d\n", status););
}
}
static struct rb_root *lkb_res_root(struct dlm_rsb *r, struct dlm_lkb *lkb)
{
struct rb_root *ret = NULL;
switch (lkb->lkb_status) {
case DLM_LKSTS_GRANTED:
ret = &r->res_grantroot;
break;
case DLM_LKSTS_CONVERT:
ret = &r->res_convertroot;
break;
default:
DLM_ASSERT(0, dlm_print_lkb(lkb);
printk("sts=%d\n", lkb->lkb_status););
}
return ret;
}
static void del_lkb(struct dlm_rsb *r, struct dlm_lkb *lkb)
{
struct rb_root *root = NULL;
if (lkb->lkb_status && lkb->lkb_status != DLM_LKSTS_WAITING)
root = lkb_res_root(r, lkb);
lkb->lkb_status = 0;
list_del(&lkb->lkb_statequeue);
if (root) {
rsb_interval_remove(lkb, root);
RB_CLEAR_NODE(&lkb->lkb_statenode);/* To aid in debugging */
}
WARN_ON(!RB_EMPTY_NODE(&lkb->lkb_statenode));
unhold_lkb(lkb);
}
@@ -2113,6 +2252,11 @@ static int revert_lock_pc(struct dlm_rsb *r, struct dlm_lkb *lkb)
static void _grant_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)
{
/* Set ranges now so move/add lkb has something to insert */
lkb->lkb_grrange.start = lkb->lkb_rqrange.start;
lkb->lkb_grrange.end = lkb->lkb_rqrange.end;
lkb->lkb_rqrange.start = lkb->lkb_rqrange.end = NULL;
if (lkb->lkb_grmode != lkb->lkb_rqmode) {
lkb->lkb_grmode = lkb->lkb_rqmode;
if (lkb->lkb_status)
@@ -2189,27 +2333,34 @@ static void munge_altmode(struct dlm_lkb *lkb, struct dlm_message *ms)
}
}
static inline int first_in_list(struct dlm_lkb *lkb, struct list_head *head)
static inline int first_in_list_range(struct dlm_lkb *lkb, struct list_head *head)
{
struct dlm_lkb *first = list_entry(head->next, struct dlm_lkb,
lkb_statequeue);
if (lkb->lkb_id == first->lkb_id)
return 1;
struct dlm_lkb *first;
list_for_each_entry(first, head, lkb_statequeue) {
if (ranges_overlap(&lkb->lkb_rqrange, &first->lkb_rqrange)) {
if (lkb->lkb_id == first->lkb_id)
return 1;
break;
}
}
return 0;
}
/* Check if the given lkb conflicts with another lkb on the queue. */
static int queue_conflict(struct list_head *head, struct dlm_lkb *lkb)
static int queue_conflict(struct rb_root *root, struct dlm_lkb *lkb)
{
struct dlm_lkb *this;
struct dlm_key *start, *end;
list_for_each_entry(this, head, lkb_statequeue) {
if (this == lkb)
continue;
if (!modes_compat(this, lkb))
start = lkb->lkb_rqrange.start;
end = lkb->lkb_rqrange.end;
this = rsb_interval_iter_first(root, start, end);
while (this) {
if (this != lkb && !modes_compat(this, lkb))
return 1;
this = rsb_interval_iter_next(this, start, end);
}
return 0;
}
@@ -2266,6 +2417,9 @@ static int conversion_deadlock_detect(struct dlm_rsb *r, struct dlm_lkb *lkb2)
continue;
}
if (!ranges_overlap(&lkb1->lkb_rqrange, &lkb2->lkb_grrange))
continue;
if (!lkb_is_ahead) {
if (!modes_compat(lkb2, lkb1))
return 1;
@@ -2326,7 +2480,7 @@ static int _can_be_granted(struct dlm_rsb *r, struct dlm_lkb *lkb, int now,
* added to the remaining conditions.
*/
if (queue_conflict(&r->res_grantqueue, lkb))
if (queue_conflict(&r->res_grantroot, lkb))
return 0;
/*
@@ -2335,7 +2489,7 @@ static int _can_be_granted(struct dlm_rsb *r, struct dlm_lkb *lkb, int now,
* locks
*/
if (queue_conflict(&r->res_convertqueue, lkb))
if (queue_conflict(&r->res_convertroot, lkb))
return 0;
/*
@@ -2406,8 +2560,7 @@ static int _can_be_granted(struct dlm_rsb *r, struct dlm_lkb *lkb, int now,
* granted until all other conversion requests ahead of it are granted
* and/or canceled.
*/
if (!now && conv && first_in_list(lkb, &r->res_convertqueue))
if (!now && conv && first_in_list_range(lkb, &r->res_convertqueue))
return 1;
/*
@@ -2434,7 +2587,7 @@ static int _can_be_granted(struct dlm_rsb *r, struct dlm_lkb *lkb, int now,
*/
if (!now && !conv && list_empty(&r->res_convertqueue) &&
first_in_list(lkb, &r->res_waitqueue))
first_in_list_range(lkb, &r->res_waitqueue))
return 1;
return 0;
@@ -2512,7 +2665,7 @@ static int can_be_granted(struct dlm_rsb *r, struct dlm_lkb *lkb, int now,
cw if there's a blocked conversion to DLM_LOCK_CW. */
static int grant_pending_convert(struct dlm_rsb *r, int high, int *cw,
unsigned int *count)
unsigned int *count, struct dlm_range **range)
{
struct dlm_lkb *lkb, *s;
int recover = rsb_flag(r, RSB_RECOVER_GRANT);
@@ -2551,7 +2704,11 @@ static int grant_pending_convert(struct dlm_rsb *r, int high, int *cw,
continue;
}
hi = max_t(int, lkb->lkb_rqmode, hi);
if (lkb->lkb_rqmode > hi) {
hi = lkb->lkb_rqmode;
if (range)
*range = &lkb->lkb_rqrange;
}
if (cw && lkb->lkb_rqmode == DLM_LOCK_CW)
*cw = 1;
@@ -2568,7 +2725,7 @@ static int grant_pending_convert(struct dlm_rsb *r, int high, int *cw,
}
static int grant_pending_wait(struct dlm_rsb *r, int high, int *cw,
unsigned int *count)
unsigned int *count, struct dlm_range **range)
{
struct dlm_lkb *lkb, *s;
@@ -2578,7 +2735,11 @@ static int grant_pending_wait(struct dlm_rsb *r, int high, int *cw,
if (count)
(*count)++;
} else {
high = max_t(int, lkb->lkb_rqmode, high);
if (lkb->lkb_rqmode > high) {
high = lkb->lkb_rqmode;
*range = &lkb->lkb_rqrange;
}
if (lkb->lkb_rqmode == DLM_LOCK_CW)
*cw = 1;
}
@@ -2611,15 +2772,15 @@ static void grant_pending_locks(struct dlm_rsb *r, unsigned int *count)
struct dlm_lkb *lkb, *s;
int high = DLM_LOCK_IV;
int cw = 0;
struct dlm_range *highrange = NULL;
if (!is_master(r)) {
log_print("grant_pending_locks r nodeid %d", r->res_nodeid);
dlm_dump_rsb(r);
return;
}
high = grant_pending_convert(r, high, &cw, count);
high = grant_pending_wait(r, high, &cw, count);
high = grant_pending_convert(r, high, &cw, count, &highrange);
high = grant_pending_wait(r, high, &cw, count, &highrange);
if (high == DLM_LOCK_IV)
return;
@@ -2631,12 +2792,13 @@ static void grant_pending_locks(struct dlm_rsb *r, unsigned int *count)
*/
list_for_each_entry_safe(lkb, s, &r->res_grantqueue, lkb_statequeue) {
if (lkb->lkb_bastfn && lock_requires_bast(lkb, high, cw)) {
if ((lkb->lkb_bastfn || lkb->lkb_rbastfn) &&
lock_requires_bast(lkb, high, cw)) {
if (cw && high == DLM_LOCK_PR &&
lkb->lkb_grmode == DLM_LOCK_PR)
queue_bast(r, lkb, DLM_LOCK_CW);
queue_bast(r, lkb, DLM_LOCK_CW, highrange);
else
queue_bast(r, lkb, high);
queue_bast(r, lkb, high, highrange);
lkb->lkb_highbast = high;
}
}
@@ -2665,8 +2827,9 @@ static void send_bast_queue(struct dlm_rsb *r, struct list_head *head,
/* skip self when sending basts to convertqueue */
if (gr == lkb)
continue;
if (gr->lkb_bastfn && modes_require_bast(gr, lkb)) {
queue_bast(r, gr, lkb->lkb_rqmode);
if ((gr->lkb_rbastfn || gr->lkb_bastfn) &&
modes_require_bast(gr, lkb)) {
queue_bast(r, gr, lkb->lkb_rqmode, &lkb->lkb_rqrange);
gr->lkb_highbast = lkb->lkb_rqmode;
}
}
@@ -2801,11 +2964,15 @@ static void confirm_master(struct dlm_rsb *r, int error)
}
}
static int set_lock_args(int mode, struct dlm_lksb *lksb, uint32_t flags,
static int set_lock_args(int mode, struct dlm_range *range,
struct dlm_lksb *lksb, uint32_t flags,
int namelen, unsigned long timeout_cs,
void (*ast) (void *astparam),
void *astparam,
void (*bast) (void *astparam, int mode),
void (*rbast) (void *astarg, int mode,
struct dlm_key *start,
struct dlm_key *end),
struct dlm_args *args)
{
int rv = -EINVAL;
@@ -2815,6 +2982,9 @@ static int set_lock_args(int mode, struct dlm_lksb *lksb, uint32_t flags,
if (mode < 0 || mode > DLM_LOCK_EX)
goto out;
if (range && cmp_dlm_keys(range->start, range->end) > 0)
goto out;
if (!(flags & DLM_LKF_CONVERT) && (namelen > DLM_RESNAME_MAXLEN))
goto out;
@@ -2851,6 +3021,10 @@ static int set_lock_args(int mode, struct dlm_lksb *lksb, uint32_t flags,
if (flags & DLM_LKF_CONVERT && !lksb->sb_lkid)
goto out;
/* XXX: The caller could pass default_range for us */
if (!range)
range = &default_range;
/* these args will be copied to the lkb in validate_lock_args,
it cannot be done now because when converting locks, fields in
an active lkb cannot be modified before locking the rsb */
@@ -2859,8 +3033,10 @@ static int set_lock_args(int mode, struct dlm_lksb *lksb, uint32_t flags,
args->astfn = ast;
args->astparam = astparam;
args->bastfn = bast;
args->rbastfn = rbast;
args->timeout = timeout_cs;
args->mode = mode;
args->range = *range;
args->lksb = lksb;
rv = 0;
out:
@@ -2910,7 +3086,21 @@ static int validate_lock_args(struct dlm_ls *ls, struct dlm_lkb *lkb,
lkb->lkb_astfn = args->astfn;
lkb->lkb_astparam = args->astparam;
lkb->lkb_bastfn = args->bastfn;
lkb->lkb_rbastfn = args->rbastfn;
lkb->lkb_rqmode = args->mode;
if (args->range.start && args->range.end) {
rv = -ENOMEM;
lkb->lkb_rqrange.start = alloc_key(args->range.start->val,
args->range.start->len,
GFP_NOFS);
if (!lkb->lkb_rqrange.start)
goto out;
lkb->lkb_rqrange.end = alloc_key(args->range.end->val,
args->range.end->len,
GFP_NOFS);
if (!lkb->lkb_rqrange.end)
goto out;
}
lkb->lkb_lksb = args->lksb;
lkb->lkb_lvbptr = args->lksb->sb_lvbptr;
lkb->lkb_ownpid = (int) current->pid;
@@ -2970,6 +3160,11 @@ static int validate_unlock_args(struct dlm_lkb *lkb, struct dlm_args *args)
goto out;
}
#if 0
/* XXX: Shouldn't CANCEL check against rqstart/rqend? */
if (args->start != lkb->lkb_grstart || args->end != lkb->lkb_grend)
goto out;
#endif
/* cancel not allowed with another cancel/unlock in progress */
if (args->flags & DLM_LKF_CANCEL) {
@@ -3055,8 +3250,8 @@ static int validate_unlock_args(struct dlm_lkb *lkb, struct dlm_args *args)
rv = 0;
out:
if (rv)
log_debug(ls, "validate_unlock_args %d %x %x %x %x %d %s", rv,
lkb->lkb_id, lkb->lkb_flags, lkb->lkb_exflags,
log_debug(ls, "validate_unlock_args %d %x %x %x %x %d %s",
rv, lkb->lkb_id, lkb->lkb_flags, lkb->lkb_exflags,
args->flags, lkb->lkb_wait_type,
lkb->lkb_resource->res_name);
return rv;
@@ -3138,7 +3333,7 @@ static int do_convert(struct dlm_rsb *r, struct dlm_lkb *lkb)
before we try again to grant this one. */
if (is_demoted(lkb)) {
grant_pending_convert(r, DLM_LOCK_IV, NULL, NULL);
grant_pending_convert(r, DLM_LOCK_IV, NULL, NULL, NULL);
if (_can_be_granted(r, lkb, 1, 0)) {
grant_lock(r, lkb);
queue_cast(r, lkb, 0);
@@ -3405,19 +3600,24 @@ static int cancel_lock(struct dlm_ls *ls, struct dlm_lkb *lkb,
* Two stage 1 varieties: dlm_lock() and dlm_unlock()
*/
int dlm_lock(dlm_lockspace_t *lockspace,
int mode,
struct dlm_lksb *lksb,
uint32_t flags,
void *name,
unsigned int namelen,
uint32_t parent_lkid,
void (*ast) (void *astarg),
void *astarg,
void (*bast) (void *astarg, int mode))
static int _dlm_lock(dlm_lockspace_t *lockspace,
int mode,
struct dlm_key *start,
struct dlm_key *end,
struct dlm_lksb *lksb,
uint32_t flags,
void *name,
unsigned int namelen,
uint32_t parent_lkid,
void (*ast) (void *astarg),
void *astarg,
void (*bast) (void *astarg, int mode),
void (*rbast) (void *astarg, int mode,
struct dlm_key *start, struct dlm_key *end))
{
struct dlm_ls *ls;
struct dlm_lkb *lkb;
struct dlm_range range = { start, end };
struct dlm_args args;
int error, convert = flags & DLM_LKF_CONVERT;
@@ -3435,8 +3635,8 @@ int dlm_lock(dlm_lockspace_t *lockspace,
if (error)
goto out;
error = set_lock_args(mode, lksb, flags, namelen, 0, ast,
astarg, bast, &args);
error = set_lock_args(mode, start ? &range : NULL, lksb, flags, namelen,
0, ast, astarg, bast, rbast, &args);
if (error)
goto out_put;
@@ -3458,6 +3658,47 @@ int dlm_lock(dlm_lockspace_t *lockspace,
return error;
}
int dlm_lock_range(dlm_lockspace_t *lockspace,
int mode,
struct dlm_key *start,
struct dlm_key *end,
struct dlm_lksb *lksb,
uint32_t flags,
void *name,
unsigned int namelen,
uint32_t parent_lkid,
void (*ast) (void *astarg),
void *astarg,
void (*rbast) (void *astarg, int mode,
struct dlm_key *start, struct dlm_key *end))
{
if (!start || !end)
return -EINVAL;
if (start->len > DLM_KEY_LEN || end->len > DLM_KEY_LEN) {
WARN_ON_ONCE(1);
return -EINVAL;
}
return _dlm_lock(lockspace, mode, start, end, lksb, flags, name,
namelen, parent_lkid, ast, astarg, NULL, rbast);
}
int dlm_lock(dlm_lockspace_t *lockspace,
int mode,
struct dlm_lksb *lksb,
uint32_t flags,
void *name,
unsigned int namelen,
uint32_t parent_lkid,
void (*ast) (void *astarg),
void *astarg,
void (*bast) (void *astarg, int mode))
{
return _dlm_lock(lockspace, mode, NULL, NULL, lksb, flags, name,
namelen, parent_lkid, ast, astarg, bast, NULL);
}
int dlm_unlock(dlm_lockspace_t *lockspace,
uint32_t lkid,
uint32_t flags,
@@ -3492,6 +3733,7 @@ int dlm_unlock(dlm_lockspace_t *lockspace,
error = 0;
if (error == -EBUSY && (flags & (DLM_LKF_CANCEL | DLM_LKF_FORCEUNLOCK)))
error = 0;
out_put:
dlm_put_lkb(lkb);
out:
@@ -3609,10 +3851,29 @@ static void send_args(struct dlm_rsb *r, struct dlm_lkb *lkb,
ms->m_rqmode = lkb->lkb_rqmode;
ms->m_hash = r->res_hash;
ms->m_grstart_len = ms->m_grend_len = ms->m_rqstart_len =
ms->m_rqend_len = 0;
if (lkb->lkb_grrange.start) {
ms->m_grstart_len = lkb->lkb_grrange.start->len;
memcpy(ms->m_grstart, lkb->lkb_grrange.start->val, ms->m_grstart_len);
}
if (lkb->lkb_grrange.end) {
ms->m_grend_len = lkb->lkb_grrange.end->len;
memcpy(ms->m_grend, lkb->lkb_grrange.end->val, ms->m_grend_len);
}
if (lkb->lkb_rqrange.start) {
ms->m_rqstart_len = lkb->lkb_rqrange.start->len;
memcpy(ms->m_rqstart, lkb->lkb_rqrange.start->val, ms->m_rqstart_len);
}
if (lkb->lkb_rqrange.end) {
ms->m_rqend_len = lkb->lkb_rqrange.end->len;
memcpy(ms->m_rqend, lkb->lkb_rqrange.end->val, ms->m_rqend_len);
}
/* m_result and m_bastmode are set from function args,
not from lkb fields */
if (lkb->lkb_bastfn)
if (lkb->lkb_bastfn || lkb->lkb_rbastfn)
ms->m_asts |= DLM_CB_BAST;
if (lkb->lkb_astfn)
ms->m_asts |= DLM_CB_CAST;
@@ -3738,6 +3999,7 @@ static int send_bast(struct dlm_rsb *r, struct dlm_lkb *lkb, int mode)
send_args(r, lkb, ms);
ms->m_bastmode = mode;
/* XXX: Fill bastrange here */
error = send_message(mh, ms);
out:
@@ -3929,6 +4191,31 @@ static int receive_request_args(struct dlm_ls *ls, struct dlm_lkb *lkb,
return -ENOMEM;
}
if (ms->m_grstart_len) {
lkb->lkb_grrange.start = alloc_key(ms->m_grstart,
ms->m_grstart_len, GFP_NOFS);
if (!lkb->lkb_grrange.start)
return -ENOMEM;
}
if (ms->m_grend_len) {
lkb->lkb_grrange.end = alloc_key(ms->m_grend, ms->m_grend_len,
GFP_NOFS);
if (!lkb->lkb_grrange.end)
return -ENOMEM;
}
if (ms->m_rqstart_len) {
lkb->lkb_rqrange.start = alloc_key(ms->m_rqstart,
ms->m_rqstart_len, GFP_NOFS);
if (!lkb->lkb_rqrange.start)
return -ENOMEM;
}
if (ms->m_rqend_len) {
lkb->lkb_rqrange.end = alloc_key(ms->m_rqend, ms->m_rqend_len,
GFP_NOFS);
if (!lkb->lkb_rqrange.end)
return -ENOMEM;
}
return 0;
}
@@ -4335,6 +4622,8 @@ static int receive_bast(struct dlm_ls *ls, struct dlm_message *ms)
{
struct dlm_lkb *lkb;
struct dlm_rsb *r;
struct dlm_range range;
struct dlm_key start, end;
int error;
error = find_lkb(ls, ms->m_remid, &lkb);
@@ -4350,7 +4639,14 @@ static int receive_bast(struct dlm_ls *ls, struct dlm_message *ms)
if (error)
goto out;
queue_bast(r, lkb, ms->m_bastmode);
start.val = ms->m_baststart;
start.len = ms->m_baststart_len;
end.val = ms->m_bastend;
end.len = ms->m_bastend_len;
range.start = &start;
range.end = &end;
queue_bast(r, lkb, ms->m_bastmode, &range);
lkb->lkb_highbast = ms->m_bastmode;
out:
unlock_rsb(r);
@@ -5796,8 +6092,9 @@ int dlm_user_request(struct dlm_ls *ls, struct dlm_user_args *ua,
When DLM_IFL_USER is set, the dlm knows that this is a userspace
lock and that lkb_astparam is the dlm_user_args structure. */
error = set_lock_args(mode, &ua->lksb, flags, namelen, timeout_cs,
fake_astfn, ua, fake_bastfn, &args);
error = set_lock_args(mode, NULL, &ua->lksb, flags, namelen,
timeout_cs, fake_astfn, ua, fake_bastfn, NULL,
&args);
lkb->lkb_flags |= DLM_IFL_USER;
if (error) {
@@ -5868,8 +6165,8 @@ int dlm_user_convert(struct dlm_ls *ls, struct dlm_user_args *ua_tmp,
ua->bastaddr = ua_tmp->bastaddr;
ua->user_lksb = ua_tmp->user_lksb;
error = set_lock_args(mode, &ua->lksb, flags, 0, timeout_cs,
fake_astfn, ua, fake_bastfn, &args);
error = set_lock_args(mode, NULL, &ua->lksb, flags, 0, timeout_cs,
fake_astfn, ua, fake_bastfn, NULL, &args);
if (error)
goto out_put;
+2
View File
@@ -76,5 +76,7 @@ static inline void unlock_rsb(struct dlm_rsb *r)
mutex_unlock(&r->res_mutex);
}
int ranges_overlap(struct dlm_range *range1, struct dlm_range *range2);
#endif
+1 -1
View File
@@ -632,9 +632,9 @@ static int new_lockspace(const char *name, const char *cluster,
error = do_uevent(ls, 1);
if (error)
goto out_recoverd;
wait_for_completion(&ls->ls_members_done);
error = ls->ls_members_result;
if (error)
goto out_members;
+1
View File
@@ -94,4 +94,5 @@ EXPORT_SYMBOL_GPL(dlm_new_lockspace);
EXPORT_SYMBOL_GPL(dlm_release_lockspace);
EXPORT_SYMBOL_GPL(dlm_lock);
EXPORT_SYMBOL_GPL(dlm_unlock);
EXPORT_SYMBOL_GPL(dlm_lock_range);
+1 -1
View File
@@ -7,7 +7,7 @@
*/
#include <net/genetlink.h>
#include <linux/dlm.h>
#include "include/linux/dlm.h"
#include <linux/dlm_netlink.h>
#include <linux/gfp.h>
+1 -1
View File
@@ -9,7 +9,7 @@
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/poll.h>
#include <linux/dlm.h>
#include "include/linux/dlm.h"
#include <linux/dlm_plock.h>
#include <linux/slab.h>
+1 -1
View File
@@ -399,7 +399,7 @@ static void pack_rcom_lock(struct dlm_rsb *r, struct dlm_lkb *lkb,
rl->rl_status = lkb->lkb_status;
rl->rl_wait_type = cpu_to_le16(lkb->lkb_wait_type);
if (lkb->lkb_bastfn)
if (lkb->lkb_bastfn || lkb->lkb_rbastfn)
rl->rl_asts |= DLM_CB_BAST;
if (lkb->lkb_astfn)
rl->rl_asts |= DLM_CB_CAST;
+2 -2
View File
@@ -15,7 +15,7 @@
#include <linux/poll.h>
#include <linux/signal.h>
#include <linux/spinlock.h>
#include <linux/dlm.h>
#include "include/linux/dlm.h"
#include <linux/dlm_device.h>
#include <linux/slab.h>
@@ -207,7 +207,7 @@ void dlm_user_add_ast(struct dlm_lkb *lkb, uint32_t flags, int mode,
spin_lock(&proc->asts_spin);
rv = dlm_add_lkb_callback(lkb, flags, mode, status, sbflags, seq);
rv = dlm_add_lkb_callback(lkb, flags, mode, NULL, status, sbflags, seq);
if (rv < 0) {
spin_unlock(&proc->asts_spin);
goto out;
+18
View File
@@ -105,6 +105,15 @@ void dlm_message_out(struct dlm_message *ms)
ms->m_bastmode = cpu_to_le32(ms->m_bastmode);
ms->m_asts = cpu_to_le32(ms->m_asts);
ms->m_result = cpu_to_le32(to_dlm_errno(ms->m_result));
ms->m_grstart_len = cpu_to_le16(ms->m_grstart_len);
ms->m_grend_len = cpu_to_le16(ms->m_grend_len);
ms->m_rqstart_len = cpu_to_le16(ms->m_rqstart_len);
ms->m_rqend_len = cpu_to_le16(ms->m_rqend_len);
ms->m_baststart_len = cpu_to_le16(ms->m_baststart_len);
ms->m_bastend_len = cpu_to_le16(ms->m_bastend_len);
}
void dlm_message_in(struct dlm_message *ms)
@@ -129,6 +138,15 @@ void dlm_message_in(struct dlm_message *ms)
ms->m_bastmode = le32_to_cpu(ms->m_bastmode);
ms->m_asts = le32_to_cpu(ms->m_asts);
ms->m_result = from_dlm_errno(le32_to_cpu(ms->m_result));
ms->m_grstart_len = le16_to_cpu(ms->m_grstart_len);
ms->m_grend_len = le16_to_cpu(ms->m_grend_len);
ms->m_rqstart_len = le16_to_cpu(ms->m_rqstart_len);
ms->m_rqend_len = le16_to_cpu(ms->m_rqend_len);
ms->m_baststart_len = le16_to_cpu(ms->m_baststart_len);
ms->m_bastend_len = le16_to_cpu(ms->m_bastend_len);
}
void dlm_rcom_out(struct dlm_rcom *rc)