diff --git a/kmod/dlm/Makefile b/kmod/dlm/Makefile index c43e89cd..5710f265 100644 --- a/kmod/dlm/Makefile +++ b/kmod/dlm/Makefile @@ -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 diff --git a/kmod/dlm/ast.c b/kmod/dlm/ast.c index 27a6ba9a..19630d43 100644 --- a/kmod/dlm/ast.c +++ b/kmod/dlm/ast.c @@ -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) diff --git a/kmod/dlm/ast.h b/kmod/dlm/ast.h index 757b551c..09fc3934 100644 --- a/kmod/dlm/ast.h +++ b/kmod/dlm/ast.h @@ -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); diff --git a/kmod/dlm/config.c b/kmod/dlm/config.c index 7d58d5b1..a6662120 100644 --- a/kmod/dlm/config.c +++ b/kmod/dlm/config.c @@ -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 diff --git a/kmod/dlm/dlm_internal.h b/kmod/dlm/dlm_internal.h index e7665c31..b4a91e4c 100644 --- a/kmod/dlm/dlm_internal.h +++ b/kmod/dlm/dlm_internal.h @@ -40,8 +40,9 @@ #include #include #include +#include -#include +#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 */ }; diff --git a/kmod/dlm/dlmtest.c b/kmod/dlm/dlmtest.c new file mode 100644 index 00000000..4c7d72fc --- /dev/null +++ b/kmod/dlm/dlmtest.c @@ -0,0 +1,307 @@ +#include +#include +#include +#include + +#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"); diff --git a/kmod/dlm/include/linux/dlm.h b/kmod/dlm/include/linux/dlm.h index d02da2c6..cbf05678 100644 --- a/kmod/dlm/include/linux/dlm.h +++ b/kmod/dlm/include/linux/dlm.h @@ -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__ */ diff --git a/kmod/dlm/lock.c b/kmod/dlm/lock.c index 275e171c..d62127fe 100644 --- a/kmod/dlm/lock.c +++ b/kmod/dlm/lock.c @@ -60,6 +60,7 @@ #include #include "dlm_internal.h" #include +#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; diff --git a/kmod/dlm/lock.h b/kmod/dlm/lock.h index ed8ebd3a..271736a4 100644 --- a/kmod/dlm/lock.h +++ b/kmod/dlm/lock.h @@ -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 diff --git a/kmod/dlm/lockspace.c b/kmod/dlm/lockspace.c index 88556dc0..84cb7210 100644 --- a/kmod/dlm/lockspace.c +++ b/kmod/dlm/lockspace.c @@ -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; diff --git a/kmod/dlm/main.c b/kmod/dlm/main.c index 079c0bd7..d880842d 100644 --- a/kmod/dlm/main.c +++ b/kmod/dlm/main.c @@ -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); diff --git a/kmod/dlm/netlink.c b/kmod/dlm/netlink.c index e7cfbaf8..71275218 100644 --- a/kmod/dlm/netlink.c +++ b/kmod/dlm/netlink.c @@ -7,7 +7,7 @@ */ #include -#include +#include "include/linux/dlm.h" #include #include diff --git a/kmod/dlm/plock.c b/kmod/dlm/plock.c index f704458e..a33b4f27 100644 --- a/kmod/dlm/plock.c +++ b/kmod/dlm/plock.c @@ -9,7 +9,7 @@ #include #include #include -#include +#include "include/linux/dlm.h" #include #include diff --git a/kmod/dlm/rcom.c b/kmod/dlm/rcom.c index f3f5e72a..7af563a2 100644 --- a/kmod/dlm/rcom.c +++ b/kmod/dlm/rcom.c @@ -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; diff --git a/kmod/dlm/user.c b/kmod/dlm/user.c index 16a96f6f..826437e3 100644 --- a/kmod/dlm/user.c +++ b/kmod/dlm/user.c @@ -15,7 +15,7 @@ #include #include #include -#include +#include "include/linux/dlm.h" #include #include @@ -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; diff --git a/kmod/dlm/util.c b/kmod/dlm/util.c index e36520af..b18eded3 100644 --- a/kmod/dlm/util.c +++ b/kmod/dlm/util.c @@ -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)