mirror of
https://github.com/versity/scoutfs.git
synced 2026-09-03 22:56:58 +00:00
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:
+2
-2
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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 */
|
||||
};
|
||||
|
||||
|
||||
@@ -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");
|
||||
@@ -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
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user