hwmon: add TI ads7871 a/d converter driver
[safe/jmp/linux-2.6] / fs / dlm / lock.c
index 43ca2a3..031dbe3 100644 (file)
@@ -1,7 +1,7 @@
 /******************************************************************************
 *******************************************************************************
 **
-**  Copyright (C) 2005-2007 Red Hat, Inc.  All rights reserved.
+**  Copyright (C) 2005-2010 Red Hat, Inc.  All rights reserved.
 **
 **  This copyrighted material is made available to anyone wishing to use,
 **  modify, copy, or redistribute it subject to the terms and conditions
@@ -56,6 +56,7 @@
    L: receive_xxxx_reply()     <-  R: send_xxxx_reply()
 */
 #include <linux/types.h>
+#include <linux/slab.h>
 #include "dlm_internal.h"
 #include <linux/dlm_device.h>
 #include "memory.h"
@@ -165,7 +166,7 @@ void dlm_print_lkb(struct dlm_lkb *lkb)
               lkb->lkb_grmode, lkb->lkb_wait_type, lkb->lkb_ast_type);
 }
 
-void dlm_print_rsb(struct dlm_rsb *r)
+static void dlm_print_rsb(struct dlm_rsb *r)
 {
        printk(KERN_ERR "rsb: nodeid %d flags %lx first %x rlc %d name %s\n",
               r->res_nodeid, r->res_flags, r->res_first_lkid,
@@ -307,7 +308,7 @@ static void queue_cast(struct dlm_rsb *r, struct dlm_lkb *lkb, int rv)
        lkb->lkb_lksb->sb_status = rv;
        lkb->lkb_lksb->sb_flags = lkb->lkb_sbflags;
 
-       dlm_add_ast(lkb, AST_COMP);
+       dlm_add_ast(lkb, AST_COMP, lkb->lkb_grmode);
 }
 
 static inline void queue_cast_overlap(struct dlm_rsb *r, struct dlm_lkb *lkb)
@@ -318,11 +319,13 @@ static inline void queue_cast_overlap(struct dlm_rsb *r, struct dlm_lkb *lkb)
 
 static void queue_bast(struct dlm_rsb *r, struct dlm_lkb *lkb, int rqmode)
 {
-       if (is_master_copy(lkb))
+       lkb->lkb_time_bast = ktime_get();
+
+       if (is_master_copy(lkb)) {
+               lkb->lkb_bastmode = rqmode; /* printed by debugfs */
                send_bast(r, lkb, rqmode);
-       else {
-               lkb->lkb_bastmode = rqmode;
-               dlm_add_ast(lkb, AST_BAST);
+       } else {
+               dlm_add_ast(lkb, AST_BAST, rqmode);
        }
 }
 
@@ -363,6 +366,7 @@ static int search_rsb_list(struct list_head *head, char *name, int len,
                if (len == r->res_length && !memcmp(name, r->res_name, len))
                        goto found;
        }
+       *r_ret = NULL;
        return -EBADR;
 
  found:
@@ -411,9 +415,9 @@ static int search_rsb(struct dlm_ls *ls, char *name, int len, int b,
                      unsigned int flags, struct dlm_rsb **r_ret)
 {
        int error;
-       write_lock(&ls->ls_rsbtbl[b].lock);
+       spin_lock(&ls->ls_rsbtbl[b].lock);
        error = _search_rsb(ls, name, len, b, flags, r_ret);
-       write_unlock(&ls->ls_rsbtbl[b].lock);
+       spin_unlock(&ls->ls_rsbtbl[b].lock);
        return error;
 }
 
@@ -434,13 +438,17 @@ static int search_rsb(struct dlm_ls *ls, char *name, int len, int b,
 static int find_rsb(struct dlm_ls *ls, char *name, int namelen,
                    unsigned int flags, struct dlm_rsb **r_ret)
 {
-       struct dlm_rsb *r, *tmp;
+       struct dlm_rsb *r = NULL, *tmp;
        uint32_t hash, bucket;
-       int error = 0;
+       int error = -EINVAL;
+
+       if (namelen > DLM_RESNAME_MAXLEN)
+               goto out;
 
        if (dlm_no_directory(ls))
                flags |= R_CREATE;
 
+       error = 0;
        hash = jhash(name, namelen, 0);
        bucket = hash & (ls->ls_rsbtbl_size - 1);
 
@@ -473,28 +481,22 @@ static int find_rsb(struct dlm_ls *ls, char *name, int namelen,
                r->res_nodeid = nodeid;
        }
 
-       write_lock(&ls->ls_rsbtbl[bucket].lock);
+       spin_lock(&ls->ls_rsbtbl[bucket].lock);
        error = _search_rsb(ls, name, namelen, bucket, 0, &tmp);
        if (!error) {
-               write_unlock(&ls->ls_rsbtbl[bucket].lock);
+               spin_unlock(&ls->ls_rsbtbl[bucket].lock);
                dlm_free_rsb(r);
                r = tmp;
                goto out;
        }
        list_add(&r->res_hashchain, &ls->ls_rsbtbl[bucket].list);
-       write_unlock(&ls->ls_rsbtbl[bucket].lock);
+       spin_unlock(&ls->ls_rsbtbl[bucket].lock);
        error = 0;
  out:
        *r_ret = r;
        return error;
 }
 
-int dlm_find_rsb(struct dlm_ls *ls, char *name, int namelen,
-                unsigned int flags, struct dlm_rsb **r_ret)
-{
-       return find_rsb(ls, name, namelen, flags, r_ret);
-}
-
 /* This is only called to add a reference when the code already holds
    a valid reference to the rsb, so there's no need for locking. */
 
@@ -531,9 +533,9 @@ static void put_rsb(struct dlm_rsb *r)
        struct dlm_ls *ls = r->res_ls;
        uint32_t bucket = r->res_bucket;
 
-       write_lock(&ls->ls_rsbtbl[bucket].lock);
+       spin_lock(&ls->ls_rsbtbl[bucket].lock);
        kref_put(&r->res_ref, toss_rsb);
-       write_unlock(&ls->ls_rsbtbl[bucket].lock);
+       spin_unlock(&ls->ls_rsbtbl[bucket].lock);
 }
 
 void dlm_put_rsb(struct dlm_rsb *r)
@@ -731,10 +733,7 @@ static void lkb_add_ordered(struct list_head *new, struct list_head *head,
                if (lkb->lkb_rqmode < mode)
                        break;
 
-       if (!lkb)
-               list_add_tail(new, head);
-       else
-               __list_add(new, lkb->lkb_statequeue.prev, &lkb->lkb_statequeue);
+       __list_add(new, lkb->lkb_statequeue.prev, &lkb->lkb_statequeue);
 }
 
 /* add/remove lkb to rsb's grant/convert/wait queue */
@@ -745,6 +744,8 @@ static void add_lkb(struct dlm_rsb *r, struct dlm_lkb *lkb, int status)
 
        DLM_ASSERT(!lkb->lkb_status, dlm_print_lkb(lkb););
 
+       lkb->lkb_timestamp = ktime_get();
+
        lkb->lkb_status = status;
 
        switch (status) {
@@ -834,7 +835,7 @@ static int add_to_waiters(struct dlm_lkb *lkb, int mstype)
                lkb->lkb_wait_count++;
                hold_lkb(lkb);
 
-               log_debug(ls, "add overlap %x cur %d new %d count %d flags %x",
+               log_debug(ls, "addwait %x cur %d overlap %d count %d f %x",
                          lkb->lkb_id, lkb->lkb_wait_type, mstype,
                          lkb->lkb_wait_count, lkb->lkb_flags);
                goto out;
@@ -850,7 +851,7 @@ static int add_to_waiters(struct dlm_lkb *lkb, int mstype)
        list_add(&lkb->lkb_wait_reply, &ls->ls_waiters);
  out:
        if (error)
-               log_error(ls, "add_to_waiters %x error %d flags %x %d %d %s",
+               log_error(ls, "addwait error %x %d flags %x %d %d %s",
                          lkb->lkb_id, error, lkb->lkb_flags, mstype,
                          lkb->lkb_wait_type, lkb->lkb_resource->res_name);
        mutex_unlock(&ls->ls_waiters_mutex);
@@ -862,23 +863,55 @@ static int add_to_waiters(struct dlm_lkb *lkb, int mstype)
    request reply on the requestqueue) between dlm_recover_waiters_pre() which
    set RESEND and dlm_recover_waiters_post() */
 
-static int _remove_from_waiters(struct dlm_lkb *lkb, int mstype)
+static int _remove_from_waiters(struct dlm_lkb *lkb, int mstype,
+                               struct dlm_message *ms)
 {
        struct dlm_ls *ls = lkb->lkb_resource->res_ls;
        int overlap_done = 0;
 
        if (is_overlap_unlock(lkb) && (mstype == DLM_MSG_UNLOCK_REPLY)) {
+               log_debug(ls, "remwait %x unlock_reply overlap", lkb->lkb_id);
                lkb->lkb_flags &= ~DLM_IFL_OVERLAP_UNLOCK;
                overlap_done = 1;
                goto out_del;
        }
 
        if (is_overlap_cancel(lkb) && (mstype == DLM_MSG_CANCEL_REPLY)) {
+               log_debug(ls, "remwait %x cancel_reply overlap", lkb->lkb_id);
                lkb->lkb_flags &= ~DLM_IFL_OVERLAP_CANCEL;
                overlap_done = 1;
                goto out_del;
        }
 
+       /* Cancel state was preemptively cleared by a successful convert,
+          see next comment, nothing to do. */
+
+       if ((mstype == DLM_MSG_CANCEL_REPLY) &&
+           (lkb->lkb_wait_type != DLM_MSG_CANCEL)) {
+               log_debug(ls, "remwait %x cancel_reply wait_type %d",
+                         lkb->lkb_id, lkb->lkb_wait_type);
+               return -1;
+       }
+
+       /* Remove for the convert reply, and premptively remove for the
+          cancel reply.  A convert has been granted while there's still
+          an outstanding cancel on it (the cancel is moot and the result
+          in the cancel reply should be 0).  We preempt the cancel reply
+          because the app gets the convert result and then can follow up
+          with another op, like convert.  This subsequent op would see the
+          lingering state of the cancel and fail with -EBUSY. */
+
+       if ((mstype == DLM_MSG_CONVERT_REPLY) &&
+           (lkb->lkb_wait_type == DLM_MSG_CONVERT) &&
+           is_overlap_cancel(lkb) && ms && !ms->m_result) {
+               log_debug(ls, "remwait %x convert_reply zap overlap_cancel",
+                         lkb->lkb_id);
+               lkb->lkb_wait_type = 0;
+               lkb->lkb_flags &= ~DLM_IFL_OVERLAP_CANCEL;
+               lkb->lkb_wait_count--;
+               goto out_del;
+       }
+
        /* N.B. type of reply may not always correspond to type of original
           msg due to lookup->request optimization, verify others? */
 
@@ -887,8 +920,8 @@ static int _remove_from_waiters(struct dlm_lkb *lkb, int mstype)
                goto out_del;
        }
 
-       log_error(ls, "remove_from_waiters lkid %x flags %x types %d %d",
-                 lkb->lkb_id, lkb->lkb_flags, mstype, lkb->lkb_wait_type);
+       log_error(ls, "remwait error %x reply %d flags %x no wait_type",
+                 lkb->lkb_id, mstype, lkb->lkb_flags);
        return -1;
 
  out_del:
@@ -898,7 +931,7 @@ static int _remove_from_waiters(struct dlm_lkb *lkb, int mstype)
           this would happen */
 
        if (overlap_done && lkb->lkb_wait_type) {
-               log_error(ls, "remove_from_waiters %x reply %d give up on %d",
+               log_error(ls, "remwait error %x reply %d wait_type %d overlap",
                          lkb->lkb_id, mstype, lkb->lkb_wait_type);
                lkb->lkb_wait_count--;
                lkb->lkb_wait_type = 0;
@@ -920,7 +953,7 @@ static int remove_from_waiters(struct dlm_lkb *lkb, int mstype)
        int error;
 
        mutex_lock(&ls->ls_waiters_mutex);
-       error = _remove_from_waiters(lkb, mstype);
+       error = _remove_from_waiters(lkb, mstype, NULL);
        mutex_unlock(&ls->ls_waiters_mutex);
        return error;
 }
@@ -935,7 +968,7 @@ static int remove_from_waiters_ms(struct dlm_lkb *lkb, struct dlm_message *ms)
 
        if (ms != &ls->ls_stub_ms)
                mutex_lock(&ls->ls_waiters_mutex);
-       error = _remove_from_waiters(lkb, ms->m_type);
+       error = _remove_from_waiters(lkb, ms->m_type, ms);
        if (ms != &ls->ls_stub_ms)
                mutex_unlock(&ls->ls_waiters_mutex);
        return error;
@@ -966,7 +999,7 @@ static int shrink_bucket(struct dlm_ls *ls, int b)
 
        for (;;) {
                found = 0;
-               write_lock(&ls->ls_rsbtbl[b].lock);
+               spin_lock(&ls->ls_rsbtbl[b].lock);
                list_for_each_entry_reverse(r, &ls->ls_rsbtbl[b].toss,
                                            res_hashchain) {
                        if (!time_after_eq(jiffies, r->res_toss_time +
@@ -977,20 +1010,20 @@ static int shrink_bucket(struct dlm_ls *ls, int b)
                }
 
                if (!found) {
-                       write_unlock(&ls->ls_rsbtbl[b].lock);
+                       spin_unlock(&ls->ls_rsbtbl[b].lock);
                        break;
                }
 
                if (kref_put(&r->res_ref, kill_rsb)) {
                        list_del(&r->res_hashchain);
-                       write_unlock(&ls->ls_rsbtbl[b].lock);
+                       spin_unlock(&ls->ls_rsbtbl[b].lock);
 
                        if (is_master(r))
                                dir_remove(r);
                        dlm_free_rsb(r);
                        count++;
                } else {
-                       write_unlock(&ls->ls_rsbtbl[b].lock);
+                       spin_unlock(&ls->ls_rsbtbl[b].lock);
                        log_error(ls, "tossed rsb in use %s", r->res_name);
                }
        }
@@ -1014,10 +1047,8 @@ static void add_timeout(struct dlm_lkb *lkb)
 {
        struct dlm_ls *ls = lkb->lkb_resource->res_ls;
 
-       if (is_master_copy(lkb)) {
-               lkb->lkb_timestamp = jiffies;
+       if (is_master_copy(lkb))
                return;
-       }
 
        if (test_bit(LSFL_TIMEWARN, &ls->ls_flags) &&
            !(lkb->lkb_exflags & DLM_LKF_NODLCKWT)) {
@@ -1032,7 +1063,6 @@ static void add_timeout(struct dlm_lkb *lkb)
        DLM_ASSERT(list_empty(&lkb->lkb_time_list), dlm_print_lkb(lkb););
        mutex_lock(&ls->ls_timeout_mutex);
        hold_lkb(lkb);
-       lkb->lkb_timestamp = jiffies;
        list_add_tail(&lkb->lkb_time_list, &ls->ls_timeout);
        mutex_unlock(&ls->ls_timeout_mutex);
 }
@@ -1060,6 +1090,7 @@ void dlm_scan_timeout(struct dlm_ls *ls)
        struct dlm_rsb *r;
        struct dlm_lkb *lkb;
        int do_cancel, do_warn;
+       s64 wait_us;
 
        for (;;) {
                if (dlm_locking_stopped(ls))
@@ -1070,14 +1101,15 @@ void dlm_scan_timeout(struct dlm_ls *ls)
                mutex_lock(&ls->ls_timeout_mutex);
                list_for_each_entry(lkb, &ls->ls_timeout, lkb_time_list) {
 
+                       wait_us = ktime_to_us(ktime_sub(ktime_get(),
+                                                       lkb->lkb_timestamp));
+
                        if ((lkb->lkb_exflags & DLM_LKF_TIMEOUT) &&
-                           time_after_eq(jiffies, lkb->lkb_timestamp +
-                                         lkb->lkb_timeout_cs * HZ/100))
+                           wait_us >= (lkb->lkb_timeout_cs * 10000))
                                do_cancel = 1;
 
                        if ((lkb->lkb_flags & DLM_IFL_WATCH_TIMEWARN) &&
-                           time_after_eq(jiffies, lkb->lkb_timestamp +
-                                          dlm_config.ci_timewarn_cs * HZ/100))
+                           wait_us >= dlm_config.ci_timewarn_cs * 10000)
                                do_warn = 1;
 
                        if (!do_cancel && !do_warn)
@@ -1123,12 +1155,12 @@ void dlm_scan_timeout(struct dlm_ls *ls)
 void dlm_adjust_timeouts(struct dlm_ls *ls)
 {
        struct dlm_lkb *lkb;
-       long adj = jiffies - ls->ls_recover_begin;
+       u64 adj_us = jiffies_to_usecs(jiffies - ls->ls_recover_begin);
 
        ls->ls_recover_begin = 0;
        mutex_lock(&ls->ls_timeout_mutex);
        list_for_each_entry(lkb, &ls->ls_timeout, lkb_time_list)
-               lkb->lkb_timestamp += adj;
+               lkb->lkb_timestamp = ktime_add_us(lkb->lkb_timestamp, adj_us);
        mutex_unlock(&ls->ls_timeout_mutex);
 }
 
@@ -1228,6 +1260,8 @@ static void set_lvb_lock_pc(struct dlm_rsb *r, struct dlm_lkb *lkb,
        b = dlm_lvb_operations[lkb->lkb_grmode + 1][lkb->lkb_rqmode + 1];
        if (b == 1) {
                int len = receive_extralen(ms);
+               if (len > DLM_RESNAME_MAXLEN)
+                       len = DLM_RESNAME_MAXLEN;
                memcpy(lkb->lkb_lvbptr, ms->m_extra, len);
                lkb->lkb_lvbseq = ms->m_lvbseq;
        }
@@ -1781,8 +1815,9 @@ static void grant_pending_locks(struct dlm_rsb *r)
         */
 
        list_for_each_entry_safe(lkb, s, &r->res_grantqueue, lkb_statequeue) {
-               if (lkb->lkb_bastaddr && lock_requires_bast(lkb, high, cw)) {
-                       if (cw && high == DLM_LOCK_PR)
+               if (lkb->lkb_bastfn && 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);
                        else
                                queue_bast(r, lkb, high);
@@ -1811,7 +1846,7 @@ static void send_bast_queue(struct dlm_rsb *r, struct list_head *head,
        struct dlm_lkb *gr;
 
        list_for_each_entry(gr, head, lkb_statequeue) {
-               if (gr->lkb_bastaddr && modes_require_bast(gr, lkb)) {
+               if (gr->lkb_bastfn && modes_require_bast(gr, lkb)) {
                        queue_bast(r, gr, lkb->lkb_rqmode);
                        gr->lkb_highbast = lkb->lkb_rqmode;
                }
@@ -1851,7 +1886,7 @@ static void send_blocking_asts_all(struct dlm_rsb *r, struct dlm_lkb *lkb)
 static int set_master(struct dlm_rsb *r, struct dlm_lkb *lkb)
 {
        struct dlm_ls *ls = r->res_ls;
-       int error, dir_nodeid, ret_nodeid, our_nodeid = dlm_our_nodeid();
+       int i, error, dir_nodeid, ret_nodeid, our_nodeid = dlm_our_nodeid();
 
        if (rsb_flag(r, RSB_MASTER_UNCERTAIN)) {
                rsb_clear_flag(r, RSB_MASTER_UNCERTAIN);
@@ -1885,7 +1920,7 @@ static int set_master(struct dlm_rsb *r, struct dlm_lkb *lkb)
                return 1;
        }
 
-       for (;;) {
+       for (i = 0; i < 2; i++) {
                /* It's possible for dlm_scand to remove an old rsb for
                   this same resource from the toss list, us to create
                   a new one, look up the master locally, and find it
@@ -1899,6 +1934,8 @@ static int set_master(struct dlm_rsb *r, struct dlm_lkb *lkb)
                log_debug(ls, "dir_lookup error %d %s", error, r->res_name);
                schedule();
        }
+       if (error && error != -EEXIST)
+               return error;
 
        if (ret_nodeid == our_nodeid) {
                r->res_first_lkid = 0;
@@ -1940,8 +1977,11 @@ static void confirm_master(struct dlm_rsb *r, int error)
                break;
 
        case -EAGAIN:
-               /* the remote master didn't queue our NOQUEUE request;
-                  make a waiting lkb the first_lkid */
+       case -EBADR:
+       case -ENOTBLK:
+               /* the remote request failed and won't be retried (it was
+                  a NOQUEUE, or has been canceled/unlocked); make a waiting
+                  lkb the first_lkid */
 
                r->res_first_lkid = 0;
 
@@ -1951,8 +1991,7 @@ static void confirm_master(struct dlm_rsb *r, int error)
                        list_del_init(&lkb->lkb_rsb_lookup);
                        r->res_first_lkid = lkb->lkb_id;
                        _request_lock(r, lkb);
-               } else
-                       r->res_nodeid = -1;
+               }
                break;
 
        default:
@@ -1961,8 +2000,11 @@ static void confirm_master(struct dlm_rsb *r, int error)
 }
 
 static int set_lock_args(int mode, struct dlm_lksb *lksb, uint32_t flags,
-                        int namelen, unsigned long timeout_cs, void *ast,
-                        void *astarg, void *bast, struct dlm_args *args)
+                        int namelen, unsigned long timeout_cs,
+                        void (*ast) (void *astparam),
+                        void *astparam,
+                        void (*bast) (void *astparam, int mode),
+                        struct dlm_args *args)
 {
        int rv = -EINVAL;
 
@@ -2012,9 +2054,9 @@ static int set_lock_args(int mode, struct dlm_lksb *lksb, uint32_t flags,
           an active lkb cannot be modified before locking the rsb */
 
        args->flags = flags;
-       args->astaddr = ast;
-       args->astparam = (long) astarg;
-       args->bastaddr = bast;
+       args->astfn = ast;
+       args->astparam = astparam;
+       args->bastfn = bast;
        args->timeout = timeout_cs;
        args->mode = mode;
        args->lksb = lksb;
@@ -2033,7 +2075,7 @@ static int set_unlock_args(uint32_t flags, void *astarg, struct dlm_args *args)
                return -EINVAL;
 
        args->flags = flags;
-       args->astparam = (long) astarg;
+       args->astparam = astarg;
        return 0;
 }
 
@@ -2063,9 +2105,9 @@ static int validate_lock_args(struct dlm_ls *ls, struct dlm_lkb *lkb,
 
        lkb->lkb_exflags = args->flags;
        lkb->lkb_sbflags = 0;
-       lkb->lkb_astaddr = args->astaddr;
+       lkb->lkb_astfn = args->astfn;
        lkb->lkb_astparam = args->astparam;
-       lkb->lkb_bastaddr = args->bastaddr;
+       lkb->lkb_bastfn = args->bastfn;
        lkb->lkb_rqmode = args->mode;
        lkb->lkb_lksb = args->lksb;
        lkb->lkb_lvbptr = args->lksb->sb_lvbptr;
@@ -2073,6 +2115,11 @@ static int validate_lock_args(struct dlm_ls *ls, struct dlm_lkb *lkb,
        lkb->lkb_timeout_cs = args->timeout;
        rv = 0;
  out:
+       if (rv)
+               log_debug(ls, "validate_lock_args %d %x %x %x %d %d %s",
+                         rv, lkb->lkb_id, lkb->lkb_flags, args->flags,
+                         lkb->lkb_status, lkb->lkb_wait_type,
+                         lkb->lkb_resource->res_name);
        return rv;
 }
 
@@ -2107,17 +2154,18 @@ static int validate_unlock_args(struct dlm_lkb *lkb, struct dlm_args *args)
        /* an lkb may be waiting for an rsb lookup to complete where the
           lookup was initiated by another lock */
 
-       if (args->flags & (DLM_LKF_CANCEL | DLM_LKF_FORCEUNLOCK)) {
-               if (!list_empty(&lkb->lkb_rsb_lookup)) {
+       if (!list_empty(&lkb->lkb_rsb_lookup)) {
+               if (args->flags & (DLM_LKF_CANCEL | DLM_LKF_FORCEUNLOCK)) {
                        log_debug(ls, "unlock on rsb_lookup %x", lkb->lkb_id);
                        list_del_init(&lkb->lkb_rsb_lookup);
                        queue_cast(lkb->lkb_resource, lkb,
                                   args->flags & DLM_LKF_CANCEL ?
                                   -DLM_ECANCEL : -DLM_EUNLOCK);
                        unhold_lkb(lkb); /* undoes create_lkb() */
-                       rv = -EBUSY;
-                       goto out;
                }
+               /* caller changes -EBUSY to 0 for CANCEL and FORCEUNLOCK */
+               rv = -EBUSY;
+               goto out;
        }
 
        /* cancel not allowed with another cancel/unlock in progress */
@@ -2138,6 +2186,13 @@ static int validate_unlock_args(struct dlm_lkb *lkb, struct dlm_args *args)
                        goto out;
                }
 
+               /* there's nothing to cancel */
+               if (lkb->lkb_status == DLM_LKSTS_GRANTED &&
+                   !lkb->lkb_wait_type) {
+                       rv = -EBUSY;
+                       goto out;
+               }
+
                switch (lkb->lkb_wait_type) {
                case DLM_MSG_LOOKUP:
                case DLM_MSG_REQUEST:
@@ -2225,20 +2280,30 @@ static int do_request(struct dlm_rsb *r, struct dlm_lkb *lkb)
        if (can_be_queued(lkb)) {
                error = -EINPROGRESS;
                add_lkb(r, lkb, DLM_LKSTS_WAITING);
-               send_blocking_asts(r, lkb);
                add_timeout(lkb);
                goto out;
        }
 
        error = -EAGAIN;
-       if (force_blocking_asts(lkb))
-               send_blocking_asts_all(r, lkb);
        queue_cast(r, lkb, -EAGAIN);
-
  out:
        return error;
 }
 
+static void do_request_effects(struct dlm_rsb *r, struct dlm_lkb *lkb,
+                              int error)
+{
+       switch (error) {
+       case -EAGAIN:
+               if (force_blocking_asts(lkb))
+                       send_blocking_asts_all(r, lkb);
+               break;
+       case -EINPROGRESS:
+               send_blocking_asts(r, lkb);
+               break;
+       }
+}
+
 static int do_convert(struct dlm_rsb *r, struct dlm_lkb *lkb)
 {
        int error = 0;
@@ -2249,7 +2314,6 @@ static int do_convert(struct dlm_rsb *r, struct dlm_lkb *lkb)
        if (can_be_granted(r, lkb, 1, &deadlk)) {
                grant_lock(r, lkb);
                queue_cast(r, lkb, 0);
-               grant_pending_locks(r);
                goto out;
        }
 
@@ -2279,7 +2343,6 @@ static int do_convert(struct dlm_rsb *r, struct dlm_lkb *lkb)
                if (_can_be_granted(r, lkb, 1)) {
                        grant_lock(r, lkb);
                        queue_cast(r, lkb, 0);
-                       grant_pending_locks(r);
                        goto out;
                }
                /* else fall through and move to convert queue */
@@ -2289,28 +2352,47 @@ static int do_convert(struct dlm_rsb *r, struct dlm_lkb *lkb)
                error = -EINPROGRESS;
                del_lkb(r, lkb);
                add_lkb(r, lkb, DLM_LKSTS_CONVERT);
-               send_blocking_asts(r, lkb);
                add_timeout(lkb);
                goto out;
        }
 
        error = -EAGAIN;
-       if (force_blocking_asts(lkb))
-               send_blocking_asts_all(r, lkb);
        queue_cast(r, lkb, -EAGAIN);
-
  out:
        return error;
 }
 
+static void do_convert_effects(struct dlm_rsb *r, struct dlm_lkb *lkb,
+                              int error)
+{
+       switch (error) {
+       case 0:
+               grant_pending_locks(r);
+               /* grant_pending_locks also sends basts */
+               break;
+       case -EAGAIN:
+               if (force_blocking_asts(lkb))
+                       send_blocking_asts_all(r, lkb);
+               break;
+       case -EINPROGRESS:
+               send_blocking_asts(r, lkb);
+               break;
+       }
+}
+
 static int do_unlock(struct dlm_rsb *r, struct dlm_lkb *lkb)
 {
        remove_lock(r, lkb);
        queue_cast(r, lkb, -DLM_EUNLOCK);
-       grant_pending_locks(r);
        return -DLM_EUNLOCK;
 }
 
+static void do_unlock_effects(struct dlm_rsb *r, struct dlm_lkb *lkb,
+                             int error)
+{
+       grant_pending_locks(r);
+}
+
 /* returns: 0 did nothing, -DLM_ECANCEL canceled lock */
  
 static int do_cancel(struct dlm_rsb *r, struct dlm_lkb *lkb)
@@ -2320,12 +2402,18 @@ static int do_cancel(struct dlm_rsb *r, struct dlm_lkb *lkb)
        error = revert_lock(r, lkb);
        if (error) {
                queue_cast(r, lkb, -DLM_ECANCEL);
-               grant_pending_locks(r);
                return -DLM_ECANCEL;
        }
        return 0;
 }
 
+static void do_cancel_effects(struct dlm_rsb *r, struct dlm_lkb *lkb,
+                             int error)
+{
+       if (error)
+               grant_pending_locks(r);
+}
+
 /*
  * Four stage 3 varieties:
  * _request_lock(), _convert_lock(), _unlock_lock(), _cancel_lock()
@@ -2347,11 +2435,15 @@ static int _request_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)
                goto out;
        }
 
-       if (is_remote(r))
+       if (is_remote(r)) {
                /* receive_request() calls do_request() on remote node */
                error = send_request(r, lkb);
-       else
+       } else {
                error = do_request(r, lkb);
+               /* for remote locks the request_reply is sent
+                  between do_request and do_request_effects */
+               do_request_effects(r, lkb, error);
+       }
  out:
        return error;
 }
@@ -2362,11 +2454,15 @@ static int _convert_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)
 {
        int error;
 
-       if (is_remote(r))
+       if (is_remote(r)) {
                /* receive_convert() calls do_convert() on remote node */
                error = send_convert(r, lkb);
-       else
+       } else {
                error = do_convert(r, lkb);
+               /* for remote locks the convert_reply is sent
+                  between do_convert and do_convert_effects */
+               do_convert_effects(r, lkb, error);
+       }
 
        return error;
 }
@@ -2377,11 +2473,15 @@ static int _unlock_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)
 {
        int error;
 
-       if (is_remote(r))
+       if (is_remote(r)) {
                /* receive_unlock() calls do_unlock() on remote node */
                error = send_unlock(r, lkb);
-       else
+       } else {
                error = do_unlock(r, lkb);
+               /* for remote locks the unlock_reply is sent
+                  between do_unlock and do_unlock_effects */
+               do_unlock_effects(r, lkb, error);
+       }
 
        return error;
 }
@@ -2392,11 +2492,15 @@ static int _cancel_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)
 {
        int error;
 
-       if (is_remote(r))
+       if (is_remote(r)) {
                /* receive_cancel() calls do_cancel() on remote node */
                error = send_cancel(r, lkb);
-       else
+       } else {
                error = do_cancel(r, lkb);
+               /* for remote locks the cancel_reply is sent
+                  between do_cancel and do_cancel_effects */
+               do_cancel_effects(r, lkb, error);
+       }
 
        return error;
 }
@@ -2634,7 +2738,7 @@ static int _create_message(struct dlm_ls *ls, int mb_len,
           pass into lowcomms_commit and a message buffer (mb) that we
           write our data into */
 
-       mh = dlm_lowcomms_get_buffer(to_nodeid, mb_len, ls->ls_allocation, &mb);
+       mh = dlm_lowcomms_get_buffer(to_nodeid, mb_len, GFP_NOFS, &mb);
        if (!mh)
                return -ENOBUFS;
 
@@ -2711,9 +2815,9 @@ static void send_args(struct dlm_rsb *r, struct dlm_lkb *lkb,
        /* m_result and m_bastmode are set from function args,
           not from lkb fields */
 
-       if (lkb->lkb_bastaddr)
+       if (lkb->lkb_bastfn)
                ms->m_asts |= AST_BAST;
-       if (lkb->lkb_astaddr)
+       if (lkb->lkb_astfn)
                ms->m_asts |= AST_COMP;
 
        /* compare with switch in create_message; send_remove() doesn't
@@ -2989,11 +3093,23 @@ static int receive_lvb(struct dlm_ls *ls, struct dlm_lkb *lkb,
                if (!lkb->lkb_lvbptr)
                        return -ENOMEM;
                len = receive_extralen(ms);
+               if (len > DLM_RESNAME_MAXLEN)
+                       len = DLM_RESNAME_MAXLEN;
                memcpy(lkb->lkb_lvbptr, ms->m_extra, len);
        }
        return 0;
 }
 
+static void fake_bastfn(void *astparam, int mode)
+{
+       log_print("fake_bastfn should not be called");
+}
+
+static void fake_astfn(void *astparam)
+{
+       log_print("fake_astfn should not be called");
+}
+
 static int receive_request_args(struct dlm_ls *ls, struct dlm_lkb *lkb,
                                struct dlm_message *ms)
 {
@@ -3002,10 +3118,9 @@ static int receive_request_args(struct dlm_ls *ls, struct dlm_lkb *lkb,
        lkb->lkb_remid = ms->m_lkid;
        lkb->lkb_grmode = DLM_LOCK_IV;
        lkb->lkb_rqmode = ms->m_rqmode;
-       lkb->lkb_bastaddr = (void *) (long) (ms->m_asts & AST_BAST);
-       lkb->lkb_astaddr = (void *) (long) (ms->m_asts & AST_COMP);
 
-       DLM_ASSERT(is_master_copy(lkb), dlm_print_lkb(lkb););
+       lkb->lkb_bastfn = (ms->m_asts & AST_BAST) ? &fake_bastfn : NULL;
+       lkb->lkb_astfn = (ms->m_asts & AST_COMP) ? &fake_astfn : NULL;
 
        if (lkb->lkb_exflags & DLM_LKF_VALBLK) {
                /* lkb was just created so there won't be an lvb yet */
@@ -3020,16 +3135,6 @@ static int receive_request_args(struct dlm_ls *ls, struct dlm_lkb *lkb,
 static int receive_convert_args(struct dlm_ls *ls, struct dlm_lkb *lkb,
                                struct dlm_message *ms)
 {
-       if (lkb->lkb_nodeid != ms->m_header.h_nodeid) {
-               log_error(ls, "convert_args nodeid %d %d lkid %x %x",
-                         lkb->lkb_nodeid, ms->m_header.h_nodeid,
-                         lkb->lkb_id, lkb->lkb_remid);
-               return -EINVAL;
-       }
-
-       if (!is_master_copy(lkb))
-               return -EINVAL;
-
        if (lkb->lkb_status != DLM_LKSTS_GRANTED)
                return -EBUSY;
 
@@ -3045,8 +3150,6 @@ static int receive_convert_args(struct dlm_ls *ls, struct dlm_lkb *lkb,
 static int receive_unlock_args(struct dlm_ls *ls, struct dlm_lkb *lkb,
                               struct dlm_message *ms)
 {
-       if (!is_master_copy(lkb))
-               return -EINVAL;
        if (receive_lvb(ls, lkb, ms))
                return -ENOMEM;
        return 0;
@@ -3062,6 +3165,50 @@ static void setup_stub_lkb(struct dlm_ls *ls, struct dlm_message *ms)
        lkb->lkb_remid = ms->m_lkid;
 }
 
+/* This is called after the rsb is locked so that we can safely inspect
+   fields in the lkb. */
+
+static int validate_message(struct dlm_lkb *lkb, struct dlm_message *ms)
+{
+       int from = ms->m_header.h_nodeid;
+       int error = 0;
+
+       switch (ms->m_type) {
+       case DLM_MSG_CONVERT:
+       case DLM_MSG_UNLOCK:
+       case DLM_MSG_CANCEL:
+               if (!is_master_copy(lkb) || lkb->lkb_nodeid != from)
+                       error = -EINVAL;
+               break;
+
+       case DLM_MSG_CONVERT_REPLY:
+       case DLM_MSG_UNLOCK_REPLY:
+       case DLM_MSG_CANCEL_REPLY:
+       case DLM_MSG_GRANT:
+       case DLM_MSG_BAST:
+               if (!is_process_copy(lkb) || lkb->lkb_nodeid != from)
+                       error = -EINVAL;
+               break;
+
+       case DLM_MSG_REQUEST_REPLY:
+               if (!is_process_copy(lkb))
+                       error = -EINVAL;
+               else if (lkb->lkb_nodeid != -1 && lkb->lkb_nodeid != from)
+                       error = -EINVAL;
+               break;
+
+       default:
+               error = -EINVAL;
+       }
+
+       if (error)
+               log_error(lkb->lkb_resource->res_ls,
+                         "ignore invalid message %d from %d %x %x %x %d",
+                         ms->m_type, from, lkb->lkb_id, lkb->lkb_remid,
+                         lkb->lkb_flags, lkb->lkb_nodeid);
+       return error;
+}
+
 static void receive_request(struct dlm_ls *ls, struct dlm_message *ms)
 {
        struct dlm_lkb *lkb;
@@ -3093,6 +3240,7 @@ static void receive_request(struct dlm_ls *ls, struct dlm_message *ms)
        attach_lkb(r, lkb);
        error = do_request(r, lkb);
        send_request_reply(r, lkb, error);
+       do_request_effects(r, lkb, error);
 
        unlock_rsb(r);
        put_rsb(r);
@@ -3123,17 +3271,25 @@ static void receive_convert(struct dlm_ls *ls, struct dlm_message *ms)
        hold_rsb(r);
        lock_rsb(r);
 
+       error = validate_message(lkb, ms);
+       if (error)
+               goto out;
+
        receive_flags(lkb, ms);
+
        error = receive_convert_args(ls, lkb, ms);
-       if (error)
+       if (error) {
+               send_convert_reply(r, lkb, error);
                goto out;
+       }
+
        reply = !down_conversion(lkb);
 
        error = do_convert(r, lkb);
- out:
        if (reply)
                send_convert_reply(r, lkb, error);
-
+       do_convert_effects(r, lkb, error);
+ out:
        unlock_rsb(r);
        put_rsb(r);
        dlm_put_lkb(lkb);
@@ -3159,15 +3315,22 @@ static void receive_unlock(struct dlm_ls *ls, struct dlm_message *ms)
        hold_rsb(r);
        lock_rsb(r);
 
+       error = validate_message(lkb, ms);
+       if (error)
+               goto out;
+
        receive_flags(lkb, ms);
+
        error = receive_unlock_args(ls, lkb, ms);
-       if (error)
+       if (error) {
+               send_unlock_reply(r, lkb, error);
                goto out;
+       }
 
        error = do_unlock(r, lkb);
- out:
        send_unlock_reply(r, lkb, error);
-
+       do_unlock_effects(r, lkb, error);
+ out:
        unlock_rsb(r);
        put_rsb(r);
        dlm_put_lkb(lkb);
@@ -3195,9 +3358,14 @@ static void receive_cancel(struct dlm_ls *ls, struct dlm_message *ms)
        hold_rsb(r);
        lock_rsb(r);
 
+       error = validate_message(lkb, ms);
+       if (error)
+               goto out;
+
        error = do_cancel(r, lkb);
        send_cancel_reply(r, lkb, error);
-
+       do_cancel_effects(r, lkb, error);
+ out:
        unlock_rsb(r);
        put_rsb(r);
        dlm_put_lkb(lkb);
@@ -3216,22 +3384,26 @@ static void receive_grant(struct dlm_ls *ls, struct dlm_message *ms)
 
        error = find_lkb(ls, ms->m_remid, &lkb);
        if (error) {
-               log_error(ls, "receive_grant no lkb");
+               log_debug(ls, "receive_grant from %d no lkb %x",
+                         ms->m_header.h_nodeid, ms->m_remid);
                return;
        }
-       DLM_ASSERT(is_process_copy(lkb), dlm_print_lkb(lkb););
 
        r = lkb->lkb_resource;
 
        hold_rsb(r);
        lock_rsb(r);
 
+       error = validate_message(lkb, ms);
+       if (error)
+               goto out;
+
        receive_flags_reply(lkb, ms);
        if (is_altmode(lkb))
                munge_altmode(lkb, ms);
        grant_lock_pc(r, lkb, ms);
        queue_cast(r, lkb, 0);
-
+ out:
        unlock_rsb(r);
        put_rsb(r);
        dlm_put_lkb(lkb);
@@ -3245,18 +3417,22 @@ static void receive_bast(struct dlm_ls *ls, struct dlm_message *ms)
 
        error = find_lkb(ls, ms->m_remid, &lkb);
        if (error) {
-               log_error(ls, "receive_bast no lkb");
+               log_debug(ls, "receive_bast from %d no lkb %x",
+                         ms->m_header.h_nodeid, ms->m_remid);
                return;
        }
-       DLM_ASSERT(is_process_copy(lkb), dlm_print_lkb(lkb););
 
        r = lkb->lkb_resource;
 
        hold_rsb(r);
        lock_rsb(r);
 
-       queue_bast(r, lkb, ms->m_bastmode);
+       error = validate_message(lkb, ms);
+       if (error)
+               goto out;
 
+       queue_bast(r, lkb, ms->m_bastmode);
+ out:
        unlock_rsb(r);
        put_rsb(r);
        dlm_put_lkb(lkb);
@@ -3322,15 +3498,19 @@ static void receive_request_reply(struct dlm_ls *ls, struct dlm_message *ms)
 
        error = find_lkb(ls, ms->m_remid, &lkb);
        if (error) {
-               log_error(ls, "receive_request_reply no lkb");
+               log_debug(ls, "receive_request_reply from %d no lkb %x",
+                         ms->m_header.h_nodeid, ms->m_remid);
                return;
        }
-       DLM_ASSERT(is_process_copy(lkb), dlm_print_lkb(lkb););
 
        r = lkb->lkb_resource;
        hold_rsb(r);
        lock_rsb(r);
 
+       error = validate_message(lkb, ms);
+       if (error)
+               goto out;
+
        mstype = lkb->lkb_wait_type;
        error = remove_from_waiters(lkb, DLM_MSG_REQUEST_REPLY);
        if (error)
@@ -3382,6 +3562,7 @@ static void receive_request_reply(struct dlm_ls *ls, struct dlm_message *ms)
                if (is_overlap(lkb)) {
                        /* we'll ignore error in cancel/unlock reply */
                        queue_cast_overlap(r, lkb);
+                       confirm_master(r, result);
                        unhold_lkb(lkb); /* undoes create_lkb() */
                } else
                        _request_lock(r, lkb);
@@ -3462,6 +3643,10 @@ static void _receive_convert_reply(struct dlm_lkb *lkb, struct dlm_message *ms)
        hold_rsb(r);
        lock_rsb(r);
 
+       error = validate_message(lkb, ms);
+       if (error)
+               goto out;
+
        /* stub reply can happen with waiters_mutex held */
        error = remove_from_waiters_ms(lkb, ms);
        if (error)
@@ -3480,10 +3665,10 @@ static void receive_convert_reply(struct dlm_ls *ls, struct dlm_message *ms)
 
        error = find_lkb(ls, ms->m_remid, &lkb);
        if (error) {
-               log_error(ls, "receive_convert_reply no lkb");
+               log_debug(ls, "receive_convert_reply from %d no lkb %x",
+                         ms->m_header.h_nodeid, ms->m_remid);
                return;
        }
-       DLM_ASSERT(is_process_copy(lkb), dlm_print_lkb(lkb););
 
        _receive_convert_reply(lkb, ms);
        dlm_put_lkb(lkb);
@@ -3497,6 +3682,10 @@ static void _receive_unlock_reply(struct dlm_lkb *lkb, struct dlm_message *ms)
        hold_rsb(r);
        lock_rsb(r);
 
+       error = validate_message(lkb, ms);
+       if (error)
+               goto out;
+
        /* stub reply can happen with waiters_mutex held */
        error = remove_from_waiters_ms(lkb, ms);
        if (error)
@@ -3528,10 +3717,10 @@ static void receive_unlock_reply(struct dlm_ls *ls, struct dlm_message *ms)
 
        error = find_lkb(ls, ms->m_remid, &lkb);
        if (error) {
-               log_error(ls, "receive_unlock_reply no lkb");
+               log_debug(ls, "receive_unlock_reply from %d no lkb %x",
+                         ms->m_header.h_nodeid, ms->m_remid);
                return;
        }
-       DLM_ASSERT(is_process_copy(lkb), dlm_print_lkb(lkb););
 
        _receive_unlock_reply(lkb, ms);
        dlm_put_lkb(lkb);
@@ -3545,6 +3734,10 @@ static void _receive_cancel_reply(struct dlm_lkb *lkb, struct dlm_message *ms)
        hold_rsb(r);
        lock_rsb(r);
 
+       error = validate_message(lkb, ms);
+       if (error)
+               goto out;
+
        /* stub reply can happen with waiters_mutex held */
        error = remove_from_waiters_ms(lkb, ms);
        if (error)
@@ -3576,10 +3769,10 @@ static void receive_cancel_reply(struct dlm_ls *ls, struct dlm_message *ms)
 
        error = find_lkb(ls, ms->m_remid, &lkb);
        if (error) {
-               log_error(ls, "receive_cancel_reply no lkb");
+               log_debug(ls, "receive_cancel_reply from %d no lkb %x",
+                         ms->m_header.h_nodeid, ms->m_remid);
                return;
        }
-       DLM_ASSERT(is_process_copy(lkb), dlm_print_lkb(lkb););
 
        _receive_cancel_reply(lkb, ms);
        dlm_put_lkb(lkb);
@@ -3639,6 +3832,13 @@ static void receive_lookup_reply(struct dlm_ls *ls, struct dlm_message *ms)
 
 static void _receive_message(struct dlm_ls *ls, struct dlm_message *ms)
 {
+       if (!dlm_is_member(ls, ms->m_header.h_nodeid)) {
+               log_debug(ls, "ignore non-member message %d from %d %x %x %d",
+                         ms->m_type, ms->m_header.h_nodeid, ms->m_lkid,
+                         ms->m_remid, ms->m_result);
+               return;
+       }
+
        switch (ms->m_type) {
 
        /* messages sent to a master node */
@@ -3728,7 +3928,7 @@ static void dlm_receive_message(struct dlm_ls *ls, struct dlm_message *ms,
                                int nodeid)
 {
        if (dlm_locking_stopped(ls)) {
-               dlm_add_requestqueue(ls, nodeid, (struct dlm_header *) ms);
+               dlm_add_requestqueue(ls, nodeid, ms);
        } else {
                dlm_wait_requestqueue(ls);
                _receive_message(ls, ms);
@@ -3748,21 +3948,20 @@ void dlm_receive_message_saved(struct dlm_ls *ls, struct dlm_message *ms)
    standard locking activity) or an RCOM (recovery message sent as part of
    lockspace recovery). */
 
-void dlm_receive_buffer(struct dlm_header *hd, int nodeid)
+void dlm_receive_buffer(union dlm_packet *p, int nodeid)
 {
-       struct dlm_message *ms = (struct dlm_message *) hd;
-       struct dlm_rcom *rc = (struct dlm_rcom *) hd;
+       struct dlm_header *hd = &p->header;
        struct dlm_ls *ls;
        int type = 0;
 
        switch (hd->h_cmd) {
        case DLM_MSG:
-               dlm_message_in(ms);
-               type = ms->m_type;
+               dlm_message_in(&p->message);
+               type = p->message.m_type;
                break;
        case DLM_RCOM:
-               dlm_rcom_in(rc);
-               type = rc->rc_type;
+               dlm_rcom_in(&p->rcom);
+               type = p->rcom.rc_type;
                break;
        default:
                log_print("invalid h_cmd %d from %u", hd->h_cmd, nodeid);
@@ -3777,11 +3976,12 @@ void dlm_receive_buffer(struct dlm_header *hd, int nodeid)
 
        ls = dlm_find_lockspace_global(hd->h_lockspace);
        if (!ls) {
-               log_print("invalid h_lockspace %x from %d cmd %d type %d",
-                         hd->h_lockspace, nodeid, hd->h_cmd, type);
+               if (dlm_config.ci_log_debug)
+                       log_print("invalid lockspace %x from %d cmd %d type %d",
+                                 hd->h_lockspace, nodeid, hd->h_cmd, type);
 
                if (hd->h_cmd == DLM_RCOM && type == DLM_RCOM_STATUS)
-                       dlm_send_ls_not_ready(nodeid, rc);
+                       dlm_send_ls_not_ready(nodeid, &p->rcom);
                return;
        }
 
@@ -3790,9 +3990,9 @@ void dlm_receive_buffer(struct dlm_header *hd, int nodeid)
 
        down_read(&ls->ls_recv_active);
        if (hd->h_cmd == DLM_MSG)
-               dlm_receive_message(ls, ms, nodeid);
+               dlm_receive_message(ls, &p->message, nodeid);
        else
-               dlm_receive_rcom(ls, rc, nodeid);
+               dlm_receive_rcom(ls, &p->rcom, nodeid);
        up_read(&ls->ls_recv_active);
 
        dlm_put_lockspace(ls);
@@ -3805,6 +4005,7 @@ static void recover_convert_waiter(struct dlm_ls *ls, struct dlm_lkb *lkb)
                ls->ls_stub_ms.m_type = DLM_MSG_CONVERT_REPLY;
                ls->ls_stub_ms.m_result = -EINPROGRESS;
                ls->ls_stub_ms.m_flags = lkb->lkb_flags;
+               ls->ls_stub_ms.m_header.h_nodeid = lkb->lkb_nodeid;
                _receive_convert_reply(lkb, &ls->ls_stub_ms);
 
                /* Same special case as in receive_rcom_lock_args() */
@@ -3846,6 +4047,7 @@ static int waiter_needs_recovery(struct dlm_ls *ls, struct dlm_lkb *lkb)
 void dlm_recover_waiters_pre(struct dlm_ls *ls)
 {
        struct dlm_lkb *lkb, *safe;
+       int wait_type, stub_unlock_result, stub_cancel_result;
 
        mutex_lock(&ls->ls_waiters_mutex);
 
@@ -3864,7 +4066,33 @@ void dlm_recover_waiters_pre(struct dlm_ls *ls)
                if (!waiter_needs_recovery(ls, lkb))
                        continue;
 
-               switch (lkb->lkb_wait_type) {
+               wait_type = lkb->lkb_wait_type;
+               stub_unlock_result = -DLM_EUNLOCK;
+               stub_cancel_result = -DLM_ECANCEL;
+
+               /* Main reply may have been received leaving a zero wait_type,
+                  but a reply for the overlapping op may not have been
+                  received.  In that case we need to fake the appropriate
+                  reply for the overlap op. */
+
+               if (!wait_type) {
+                       if (is_overlap_cancel(lkb)) {
+                               wait_type = DLM_MSG_CANCEL;
+                               if (lkb->lkb_grmode == DLM_LOCK_IV)
+                                       stub_cancel_result = 0;
+                       }
+                       if (is_overlap_unlock(lkb)) {
+                               wait_type = DLM_MSG_UNLOCK;
+                               if (lkb->lkb_grmode == DLM_LOCK_IV)
+                                       stub_unlock_result = -ENOENT;
+                       }
+
+                       log_debug(ls, "rwpre overlap %x %x %d %d %d",
+                                 lkb->lkb_id, lkb->lkb_flags, wait_type,
+                                 stub_cancel_result, stub_unlock_result);
+               }
+
+               switch (wait_type) {
 
                case DLM_MSG_REQUEST:
                        lkb->lkb_flags |= DLM_IFL_RESEND;
@@ -3877,8 +4105,9 @@ void dlm_recover_waiters_pre(struct dlm_ls *ls)
                case DLM_MSG_UNLOCK:
                        hold_lkb(lkb);
                        ls->ls_stub_ms.m_type = DLM_MSG_UNLOCK_REPLY;
-                       ls->ls_stub_ms.m_result = -DLM_EUNLOCK;
+                       ls->ls_stub_ms.m_result = stub_unlock_result;
                        ls->ls_stub_ms.m_flags = lkb->lkb_flags;
+                       ls->ls_stub_ms.m_header.h_nodeid = lkb->lkb_nodeid;
                        _receive_unlock_reply(lkb, &ls->ls_stub_ms);
                        dlm_put_lkb(lkb);
                        break;
@@ -3886,15 +4115,16 @@ void dlm_recover_waiters_pre(struct dlm_ls *ls)
                case DLM_MSG_CANCEL:
                        hold_lkb(lkb);
                        ls->ls_stub_ms.m_type = DLM_MSG_CANCEL_REPLY;
-                       ls->ls_stub_ms.m_result = -DLM_ECANCEL;
+                       ls->ls_stub_ms.m_result = stub_cancel_result;
                        ls->ls_stub_ms.m_flags = lkb->lkb_flags;
+                       ls->ls_stub_ms.m_header.h_nodeid = lkb->lkb_nodeid;
                        _receive_cancel_reply(lkb, &ls->ls_stub_ms);
                        dlm_put_lkb(lkb);
                        break;
 
                default:
-                       log_error(ls, "invalid lkb wait_type %d",
-                                 lkb->lkb_wait_type);
+                       log_error(ls, "invalid lkb wait_type %d %d",
+                                 lkb->lkb_wait_type, wait_type);
                }
                schedule();
        }
@@ -4096,7 +4326,7 @@ static struct dlm_rsb *find_purged_rsb(struct dlm_ls *ls, int bucket)
 {
        struct dlm_rsb *r, *r_ret = NULL;
 
-       read_lock(&ls->ls_rsbtbl[bucket].lock);
+       spin_lock(&ls->ls_rsbtbl[bucket].lock);
        list_for_each_entry(r, &ls->ls_rsbtbl[bucket].list, res_hashchain) {
                if (!rsb_flag(r, RSB_LOCKS_PURGED))
                        continue;
@@ -4105,7 +4335,7 @@ static struct dlm_rsb *find_purged_rsb(struct dlm_ls *ls, int bucket)
                r_ret = r;
                break;
        }
-       read_unlock(&ls->ls_rsbtbl[bucket].lock);
+       spin_unlock(&ls->ls_rsbtbl[bucket].lock);
        return r_ret;
 }
 
@@ -4162,32 +4392,34 @@ static struct dlm_lkb *search_remid(struct dlm_rsb *r, int nodeid,
        return NULL;
 }
 
+/* needs at least dlm_rcom + rcom_lock */
 static int receive_rcom_lock_args(struct dlm_ls *ls, struct dlm_lkb *lkb,
                                  struct dlm_rsb *r, struct dlm_rcom *rc)
 {
        struct rcom_lock *rl = (struct rcom_lock *) rc->rc_buf;
-       int lvblen;
 
        lkb->lkb_nodeid = rc->rc_header.h_nodeid;
-       lkb->lkb_ownpid = rl->rl_ownpid;
-       lkb->lkb_remid = rl->rl_lkid;
-       lkb->lkb_exflags = rl->rl_exflags;
-       lkb->lkb_flags = rl->rl_flags & 0x0000FFFF;
+       lkb->lkb_ownpid = le32_to_cpu(rl->rl_ownpid);
+       lkb->lkb_remid = le32_to_cpu(rl->rl_lkid);
+       lkb->lkb_exflags = le32_to_cpu(rl->rl_exflags);
+       lkb->lkb_flags = le32_to_cpu(rl->rl_flags) & 0x0000FFFF;
        lkb->lkb_flags |= DLM_IFL_MSTCPY;
-       lkb->lkb_lvbseq = rl->rl_lvbseq;
+       lkb->lkb_lvbseq = le32_to_cpu(rl->rl_lvbseq);
        lkb->lkb_rqmode = rl->rl_rqmode;
        lkb->lkb_grmode = rl->rl_grmode;
        /* don't set lkb_status because add_lkb wants to itself */
 
-       lkb->lkb_bastaddr = (void *) (long) (rl->rl_asts & AST_BAST);
-       lkb->lkb_astaddr = (void *) (long) (rl->rl_asts & AST_COMP);
+       lkb->lkb_bastfn = (rl->rl_asts & AST_BAST) ? &fake_bastfn : NULL;
+       lkb->lkb_astfn = (rl->rl_asts & AST_COMP) ? &fake_astfn : NULL;
 
        if (lkb->lkb_exflags & DLM_LKF_VALBLK) {
+               int lvblen = rc->rc_header.h_length - sizeof(struct dlm_rcom) -
+                        sizeof(struct rcom_lock);
+               if (lvblen > ls->ls_lvblen)
+                       return -EINVAL;
                lkb->lkb_lvbptr = dlm_allocate_lvb(ls);
                if (!lkb->lkb_lvbptr)
                        return -ENOMEM;
-               lvblen = rc->rc_header.h_length - sizeof(struct dlm_rcom) -
-                        sizeof(struct rcom_lock);
                memcpy(lkb->lkb_lvbptr, rl->rl_lvb, lvblen);
        }
 
@@ -4195,7 +4427,8 @@ static int receive_rcom_lock_args(struct dlm_ls *ls, struct dlm_lkb *lkb,
           The real granted mode of these converting locks cannot be determined
           until all locks have been rebuilt on the rsb (recover_conversion) */
 
-       if (rl->rl_wait_type == DLM_MSG_CONVERT && middle_conversion(lkb)) {
+       if (rl->rl_wait_type == cpu_to_le16(DLM_MSG_CONVERT) &&
+           middle_conversion(lkb)) {
                rl->rl_status = DLM_LKSTS_CONVERT;
                lkb->lkb_grmode = DLM_LOCK_IV;
                rsb_set_flag(r, RSB_RECOVER_CONVERT);
@@ -4210,6 +4443,7 @@ static int receive_rcom_lock_args(struct dlm_ls *ls, struct dlm_lkb *lkb,
    the given values and send back our lkid.  We send back our lkid by sending
    back the rcom_lock struct we got but with the remid field filled in. */
 
+/* needs at least dlm_rcom + rcom_lock */
 int dlm_recover_master_copy(struct dlm_ls *ls, struct dlm_rcom *rc)
 {
        struct rcom_lock *rl = (struct rcom_lock *) rc->rc_buf;
@@ -4222,13 +4456,14 @@ int dlm_recover_master_copy(struct dlm_ls *ls, struct dlm_rcom *rc)
                goto out;
        }
 
-       error = find_rsb(ls, rl->rl_name, rl->rl_namelen, R_MASTER, &r);
+       error = find_rsb(ls, rl->rl_name, le16_to_cpu(rl->rl_namelen),
+                        R_MASTER, &r);
        if (error)
                goto out;
 
        lock_rsb(r);
 
-       lkb = search_remid(r, rc->rc_header.h_nodeid, rl->rl_lkid);
+       lkb = search_remid(r, rc->rc_header.h_nodeid, le32_to_cpu(rl->rl_lkid));
        if (lkb) {
                error = -EEXIST;
                goto out_remid;
@@ -4251,18 +4486,20 @@ int dlm_recover_master_copy(struct dlm_ls *ls, struct dlm_rcom *rc)
  out_remid:
        /* this is the new value returned to the lock holder for
           saving in its process-copy lkb */
-       rl->rl_remid = lkb->lkb_id;
+       rl->rl_remid = cpu_to_le32(lkb->lkb_id);
 
  out_unlock:
        unlock_rsb(r);
        put_rsb(r);
  out:
        if (error)
-               log_debug(ls, "recover_master_copy %d %x", error, rl->rl_lkid);
-       rl->rl_result = error;
+               log_debug(ls, "recover_master_copy %d %x", error,
+                         le32_to_cpu(rl->rl_lkid));
+       rl->rl_result = cpu_to_le32(error);
        return error;
 }
 
+/* needs at least dlm_rcom + rcom_lock */
 int dlm_recover_process_copy(struct dlm_ls *ls, struct dlm_rcom *rc)
 {
        struct rcom_lock *rl = (struct rcom_lock *) rc->rc_buf;
@@ -4270,15 +4507,16 @@ int dlm_recover_process_copy(struct dlm_ls *ls, struct dlm_rcom *rc)
        struct dlm_lkb *lkb;
        int error;
 
-       error = find_lkb(ls, rl->rl_lkid, &lkb);
+       error = find_lkb(ls, le32_to_cpu(rl->rl_lkid), &lkb);
        if (error) {
-               log_error(ls, "recover_process_copy no lkid %x", rl->rl_lkid);
+               log_error(ls, "recover_process_copy no lkid %x",
+                               le32_to_cpu(rl->rl_lkid));
                return error;
        }
 
        DLM_ASSERT(is_process_copy(lkb), dlm_print_lkb(lkb););
 
-       error = rl->rl_result;
+       error = le32_to_cpu(rl->rl_result);
 
        r = lkb->lkb_resource;
        hold_rsb(r);
@@ -4297,7 +4535,7 @@ int dlm_recover_process_copy(struct dlm_ls *ls, struct dlm_rcom *rc)
                log_debug(ls, "master copy exists %x", lkb->lkb_id);
                /* fall through */
        case 0:
-               lkb->lkb_remid = rl->rl_remid;
+               lkb->lkb_remid = le32_to_cpu(rl->rl_remid);
                break;
        default:
                log_error(ls, "dlm_recover_process_copy unknown error %d %x",
@@ -4332,7 +4570,7 @@ int dlm_user_request(struct dlm_ls *ls, struct dlm_user_args *ua,
        }
 
        if (flags & DLM_LKF_VALBLK) {
-               ua->lksb.sb_lvbptr = kzalloc(DLM_USER_LVB_LEN, GFP_KERNEL);
+               ua->lksb.sb_lvbptr = kzalloc(DLM_USER_LVB_LEN, GFP_NOFS);
                if (!ua->lksb.sb_lvbptr) {
                        kfree(ua);
                        __put_lkb(ls, lkb);
@@ -4346,7 +4584,7 @@ int dlm_user_request(struct dlm_ls *ls, struct dlm_user_args *ua,
           lock and that lkb_astparam is the dlm_user_args structure. */
 
        error = set_lock_args(mode, &ua->lksb, flags, namelen, timeout_cs,
-                             DLM_FAKE_USER_AST, ua, DLM_FAKE_USER_AST, &args);
+                             fake_astfn, ua, fake_bastfn, &args);
        lkb->lkb_flags |= DLM_IFL_USER;
        ua->old_mode = DLM_LOCK_IV;
 
@@ -4399,10 +4637,10 @@ int dlm_user_convert(struct dlm_ls *ls, struct dlm_user_args *ua_tmp,
        /* user can change the params on its lock when it converts it, or
           add an lvb that didn't exist before */
 
-       ua = (struct dlm_user_args *)lkb->lkb_astparam;
+       ua = lkb->lkb_ua;
 
        if (flags & DLM_LKF_VALBLK && !ua->lksb.sb_lvbptr) {
-               ua->lksb.sb_lvbptr = kzalloc(DLM_USER_LVB_LEN, GFP_KERNEL);
+               ua->lksb.sb_lvbptr = kzalloc(DLM_USER_LVB_LEN, GFP_NOFS);
                if (!ua->lksb.sb_lvbptr) {
                        error = -ENOMEM;
                        goto out_put;
@@ -4420,7 +4658,7 @@ int dlm_user_convert(struct dlm_ls *ls, struct dlm_user_args *ua_tmp,
        ua->old_mode = lkb->lkb_grmode;
 
        error = set_lock_args(mode, &ua->lksb, flags, 0, timeout_cs,
-                             DLM_FAKE_USER_AST, ua, DLM_FAKE_USER_AST, &args);
+                             fake_astfn, ua, fake_bastfn, &args);
        if (error)
                goto out_put;
 
@@ -4450,7 +4688,7 @@ int dlm_user_unlock(struct dlm_ls *ls, struct dlm_user_args *ua_tmp,
        if (error)
                goto out;
 
-       ua = (struct dlm_user_args *)lkb->lkb_astparam;
+       ua = lkb->lkb_ua;
 
        if (lvb_in && ua->lksb.sb_lvbptr)
                memcpy(ua->lksb.sb_lvbptr, lvb_in, DLM_USER_LVB_LEN);
@@ -4499,7 +4737,7 @@ int dlm_user_cancel(struct dlm_ls *ls, struct dlm_user_args *ua_tmp,
        if (error)
                goto out;
 
-       ua = (struct dlm_user_args *)lkb->lkb_astparam;
+       ua = lkb->lkb_ua;
        if (ua_tmp->castparam)
                ua->castparam = ua_tmp->castparam;
        ua->user_lksb = ua_tmp->user_lksb;
@@ -4537,7 +4775,7 @@ int dlm_user_deadlock(struct dlm_ls *ls, uint32_t flags, uint32_t lkid)
        if (error)
                goto out;
 
-       ua = (struct dlm_user_args *)lkb->lkb_astparam;
+       ua = lkb->lkb_ua;
 
        error = set_unlock_args(flags, ua, &args);
        if (error)
@@ -4576,7 +4814,6 @@ int dlm_user_deadlock(struct dlm_ls *ls, uint32_t flags, uint32_t lkid)
 
 static int orphan_proc_lock(struct dlm_ls *ls, struct dlm_lkb *lkb)
 {
-       struct dlm_user_args *ua = (struct dlm_user_args *)lkb->lkb_astparam;
        struct dlm_args args;
        int error;
 
@@ -4585,7 +4822,7 @@ static int orphan_proc_lock(struct dlm_ls *ls, struct dlm_lkb *lkb)
        list_add_tail(&lkb->lkb_ownqueue, &ls->ls_orphans);
        mutex_unlock(&ls->ls_orphans_mutex);
 
-       set_unlock_args(0, ua, &args);
+       set_unlock_args(0, lkb->lkb_ua, &args);
 
        error = cancel_lock(ls, lkb, &args);
        if (error == -DLM_ECANCEL)
@@ -4598,11 +4835,10 @@ static int orphan_proc_lock(struct dlm_ls *ls, struct dlm_lkb *lkb)
 
 static int unlock_proc_lock(struct dlm_ls *ls, struct dlm_lkb *lkb)
 {
-       struct dlm_user_args *ua = (struct dlm_user_args *)lkb->lkb_astparam;
        struct dlm_args args;
        int error;
 
-       set_unlock_args(DLM_LKF_FORCEUNLOCK, ua, &args);
+       set_unlock_args(DLM_LKF_FORCEUNLOCK, lkb->lkb_ua, &args);
 
        error = unlock_lock(ls, lkb, &args);
        if (error == -DLM_EUNLOCK)