void __dlm_queue_ast(struct dlm_ctxt *dlm, struct dlm_lock *lock) { struct dlm_lock_resource *res; BUG_ON(!dlm); BUG_ON(!lock); res = lock->lockres; assert_spin_locked(&dlm->ast_lock); if (!list_empty(&lock->ast_list)) { mlog(ML_ERROR, "%s: res %.*s, lock %u:%llu, " "AST list not empty, pending %d, newlevel %d\n", dlm->name, res->lockname.len, res->lockname.name, dlm_get_lock_cookie_node(be64_to_cpu(lock->ml.cookie)), dlm_get_lock_cookie_seq(be64_to_cpu(lock->ml.cookie)), lock->ast_pending, lock->ml.type); BUG(); } if (lock->ast_pending) mlog(0, "%s: res %.*s, lock %u:%llu, AST getting flushed\n", dlm->name, res->lockname.len, res->lockname.name, dlm_get_lock_cookie_node(be64_to_cpu(lock->ml.cookie)), dlm_get_lock_cookie_seq(be64_to_cpu(lock->ml.cookie))); /* putting lock on list, add a ref */ dlm_lock_get(lock); spin_lock(&lock->spinlock); /* check to see if this ast obsoletes the bast */ if (dlm_should_cancel_bast(dlm, lock)) { mlog(0, "%s: res %.*s, lock %u:%llu, Cancelling BAST\n", dlm->name, res->lockname.len, res->lockname.name, dlm_get_lock_cookie_node(be64_to_cpu(lock->ml.cookie)), dlm_get_lock_cookie_seq(be64_to_cpu(lock->ml.cookie))); lock->bast_pending = 0; list_del_init(&lock->bast_list); lock->ml.highest_blocked = LKM_IVMODE; /* removing lock from list, remove a ref. guaranteed * this won't be the last ref because of the get above, * so res->spinlock will not be taken here */ dlm_lock_put(lock); /* free up the reserved bast that we are cancelling. * guaranteed that this will not be the last reserved * ast because *both* an ast and a bast were reserved * to get to this point. the res->spinlock will not be * taken here */ dlm_lockres_release_ast(dlm, res); } list_add_tail(&lock->ast_list, &dlm->pending_asts); lock->ast_pending = 1; spin_unlock(&lock->spinlock); }
void __dlm_queue_bast(struct dlm_ctxt *dlm, struct dlm_lock *lock) { struct dlm_lock_resource *res; BUG_ON(!dlm); BUG_ON(!lock); assert_spin_locked(&dlm->ast_lock); res = lock->lockres; BUG_ON(!list_empty(&lock->bast_list)); if (lock->bast_pending) mlog(0, "%s: res %.*s, lock %u:%llu, BAST getting flushed\n", dlm->name, res->lockname.len, res->lockname.name, dlm_get_lock_cookie_node(be64_to_cpu(lock->ml.cookie)), dlm_get_lock_cookie_seq(be64_to_cpu(lock->ml.cookie))); /* putting lock on list, add a ref */ dlm_lock_get(lock); spin_lock(&lock->spinlock); list_add_tail(&lock->bast_list, &dlm->pending_basts); lock->bast_pending = 1; spin_unlock(&lock->spinlock); }
void dlm_do_local_bast(struct dlm_ctxt *dlm, struct dlm_lock_resource *res, struct dlm_lock *lock, int blocked_type) { dlm_bastlockfunc_t *fn = lock->bast; BUG_ON(lock->ml.node != dlm->node_num); mlog(0, "%s: res %.*s, lock %u:%llu, Local BAST, blocked %d\n", dlm->name, res->lockname.len, res->lockname.name, dlm_get_lock_cookie_node(be64_to_cpu(lock->ml.cookie)), dlm_get_lock_cookie_seq(be64_to_cpu(lock->ml.cookie)), blocked_type); (*fn)(lock->astdata, blocked_type); }
void dlm_do_local_ast(struct dlm_ctxt *dlm, struct dlm_lock_resource *res, struct dlm_lock *lock) { dlm_astlockfunc_t *fn; struct dlm_lockstatus *lksb; mlog(0, "%s: res %.*s, lock %u:%llu, Local AST\n", dlm->name, res->lockname.len, res->lockname.name, dlm_get_lock_cookie_node(be64_to_cpu(lock->ml.cookie)), dlm_get_lock_cookie_seq(be64_to_cpu(lock->ml.cookie))); lksb = lock->lksb; fn = lock->ast; BUG_ON(lock->ml.node != dlm->node_num); dlm_update_lvb(dlm, res, lock); (*fn)(lock->astdata); }
int dlm_do_remote_ast(struct dlm_ctxt *dlm, struct dlm_lock_resource *res, struct dlm_lock *lock) { int ret; struct dlm_lockstatus *lksb; int lksbflags; mlog(0, "%s: res %.*s, lock %u:%llu, Remote AST\n", dlm->name, res->lockname.len, res->lockname.name, dlm_get_lock_cookie_node(be64_to_cpu(lock->ml.cookie)), dlm_get_lock_cookie_seq(be64_to_cpu(lock->ml.cookie))); lksb = lock->lksb; BUG_ON(lock->ml.node == dlm->node_num); lksbflags = lksb->flags; dlm_update_lvb(dlm, res, lock); /* lock request came from another node * go do the ast over there */ ret = dlm_send_proxy_ast(dlm, res, lock, lksbflags); return ret; }
int dlm_proxy_ast_handler(struct o2net_msg *msg, u32 len, void *data, void **ret_data) { int ret; unsigned int locklen; struct dlm_ctxt *dlm = data; struct dlm_lock_resource *res = NULL; struct dlm_lock *lock = NULL; struct dlm_proxy_ast *past = (struct dlm_proxy_ast *) msg->buf; char *name; struct list_head *iter, *head=NULL; u64 cookie; u32 flags; u8 node; if (!dlm_grab(dlm)) { dlm_error(DLM_REJECTED); return DLM_REJECTED; } mlog_bug_on_msg(!dlm_domain_fully_joined(dlm), "Domain %s not fully joined!\n", dlm->name); name = past->name; locklen = past->namelen; cookie = past->cookie; flags = be32_to_cpu(past->flags); node = past->node_idx; if (locklen > DLM_LOCKID_NAME_MAX) { ret = DLM_IVBUFLEN; mlog(ML_ERROR, "Invalid name length (%d) in proxy ast " "handler!\n", locklen); goto leave; } if ((flags & (LKM_PUT_LVB|LKM_GET_LVB)) == (LKM_PUT_LVB|LKM_GET_LVB)) { mlog(ML_ERROR, "Both PUT and GET lvb specified, (0x%x)\n", flags); ret = DLM_BADARGS; goto leave; } mlog(0, "lvb: %s\n", flags & LKM_PUT_LVB ? "put lvb" : (flags & LKM_GET_LVB ? "get lvb" : "none")); mlog(0, "type=%d, blocked_type=%d\n", past->type, past->blocked_type); if (past->type != DLM_AST && past->type != DLM_BAST) { mlog(ML_ERROR, "Unknown ast type! %d, cookie=%u:%llu" "name=%.*s, node=%u\n", past->type, dlm_get_lock_cookie_node(be64_to_cpu(cookie)), dlm_get_lock_cookie_seq(be64_to_cpu(cookie)), locklen, name, node); ret = DLM_IVLOCKID; goto leave; } res = dlm_lookup_lockres(dlm, name, locklen); if (!res) { mlog(0, "Got %sast for unknown lockres! cookie=%u:%llu, " "name=%.*s, node=%u\n", (past->type == DLM_AST ? "" : "b"), dlm_get_lock_cookie_node(be64_to_cpu(cookie)), dlm_get_lock_cookie_seq(be64_to_cpu(cookie)), locklen, name, node); ret = DLM_IVLOCKID; goto leave; } /* cannot get a proxy ast message if this node owns it */ BUG_ON(res->owner == dlm->node_num); mlog(0, "lockres %.*s\n", res->lockname.len, res->lockname.name); spin_lock(&res->spinlock); if (res->state & DLM_LOCK_RES_RECOVERING) { mlog(0, "Responding with DLM_RECOVERING!\n"); ret = DLM_RECOVERING; goto unlock_out; } if (res->state & DLM_LOCK_RES_MIGRATING) { mlog(0, "Responding with DLM_MIGRATING!\n"); ret = DLM_MIGRATING; goto unlock_out; } /* try convert queue for both ast/bast */ head = &res->converting; lock = NULL; list_for_each(iter, head) { lock = list_entry (iter, struct dlm_lock, list); if (lock->ml.cookie == cookie) goto do_ast; }
int dlm_proxy_ast_handler(struct o2net_msg *msg, u32 len, void *data, void **ret_data) { int ret; unsigned int locklen; struct dlm_ctxt *dlm = data; struct dlm_lock_resource *res = NULL; struct dlm_lock *lock = NULL; struct dlm_proxy_ast *past = (struct dlm_proxy_ast *) msg->buf; char *name; struct list_head *head = NULL; __be64 cookie; u32 flags; u8 node; if (!dlm_grab(dlm)) { dlm_error(DLM_REJECTED); return DLM_REJECTED; } mlog_bug_on_msg(!dlm_domain_fully_joined(dlm), "Domain %s not fully joined!\n", dlm->name); name = past->name; locklen = past->namelen; cookie = past->cookie; flags = be32_to_cpu(past->flags); node = past->node_idx; if (locklen > DLM_LOCKID_NAME_MAX) { ret = DLM_IVBUFLEN; mlog(ML_ERROR, "Invalid name length (%d) in proxy ast " "handler!\n", locklen); goto leave; } if ((flags & (LKM_PUT_LVB|LKM_GET_LVB)) == (LKM_PUT_LVB|LKM_GET_LVB)) { mlog(ML_ERROR, "Both PUT and GET lvb specified, (0x%x)\n", flags); ret = DLM_BADARGS; goto leave; } mlog(0, "lvb: %s\n", flags & LKM_PUT_LVB ? "put lvb" : (flags & LKM_GET_LVB ? "get lvb" : "none")); mlog(0, "type=%d, blocked_type=%d\n", past->type, past->blocked_type); if (past->type != DLM_AST && past->type != DLM_BAST) { mlog(ML_ERROR, "Unknown ast type! %d, cookie=%u:%llu" "name=%.*s, node=%u\n", past->type, dlm_get_lock_cookie_node(be64_to_cpu(cookie)), dlm_get_lock_cookie_seq(be64_to_cpu(cookie)), locklen, name, node); ret = DLM_IVLOCKID; goto leave; } res = dlm_lookup_lockres(dlm, name, locklen); if (!res) { mlog(0, "Got %sast for unknown lockres! cookie=%u:%llu, " "name=%.*s, node=%u\n", (past->type == DLM_AST ? "" : "b"), dlm_get_lock_cookie_node(be64_to_cpu(cookie)), dlm_get_lock_cookie_seq(be64_to_cpu(cookie)), locklen, name, node); ret = DLM_IVLOCKID; goto leave; } /* cannot get a proxy ast message if this node owns it */ BUG_ON(res->owner == dlm->node_num); mlog(0, "%s: res %.*s\n", dlm->name, res->lockname.len, res->lockname.name); spin_lock(&res->spinlock); if (res->state & DLM_LOCK_RES_RECOVERING) { mlog(0, "Responding with DLM_RECOVERING!\n"); ret = DLM_RECOVERING; goto unlock_out; } if (res->state & DLM_LOCK_RES_MIGRATING) { mlog(0, "Responding with DLM_MIGRATING!\n"); ret = DLM_MIGRATING; goto unlock_out; } /* try convert queue for both ast/bast */ head = &res->converting; lock = NULL; list_for_each_entry(lock, head, list) { if (lock->ml.cookie == cookie) goto do_ast; } /* if not on convert, try blocked for ast, granted for bast */ if (past->type == DLM_AST) head = &res->blocked; else head = &res->granted; list_for_each_entry(lock, head, list) { if (lock->ml.cookie == cookie) goto do_ast; } mlog(0, "Got %sast for unknown lock! cookie=%u:%llu, name=%.*s, " "node=%u\n", past->type == DLM_AST ? "" : "b", dlm_get_lock_cookie_node(be64_to_cpu(cookie)), dlm_get_lock_cookie_seq(be64_to_cpu(cookie)), locklen, name, node); ret = DLM_NORMAL; unlock_out: spin_unlock(&res->spinlock); goto leave; do_ast: ret = DLM_NORMAL; if (past->type == DLM_AST) { /* do not alter lock refcount. switching lists. */ list_move_tail(&lock->list, &res->granted); mlog(0, "%s: res %.*s, lock %u:%llu, Granted type %d => %d\n", dlm->name, res->lockname.len, res->lockname.name, dlm_get_lock_cookie_node(be64_to_cpu(cookie)), dlm_get_lock_cookie_seq(be64_to_cpu(cookie)), lock->ml.type, lock->ml.convert_type); if (lock->ml.convert_type != LKM_IVMODE) { lock->ml.type = lock->ml.convert_type; lock->ml.convert_type = LKM_IVMODE; } else { // should already be there.... } lock->lksb->status = DLM_NORMAL; /* if we requested the lvb, fetch it into our lksb now */ if (flags & LKM_GET_LVB) { BUG_ON(!(lock->lksb->flags & DLM_LKSB_GET_LVB)); memcpy(lock->lksb->lvb, past->lvb, DLM_LVB_LEN); } } spin_unlock(&res->spinlock); if (past->type == DLM_AST) dlm_do_local_ast(dlm, res, lock); else dlm_do_local_bast(dlm, res, lock, past->blocked_type); leave: if (res) dlm_lockres_put(res); dlm_put(dlm); return ret; }
/* * locking: * caller needs: none * taken: res->spinlock and lock->spinlock taken and dropped * held on exit: none * returns: DLM_NORMAL, DLM_NOLOCKMGR, status from network * all callers should have taken an extra ref on lock coming in */ static enum dlm_status dlmunlock_common(struct dlm_ctxt *dlm, struct dlm_lock_resource *res, struct dlm_lock *lock, struct dlm_lockstatus *lksb, int flags, int *call_ast, int master_node) { enum dlm_status status; int actions = 0; int in_use; u8 owner; mlog(0, "master_node = %d, valblk = %d\n", master_node, flags & LKM_VALBLK); if (master_node) BUG_ON(res->owner != dlm->node_num); else BUG_ON(res->owner == dlm->node_num); spin_lock(&dlm->ast_lock); /* We want to be sure that we're not freeing a lock * that still has AST's pending... */ in_use = !list_empty(&lock->ast_list); spin_unlock(&dlm->ast_lock); if (in_use) { mlog(ML_ERROR, "lockres %.*s: Someone is calling dlmunlock " "while waiting for an ast!", res->lockname.len, res->lockname.name); return DLM_BADPARAM; } spin_lock(&res->spinlock); if (res->state & DLM_LOCK_RES_IN_PROGRESS) { if (master_node) { mlog(ML_ERROR, "lockres in progress!\n"); spin_unlock(&res->spinlock); return DLM_FORWARD; } /* ok for this to sleep if not in a network handler */ __dlm_wait_on_lockres(res); res->state |= DLM_LOCK_RES_IN_PROGRESS; } spin_lock(&lock->spinlock); if (res->state & DLM_LOCK_RES_RECOVERING) { status = DLM_RECOVERING; goto leave; } if (res->state & DLM_LOCK_RES_MIGRATING) { status = DLM_MIGRATING; goto leave; } /* see above for what the spec says about * LKM_CANCEL and the lock queue state */ if (flags & LKM_CANCEL) status = dlm_get_cancel_actions(dlm, res, lock, lksb, &actions); else status = dlm_get_unlock_actions(dlm, res, lock, lksb, &actions); if (status != DLM_NORMAL && (status != DLM_CANCELGRANT || !master_node)) goto leave; /* By now this has been masked out of cancel requests. */ if (flags & LKM_VALBLK) { /* make the final update to the lvb */ if (master_node) memcpy(res->lvb, lksb->lvb, DLM_LVB_LEN); else flags |= LKM_PUT_LVB; /* let the send function * handle it. */ } if (!master_node) { owner = res->owner; /* drop locks and send message */ if (flags & LKM_CANCEL) lock->cancel_pending = 1; else lock->unlock_pending = 1; spin_unlock(&lock->spinlock); spin_unlock(&res->spinlock); status = dlm_send_remote_unlock_request(dlm, res, lock, lksb, flags, owner); spin_lock(&res->spinlock); spin_lock(&lock->spinlock); /* if the master told us the lock was already granted, * let the ast handle all of these actions */ if (status == DLM_CANCELGRANT) { actions &= ~(DLM_UNLOCK_REMOVE_LOCK| DLM_UNLOCK_REGRANT_LOCK| DLM_UNLOCK_CLEAR_CONVERT_TYPE); } else if (status == DLM_RECOVERING || status == DLM_MIGRATING || status == DLM_FORWARD) { /* must clear the actions because this unlock * is about to be retried. cannot free or do * any list manipulation. */ mlog(0, "%s:%.*s: clearing actions, %s\n", dlm->name, res->lockname.len, res->lockname.name, status==DLM_RECOVERING?"recovering": (status==DLM_MIGRATING?"migrating": "forward")); actions = 0; } if (flags & LKM_CANCEL) lock->cancel_pending = 0; else lock->unlock_pending = 0; } /* get an extra ref on lock. if we are just switching * lists here, we dont want the lock to go away. */ dlm_lock_get(lock); if (actions & DLM_UNLOCK_REMOVE_LOCK) { list_del_init(&lock->list); dlm_lock_put(lock); } if (actions & DLM_UNLOCK_REGRANT_LOCK) { dlm_lock_get(lock); list_add_tail(&lock->list, &res->granted); } if (actions & DLM_UNLOCK_CLEAR_CONVERT_TYPE) { mlog(0, "clearing convert_type at %smaster node\n", master_node ? "" : "non-"); lock->ml.convert_type = LKM_IVMODE; } /* remove the extra ref on lock */ dlm_lock_put(lock); leave: res->state &= ~DLM_LOCK_RES_IN_PROGRESS; if (!dlm_lock_on_list(&res->converting, lock)) BUG_ON(lock->ml.convert_type != LKM_IVMODE); else BUG_ON(lock->ml.convert_type == LKM_IVMODE); spin_unlock(&lock->spinlock); spin_unlock(&res->spinlock); wake_up(&res->wq); /* let the caller's final dlm_lock_put handle the actual kfree */ if (actions & DLM_UNLOCK_FREE_LOCK) { /* this should always be coupled with list removal */ BUG_ON(!(actions & DLM_UNLOCK_REMOVE_LOCK)); mlog(0, "lock %u:%llu should be gone now! refs=%d\n", dlm_get_lock_cookie_node(be64_to_cpu(lock->ml.cookie)), dlm_get_lock_cookie_seq(be64_to_cpu(lock->ml.cookie)), atomic_read(&lock->lock_refs.refcount)-1); dlm_lock_put(lock); } if (actions & DLM_UNLOCK_CALL_AST) *call_ast = 1; /* if cancel or unlock succeeded, lvb work is done */ if (status == DLM_NORMAL) lksb->flags &= ~(DLM_LKSB_PUT_LVB|DLM_LKSB_GET_LVB); return status; }