162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/******************************************************************************
362306a36Sopenharmony_ci*******************************************************************************
462306a36Sopenharmony_ci**
562306a36Sopenharmony_ci**  Copyright (C) 2005-2010 Red Hat, Inc.  All rights reserved.
662306a36Sopenharmony_ci**
762306a36Sopenharmony_ci**
862306a36Sopenharmony_ci*******************************************************************************
962306a36Sopenharmony_ci******************************************************************************/
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci/* Central locking logic has four stages:
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci   dlm_lock()
1462306a36Sopenharmony_ci   dlm_unlock()
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci   request_lock(ls, lkb)
1762306a36Sopenharmony_ci   convert_lock(ls, lkb)
1862306a36Sopenharmony_ci   unlock_lock(ls, lkb)
1962306a36Sopenharmony_ci   cancel_lock(ls, lkb)
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci   _request_lock(r, lkb)
2262306a36Sopenharmony_ci   _convert_lock(r, lkb)
2362306a36Sopenharmony_ci   _unlock_lock(r, lkb)
2462306a36Sopenharmony_ci   _cancel_lock(r, lkb)
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci   do_request(r, lkb)
2762306a36Sopenharmony_ci   do_convert(r, lkb)
2862306a36Sopenharmony_ci   do_unlock(r, lkb)
2962306a36Sopenharmony_ci   do_cancel(r, lkb)
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci   Stage 1 (lock, unlock) is mainly about checking input args and
3262306a36Sopenharmony_ci   splitting into one of the four main operations:
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci       dlm_lock          = request_lock
3562306a36Sopenharmony_ci       dlm_lock+CONVERT  = convert_lock
3662306a36Sopenharmony_ci       dlm_unlock        = unlock_lock
3762306a36Sopenharmony_ci       dlm_unlock+CANCEL = cancel_lock
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci   Stage 2, xxxx_lock(), just finds and locks the relevant rsb which is
4062306a36Sopenharmony_ci   provided to the next stage.
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci   Stage 3, _xxxx_lock(), determines if the operation is local or remote.
4362306a36Sopenharmony_ci   When remote, it calls send_xxxx(), when local it calls do_xxxx().
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci   Stage 4, do_xxxx(), is the guts of the operation.  It manipulates the
4662306a36Sopenharmony_ci   given rsb and lkb and queues callbacks.
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci   For remote operations, send_xxxx() results in the corresponding do_xxxx()
4962306a36Sopenharmony_ci   function being executed on the remote node.  The connecting send/receive
5062306a36Sopenharmony_ci   calls on local (L) and remote (R) nodes:
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci   L: send_xxxx()              ->  R: receive_xxxx()
5362306a36Sopenharmony_ci                                   R: do_xxxx()
5462306a36Sopenharmony_ci   L: receive_xxxx_reply()     <-  R: send_xxxx_reply()
5562306a36Sopenharmony_ci*/
5662306a36Sopenharmony_ci#include <trace/events/dlm.h>
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci#include <linux/types.h>
5962306a36Sopenharmony_ci#include <linux/rbtree.h>
6062306a36Sopenharmony_ci#include <linux/slab.h>
6162306a36Sopenharmony_ci#include "dlm_internal.h"
6262306a36Sopenharmony_ci#include <linux/dlm_device.h>
6362306a36Sopenharmony_ci#include "memory.h"
6462306a36Sopenharmony_ci#include "midcomms.h"
6562306a36Sopenharmony_ci#include "requestqueue.h"
6662306a36Sopenharmony_ci#include "util.h"
6762306a36Sopenharmony_ci#include "dir.h"
6862306a36Sopenharmony_ci#include "member.h"
6962306a36Sopenharmony_ci#include "lockspace.h"
7062306a36Sopenharmony_ci#include "ast.h"
7162306a36Sopenharmony_ci#include "lock.h"
7262306a36Sopenharmony_ci#include "rcom.h"
7362306a36Sopenharmony_ci#include "recover.h"
7462306a36Sopenharmony_ci#include "lvb_table.h"
7562306a36Sopenharmony_ci#include "user.h"
7662306a36Sopenharmony_ci#include "config.h"
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_cistatic int send_request(struct dlm_rsb *r, struct dlm_lkb *lkb);
7962306a36Sopenharmony_cistatic int send_convert(struct dlm_rsb *r, struct dlm_lkb *lkb);
8062306a36Sopenharmony_cistatic int send_unlock(struct dlm_rsb *r, struct dlm_lkb *lkb);
8162306a36Sopenharmony_cistatic int send_cancel(struct dlm_rsb *r, struct dlm_lkb *lkb);
8262306a36Sopenharmony_cistatic int send_grant(struct dlm_rsb *r, struct dlm_lkb *lkb);
8362306a36Sopenharmony_cistatic int send_bast(struct dlm_rsb *r, struct dlm_lkb *lkb, int mode);
8462306a36Sopenharmony_cistatic int send_lookup(struct dlm_rsb *r, struct dlm_lkb *lkb);
8562306a36Sopenharmony_cistatic int send_remove(struct dlm_rsb *r);
8662306a36Sopenharmony_cistatic int _request_lock(struct dlm_rsb *r, struct dlm_lkb *lkb);
8762306a36Sopenharmony_cistatic int _cancel_lock(struct dlm_rsb *r, struct dlm_lkb *lkb);
8862306a36Sopenharmony_cistatic void __receive_convert_reply(struct dlm_rsb *r, struct dlm_lkb *lkb,
8962306a36Sopenharmony_ci				    const struct dlm_message *ms, bool local);
9062306a36Sopenharmony_cistatic int receive_extralen(const struct dlm_message *ms);
9162306a36Sopenharmony_cistatic void do_purge(struct dlm_ls *ls, int nodeid, int pid);
9262306a36Sopenharmony_cistatic void toss_rsb(struct kref *kref);
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci/*
9562306a36Sopenharmony_ci * Lock compatibilty matrix - thanks Steve
9662306a36Sopenharmony_ci * UN = Unlocked state. Not really a state, used as a flag
9762306a36Sopenharmony_ci * PD = Padding. Used to make the matrix a nice power of two in size
9862306a36Sopenharmony_ci * Other states are the same as the VMS DLM.
9962306a36Sopenharmony_ci * Usage: matrix[grmode+1][rqmode+1]  (although m[rq+1][gr+1] is the same)
10062306a36Sopenharmony_ci */
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_cistatic const int __dlm_compat_matrix[8][8] = {
10362306a36Sopenharmony_ci      /* UN NL CR CW PR PW EX PD */
10462306a36Sopenharmony_ci        {1, 1, 1, 1, 1, 1, 1, 0},       /* UN */
10562306a36Sopenharmony_ci        {1, 1, 1, 1, 1, 1, 1, 0},       /* NL */
10662306a36Sopenharmony_ci        {1, 1, 1, 1, 1, 1, 0, 0},       /* CR */
10762306a36Sopenharmony_ci        {1, 1, 1, 1, 0, 0, 0, 0},       /* CW */
10862306a36Sopenharmony_ci        {1, 1, 1, 0, 1, 0, 0, 0},       /* PR */
10962306a36Sopenharmony_ci        {1, 1, 1, 0, 0, 0, 0, 0},       /* PW */
11062306a36Sopenharmony_ci        {1, 1, 0, 0, 0, 0, 0, 0},       /* EX */
11162306a36Sopenharmony_ci        {0, 0, 0, 0, 0, 0, 0, 0}        /* PD */
11262306a36Sopenharmony_ci};
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci/*
11562306a36Sopenharmony_ci * This defines the direction of transfer of LVB data.
11662306a36Sopenharmony_ci * Granted mode is the row; requested mode is the column.
11762306a36Sopenharmony_ci * Usage: matrix[grmode+1][rqmode+1]
11862306a36Sopenharmony_ci * 1 = LVB is returned to the caller
11962306a36Sopenharmony_ci * 0 = LVB is written to the resource
12062306a36Sopenharmony_ci * -1 = nothing happens to the LVB
12162306a36Sopenharmony_ci */
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ciconst int dlm_lvb_operations[8][8] = {
12462306a36Sopenharmony_ci        /* UN   NL  CR  CW  PR  PW  EX  PD*/
12562306a36Sopenharmony_ci        {  -1,  1,  1,  1,  1,  1,  1, -1 }, /* UN */
12662306a36Sopenharmony_ci        {  -1,  1,  1,  1,  1,  1,  1,  0 }, /* NL */
12762306a36Sopenharmony_ci        {  -1, -1,  1,  1,  1,  1,  1,  0 }, /* CR */
12862306a36Sopenharmony_ci        {  -1, -1, -1,  1,  1,  1,  1,  0 }, /* CW */
12962306a36Sopenharmony_ci        {  -1, -1, -1, -1,  1,  1,  1,  0 }, /* PR */
13062306a36Sopenharmony_ci        {  -1,  0,  0,  0,  0,  0,  1,  0 }, /* PW */
13162306a36Sopenharmony_ci        {  -1,  0,  0,  0,  0,  0,  0,  0 }, /* EX */
13262306a36Sopenharmony_ci        {  -1,  0,  0,  0,  0,  0,  0,  0 }  /* PD */
13362306a36Sopenharmony_ci};
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci#define modes_compat(gr, rq) \
13662306a36Sopenharmony_ci	__dlm_compat_matrix[(gr)->lkb_grmode + 1][(rq)->lkb_rqmode + 1]
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ciint dlm_modes_compat(int mode1, int mode2)
13962306a36Sopenharmony_ci{
14062306a36Sopenharmony_ci	return __dlm_compat_matrix[mode1 + 1][mode2 + 1];
14162306a36Sopenharmony_ci}
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci/*
14462306a36Sopenharmony_ci * Compatibility matrix for conversions with QUECVT set.
14562306a36Sopenharmony_ci * Granted mode is the row; requested mode is the column.
14662306a36Sopenharmony_ci * Usage: matrix[grmode+1][rqmode+1]
14762306a36Sopenharmony_ci */
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_cistatic const int __quecvt_compat_matrix[8][8] = {
15062306a36Sopenharmony_ci      /* UN NL CR CW PR PW EX PD */
15162306a36Sopenharmony_ci        {0, 0, 0, 0, 0, 0, 0, 0},       /* UN */
15262306a36Sopenharmony_ci        {0, 0, 1, 1, 1, 1, 1, 0},       /* NL */
15362306a36Sopenharmony_ci        {0, 0, 0, 1, 1, 1, 1, 0},       /* CR */
15462306a36Sopenharmony_ci        {0, 0, 0, 0, 1, 1, 1, 0},       /* CW */
15562306a36Sopenharmony_ci        {0, 0, 0, 1, 0, 1, 1, 0},       /* PR */
15662306a36Sopenharmony_ci        {0, 0, 0, 0, 0, 0, 1, 0},       /* PW */
15762306a36Sopenharmony_ci        {0, 0, 0, 0, 0, 0, 0, 0},       /* EX */
15862306a36Sopenharmony_ci        {0, 0, 0, 0, 0, 0, 0, 0}        /* PD */
15962306a36Sopenharmony_ci};
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_civoid dlm_print_lkb(struct dlm_lkb *lkb)
16262306a36Sopenharmony_ci{
16362306a36Sopenharmony_ci	printk(KERN_ERR "lkb: nodeid %d id %x remid %x exflags %x flags %x "
16462306a36Sopenharmony_ci	       "sts %d rq %d gr %d wait_type %d wait_nodeid %d seq %llu\n",
16562306a36Sopenharmony_ci	       lkb->lkb_nodeid, lkb->lkb_id, lkb->lkb_remid, lkb->lkb_exflags,
16662306a36Sopenharmony_ci	       dlm_iflags_val(lkb), lkb->lkb_status, lkb->lkb_rqmode,
16762306a36Sopenharmony_ci	       lkb->lkb_grmode, lkb->lkb_wait_type, lkb->lkb_wait_nodeid,
16862306a36Sopenharmony_ci	       (unsigned long long)lkb->lkb_recover_seq);
16962306a36Sopenharmony_ci}
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_cistatic void dlm_print_rsb(struct dlm_rsb *r)
17262306a36Sopenharmony_ci{
17362306a36Sopenharmony_ci	printk(KERN_ERR "rsb: nodeid %d master %d dir %d flags %lx first %x "
17462306a36Sopenharmony_ci	       "rlc %d name %s\n",
17562306a36Sopenharmony_ci	       r->res_nodeid, r->res_master_nodeid, r->res_dir_nodeid,
17662306a36Sopenharmony_ci	       r->res_flags, r->res_first_lkid, r->res_recover_locks_count,
17762306a36Sopenharmony_ci	       r->res_name);
17862306a36Sopenharmony_ci}
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_civoid dlm_dump_rsb(struct dlm_rsb *r)
18162306a36Sopenharmony_ci{
18262306a36Sopenharmony_ci	struct dlm_lkb *lkb;
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	dlm_print_rsb(r);
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	printk(KERN_ERR "rsb: root_list empty %d recover_list empty %d\n",
18762306a36Sopenharmony_ci	       list_empty(&r->res_root_list), list_empty(&r->res_recover_list));
18862306a36Sopenharmony_ci	printk(KERN_ERR "rsb lookup list\n");
18962306a36Sopenharmony_ci	list_for_each_entry(lkb, &r->res_lookup, lkb_rsb_lookup)
19062306a36Sopenharmony_ci		dlm_print_lkb(lkb);
19162306a36Sopenharmony_ci	printk(KERN_ERR "rsb grant queue:\n");
19262306a36Sopenharmony_ci	list_for_each_entry(lkb, &r->res_grantqueue, lkb_statequeue)
19362306a36Sopenharmony_ci		dlm_print_lkb(lkb);
19462306a36Sopenharmony_ci	printk(KERN_ERR "rsb convert queue:\n");
19562306a36Sopenharmony_ci	list_for_each_entry(lkb, &r->res_convertqueue, lkb_statequeue)
19662306a36Sopenharmony_ci		dlm_print_lkb(lkb);
19762306a36Sopenharmony_ci	printk(KERN_ERR "rsb wait queue:\n");
19862306a36Sopenharmony_ci	list_for_each_entry(lkb, &r->res_waitqueue, lkb_statequeue)
19962306a36Sopenharmony_ci		dlm_print_lkb(lkb);
20062306a36Sopenharmony_ci}
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci/* Threads cannot use the lockspace while it's being recovered */
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_cistatic inline void dlm_lock_recovery(struct dlm_ls *ls)
20562306a36Sopenharmony_ci{
20662306a36Sopenharmony_ci	down_read(&ls->ls_in_recovery);
20762306a36Sopenharmony_ci}
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_civoid dlm_unlock_recovery(struct dlm_ls *ls)
21062306a36Sopenharmony_ci{
21162306a36Sopenharmony_ci	up_read(&ls->ls_in_recovery);
21262306a36Sopenharmony_ci}
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ciint dlm_lock_recovery_try(struct dlm_ls *ls)
21562306a36Sopenharmony_ci{
21662306a36Sopenharmony_ci	return down_read_trylock(&ls->ls_in_recovery);
21762306a36Sopenharmony_ci}
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_cistatic inline int can_be_queued(struct dlm_lkb *lkb)
22062306a36Sopenharmony_ci{
22162306a36Sopenharmony_ci	return !(lkb->lkb_exflags & DLM_LKF_NOQUEUE);
22262306a36Sopenharmony_ci}
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_cistatic inline int force_blocking_asts(struct dlm_lkb *lkb)
22562306a36Sopenharmony_ci{
22662306a36Sopenharmony_ci	return (lkb->lkb_exflags & DLM_LKF_NOQUEUEBAST);
22762306a36Sopenharmony_ci}
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_cistatic inline int is_demoted(struct dlm_lkb *lkb)
23062306a36Sopenharmony_ci{
23162306a36Sopenharmony_ci	return test_bit(DLM_SBF_DEMOTED_BIT, &lkb->lkb_sbflags);
23262306a36Sopenharmony_ci}
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_cistatic inline int is_altmode(struct dlm_lkb *lkb)
23562306a36Sopenharmony_ci{
23662306a36Sopenharmony_ci	return test_bit(DLM_SBF_ALTMODE_BIT, &lkb->lkb_sbflags);
23762306a36Sopenharmony_ci}
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_cistatic inline int is_granted(struct dlm_lkb *lkb)
24062306a36Sopenharmony_ci{
24162306a36Sopenharmony_ci	return (lkb->lkb_status == DLM_LKSTS_GRANTED);
24262306a36Sopenharmony_ci}
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_cistatic inline int is_remote(struct dlm_rsb *r)
24562306a36Sopenharmony_ci{
24662306a36Sopenharmony_ci	DLM_ASSERT(r->res_nodeid >= 0, dlm_print_rsb(r););
24762306a36Sopenharmony_ci	return !!r->res_nodeid;
24862306a36Sopenharmony_ci}
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_cistatic inline int is_process_copy(struct dlm_lkb *lkb)
25162306a36Sopenharmony_ci{
25262306a36Sopenharmony_ci	return lkb->lkb_nodeid &&
25362306a36Sopenharmony_ci	       !test_bit(DLM_IFL_MSTCPY_BIT, &lkb->lkb_iflags);
25462306a36Sopenharmony_ci}
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_cistatic inline int is_master_copy(struct dlm_lkb *lkb)
25762306a36Sopenharmony_ci{
25862306a36Sopenharmony_ci	return test_bit(DLM_IFL_MSTCPY_BIT, &lkb->lkb_iflags);
25962306a36Sopenharmony_ci}
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_cistatic inline int middle_conversion(struct dlm_lkb *lkb)
26262306a36Sopenharmony_ci{
26362306a36Sopenharmony_ci	if ((lkb->lkb_grmode==DLM_LOCK_PR && lkb->lkb_rqmode==DLM_LOCK_CW) ||
26462306a36Sopenharmony_ci	    (lkb->lkb_rqmode==DLM_LOCK_PR && lkb->lkb_grmode==DLM_LOCK_CW))
26562306a36Sopenharmony_ci		return 1;
26662306a36Sopenharmony_ci	return 0;
26762306a36Sopenharmony_ci}
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_cistatic inline int down_conversion(struct dlm_lkb *lkb)
27062306a36Sopenharmony_ci{
27162306a36Sopenharmony_ci	return (!middle_conversion(lkb) && lkb->lkb_rqmode < lkb->lkb_grmode);
27262306a36Sopenharmony_ci}
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_cistatic inline int is_overlap_unlock(struct dlm_lkb *lkb)
27562306a36Sopenharmony_ci{
27662306a36Sopenharmony_ci	return test_bit(DLM_IFL_OVERLAP_UNLOCK_BIT, &lkb->lkb_iflags);
27762306a36Sopenharmony_ci}
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_cistatic inline int is_overlap_cancel(struct dlm_lkb *lkb)
28062306a36Sopenharmony_ci{
28162306a36Sopenharmony_ci	return test_bit(DLM_IFL_OVERLAP_CANCEL_BIT, &lkb->lkb_iflags);
28262306a36Sopenharmony_ci}
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_cistatic inline int is_overlap(struct dlm_lkb *lkb)
28562306a36Sopenharmony_ci{
28662306a36Sopenharmony_ci	return test_bit(DLM_IFL_OVERLAP_UNLOCK_BIT, &lkb->lkb_iflags) ||
28762306a36Sopenharmony_ci	       test_bit(DLM_IFL_OVERLAP_CANCEL_BIT, &lkb->lkb_iflags);
28862306a36Sopenharmony_ci}
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_cistatic void queue_cast(struct dlm_rsb *r, struct dlm_lkb *lkb, int rv)
29162306a36Sopenharmony_ci{
29262306a36Sopenharmony_ci	if (is_master_copy(lkb))
29362306a36Sopenharmony_ci		return;
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	DLM_ASSERT(lkb->lkb_lksb, dlm_print_lkb(lkb););
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	if (rv == -DLM_ECANCEL &&
29862306a36Sopenharmony_ci	    test_and_clear_bit(DLM_IFL_DEADLOCK_CANCEL_BIT, &lkb->lkb_iflags))
29962306a36Sopenharmony_ci		rv = -EDEADLK;
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	dlm_add_cb(lkb, DLM_CB_CAST, lkb->lkb_grmode, rv, dlm_sbflags_val(lkb));
30262306a36Sopenharmony_ci}
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_cistatic inline void queue_cast_overlap(struct dlm_rsb *r, struct dlm_lkb *lkb)
30562306a36Sopenharmony_ci{
30662306a36Sopenharmony_ci	queue_cast(r, lkb,
30762306a36Sopenharmony_ci		   is_overlap_unlock(lkb) ? -DLM_EUNLOCK : -DLM_ECANCEL);
30862306a36Sopenharmony_ci}
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_cistatic void queue_bast(struct dlm_rsb *r, struct dlm_lkb *lkb, int rqmode)
31162306a36Sopenharmony_ci{
31262306a36Sopenharmony_ci	if (is_master_copy(lkb)) {
31362306a36Sopenharmony_ci		send_bast(r, lkb, rqmode);
31462306a36Sopenharmony_ci	} else {
31562306a36Sopenharmony_ci		dlm_add_cb(lkb, DLM_CB_BAST, rqmode, 0, 0);
31662306a36Sopenharmony_ci	}
31762306a36Sopenharmony_ci}
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci/*
32062306a36Sopenharmony_ci * Basic operations on rsb's and lkb's
32162306a36Sopenharmony_ci */
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci/* This is only called to add a reference when the code already holds
32462306a36Sopenharmony_ci   a valid reference to the rsb, so there's no need for locking. */
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_cistatic inline void hold_rsb(struct dlm_rsb *r)
32762306a36Sopenharmony_ci{
32862306a36Sopenharmony_ci	kref_get(&r->res_ref);
32962306a36Sopenharmony_ci}
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_civoid dlm_hold_rsb(struct dlm_rsb *r)
33262306a36Sopenharmony_ci{
33362306a36Sopenharmony_ci	hold_rsb(r);
33462306a36Sopenharmony_ci}
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci/* When all references to the rsb are gone it's transferred to
33762306a36Sopenharmony_ci   the tossed list for later disposal. */
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_cistatic void put_rsb(struct dlm_rsb *r)
34062306a36Sopenharmony_ci{
34162306a36Sopenharmony_ci	struct dlm_ls *ls = r->res_ls;
34262306a36Sopenharmony_ci	uint32_t bucket = r->res_bucket;
34362306a36Sopenharmony_ci	int rv;
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	rv = kref_put_lock(&r->res_ref, toss_rsb,
34662306a36Sopenharmony_ci			   &ls->ls_rsbtbl[bucket].lock);
34762306a36Sopenharmony_ci	if (rv)
34862306a36Sopenharmony_ci		spin_unlock(&ls->ls_rsbtbl[bucket].lock);
34962306a36Sopenharmony_ci}
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_civoid dlm_put_rsb(struct dlm_rsb *r)
35262306a36Sopenharmony_ci{
35362306a36Sopenharmony_ci	put_rsb(r);
35462306a36Sopenharmony_ci}
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_cistatic int pre_rsb_struct(struct dlm_ls *ls)
35762306a36Sopenharmony_ci{
35862306a36Sopenharmony_ci	struct dlm_rsb *r1, *r2;
35962306a36Sopenharmony_ci	int count = 0;
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	spin_lock(&ls->ls_new_rsb_spin);
36262306a36Sopenharmony_ci	if (ls->ls_new_rsb_count > dlm_config.ci_new_rsb_count / 2) {
36362306a36Sopenharmony_ci		spin_unlock(&ls->ls_new_rsb_spin);
36462306a36Sopenharmony_ci		return 0;
36562306a36Sopenharmony_ci	}
36662306a36Sopenharmony_ci	spin_unlock(&ls->ls_new_rsb_spin);
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci	r1 = dlm_allocate_rsb(ls);
36962306a36Sopenharmony_ci	r2 = dlm_allocate_rsb(ls);
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	spin_lock(&ls->ls_new_rsb_spin);
37262306a36Sopenharmony_ci	if (r1) {
37362306a36Sopenharmony_ci		list_add(&r1->res_hashchain, &ls->ls_new_rsb);
37462306a36Sopenharmony_ci		ls->ls_new_rsb_count++;
37562306a36Sopenharmony_ci	}
37662306a36Sopenharmony_ci	if (r2) {
37762306a36Sopenharmony_ci		list_add(&r2->res_hashchain, &ls->ls_new_rsb);
37862306a36Sopenharmony_ci		ls->ls_new_rsb_count++;
37962306a36Sopenharmony_ci	}
38062306a36Sopenharmony_ci	count = ls->ls_new_rsb_count;
38162306a36Sopenharmony_ci	spin_unlock(&ls->ls_new_rsb_spin);
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci	if (!count)
38462306a36Sopenharmony_ci		return -ENOMEM;
38562306a36Sopenharmony_ci	return 0;
38662306a36Sopenharmony_ci}
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci/* If ls->ls_new_rsb is empty, return -EAGAIN, so the caller can
38962306a36Sopenharmony_ci   unlock any spinlocks, go back and call pre_rsb_struct again.
39062306a36Sopenharmony_ci   Otherwise, take an rsb off the list and return it. */
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_cistatic int get_rsb_struct(struct dlm_ls *ls, const void *name, int len,
39362306a36Sopenharmony_ci			  struct dlm_rsb **r_ret)
39462306a36Sopenharmony_ci{
39562306a36Sopenharmony_ci	struct dlm_rsb *r;
39662306a36Sopenharmony_ci	int count;
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	spin_lock(&ls->ls_new_rsb_spin);
39962306a36Sopenharmony_ci	if (list_empty(&ls->ls_new_rsb)) {
40062306a36Sopenharmony_ci		count = ls->ls_new_rsb_count;
40162306a36Sopenharmony_ci		spin_unlock(&ls->ls_new_rsb_spin);
40262306a36Sopenharmony_ci		log_debug(ls, "find_rsb retry %d %d %s",
40362306a36Sopenharmony_ci			  count, dlm_config.ci_new_rsb_count,
40462306a36Sopenharmony_ci			  (const char *)name);
40562306a36Sopenharmony_ci		return -EAGAIN;
40662306a36Sopenharmony_ci	}
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	r = list_first_entry(&ls->ls_new_rsb, struct dlm_rsb, res_hashchain);
40962306a36Sopenharmony_ci	list_del(&r->res_hashchain);
41062306a36Sopenharmony_ci	/* Convert the empty list_head to a NULL rb_node for tree usage: */
41162306a36Sopenharmony_ci	memset(&r->res_hashnode, 0, sizeof(struct rb_node));
41262306a36Sopenharmony_ci	ls->ls_new_rsb_count--;
41362306a36Sopenharmony_ci	spin_unlock(&ls->ls_new_rsb_spin);
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	r->res_ls = ls;
41662306a36Sopenharmony_ci	r->res_length = len;
41762306a36Sopenharmony_ci	memcpy(r->res_name, name, len);
41862306a36Sopenharmony_ci	mutex_init(&r->res_mutex);
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci	INIT_LIST_HEAD(&r->res_lookup);
42162306a36Sopenharmony_ci	INIT_LIST_HEAD(&r->res_grantqueue);
42262306a36Sopenharmony_ci	INIT_LIST_HEAD(&r->res_convertqueue);
42362306a36Sopenharmony_ci	INIT_LIST_HEAD(&r->res_waitqueue);
42462306a36Sopenharmony_ci	INIT_LIST_HEAD(&r->res_root_list);
42562306a36Sopenharmony_ci	INIT_LIST_HEAD(&r->res_recover_list);
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	*r_ret = r;
42862306a36Sopenharmony_ci	return 0;
42962306a36Sopenharmony_ci}
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_cistatic int rsb_cmp(struct dlm_rsb *r, const char *name, int nlen)
43262306a36Sopenharmony_ci{
43362306a36Sopenharmony_ci	char maxname[DLM_RESNAME_MAXLEN];
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	memset(maxname, 0, DLM_RESNAME_MAXLEN);
43662306a36Sopenharmony_ci	memcpy(maxname, name, nlen);
43762306a36Sopenharmony_ci	return memcmp(r->res_name, maxname, DLM_RESNAME_MAXLEN);
43862306a36Sopenharmony_ci}
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ciint dlm_search_rsb_tree(struct rb_root *tree, const void *name, int len,
44162306a36Sopenharmony_ci			struct dlm_rsb **r_ret)
44262306a36Sopenharmony_ci{
44362306a36Sopenharmony_ci	struct rb_node *node = tree->rb_node;
44462306a36Sopenharmony_ci	struct dlm_rsb *r;
44562306a36Sopenharmony_ci	int rc;
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci	while (node) {
44862306a36Sopenharmony_ci		r = rb_entry(node, struct dlm_rsb, res_hashnode);
44962306a36Sopenharmony_ci		rc = rsb_cmp(r, name, len);
45062306a36Sopenharmony_ci		if (rc < 0)
45162306a36Sopenharmony_ci			node = node->rb_left;
45262306a36Sopenharmony_ci		else if (rc > 0)
45362306a36Sopenharmony_ci			node = node->rb_right;
45462306a36Sopenharmony_ci		else
45562306a36Sopenharmony_ci			goto found;
45662306a36Sopenharmony_ci	}
45762306a36Sopenharmony_ci	*r_ret = NULL;
45862306a36Sopenharmony_ci	return -EBADR;
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci found:
46162306a36Sopenharmony_ci	*r_ret = r;
46262306a36Sopenharmony_ci	return 0;
46362306a36Sopenharmony_ci}
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_cistatic int rsb_insert(struct dlm_rsb *rsb, struct rb_root *tree)
46662306a36Sopenharmony_ci{
46762306a36Sopenharmony_ci	struct rb_node **newn = &tree->rb_node;
46862306a36Sopenharmony_ci	struct rb_node *parent = NULL;
46962306a36Sopenharmony_ci	int rc;
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	while (*newn) {
47262306a36Sopenharmony_ci		struct dlm_rsb *cur = rb_entry(*newn, struct dlm_rsb,
47362306a36Sopenharmony_ci					       res_hashnode);
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci		parent = *newn;
47662306a36Sopenharmony_ci		rc = rsb_cmp(cur, rsb->res_name, rsb->res_length);
47762306a36Sopenharmony_ci		if (rc < 0)
47862306a36Sopenharmony_ci			newn = &parent->rb_left;
47962306a36Sopenharmony_ci		else if (rc > 0)
48062306a36Sopenharmony_ci			newn = &parent->rb_right;
48162306a36Sopenharmony_ci		else {
48262306a36Sopenharmony_ci			log_print("rsb_insert match");
48362306a36Sopenharmony_ci			dlm_dump_rsb(rsb);
48462306a36Sopenharmony_ci			dlm_dump_rsb(cur);
48562306a36Sopenharmony_ci			return -EEXIST;
48662306a36Sopenharmony_ci		}
48762306a36Sopenharmony_ci	}
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci	rb_link_node(&rsb->res_hashnode, parent, newn);
49062306a36Sopenharmony_ci	rb_insert_color(&rsb->res_hashnode, tree);
49162306a36Sopenharmony_ci	return 0;
49262306a36Sopenharmony_ci}
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci/*
49562306a36Sopenharmony_ci * Find rsb in rsbtbl and potentially create/add one
49662306a36Sopenharmony_ci *
49762306a36Sopenharmony_ci * Delaying the release of rsb's has a similar benefit to applications keeping
49862306a36Sopenharmony_ci * NL locks on an rsb, but without the guarantee that the cached master value
49962306a36Sopenharmony_ci * will still be valid when the rsb is reused.  Apps aren't always smart enough
50062306a36Sopenharmony_ci * to keep NL locks on an rsb that they may lock again shortly; this can lead
50162306a36Sopenharmony_ci * to excessive master lookups and removals if we don't delay the release.
50262306a36Sopenharmony_ci *
50362306a36Sopenharmony_ci * Searching for an rsb means looking through both the normal list and toss
50462306a36Sopenharmony_ci * list.  When found on the toss list the rsb is moved to the normal list with
50562306a36Sopenharmony_ci * ref count of 1; when found on normal list the ref count is incremented.
50662306a36Sopenharmony_ci *
50762306a36Sopenharmony_ci * rsb's on the keep list are being used locally and refcounted.
50862306a36Sopenharmony_ci * rsb's on the toss list are not being used locally, and are not refcounted.
50962306a36Sopenharmony_ci *
51062306a36Sopenharmony_ci * The toss list rsb's were either
51162306a36Sopenharmony_ci * - previously used locally but not any more (were on keep list, then
51262306a36Sopenharmony_ci *   moved to toss list when last refcount dropped)
51362306a36Sopenharmony_ci * - created and put on toss list as a directory record for a lookup
51462306a36Sopenharmony_ci *   (we are the dir node for the res, but are not using the res right now,
51562306a36Sopenharmony_ci *   but some other node is)
51662306a36Sopenharmony_ci *
51762306a36Sopenharmony_ci * The purpose of find_rsb() is to return a refcounted rsb for local use.
51862306a36Sopenharmony_ci * So, if the given rsb is on the toss list, it is moved to the keep list
51962306a36Sopenharmony_ci * before being returned.
52062306a36Sopenharmony_ci *
52162306a36Sopenharmony_ci * toss_rsb() happens when all local usage of the rsb is done, i.e. no
52262306a36Sopenharmony_ci * more refcounts exist, so the rsb is moved from the keep list to the
52362306a36Sopenharmony_ci * toss list.
52462306a36Sopenharmony_ci *
52562306a36Sopenharmony_ci * rsb's on both keep and toss lists are used for doing a name to master
52662306a36Sopenharmony_ci * lookups.  rsb's that are in use locally (and being refcounted) are on
52762306a36Sopenharmony_ci * the keep list, rsb's that are not in use locally (not refcounted) and
52862306a36Sopenharmony_ci * only exist for name/master lookups are on the toss list.
52962306a36Sopenharmony_ci *
53062306a36Sopenharmony_ci * rsb's on the toss list who's dir_nodeid is not local can have stale
53162306a36Sopenharmony_ci * name/master mappings.  So, remote requests on such rsb's can potentially
53262306a36Sopenharmony_ci * return with an error, which means the mapping is stale and needs to
53362306a36Sopenharmony_ci * be updated with a new lookup.  (The idea behind MASTER UNCERTAIN and
53462306a36Sopenharmony_ci * first_lkid is to keep only a single outstanding request on an rsb
53562306a36Sopenharmony_ci * while that rsb has a potentially stale master.)
53662306a36Sopenharmony_ci */
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_cistatic int find_rsb_dir(struct dlm_ls *ls, const void *name, int len,
53962306a36Sopenharmony_ci			uint32_t hash, uint32_t b,
54062306a36Sopenharmony_ci			int dir_nodeid, int from_nodeid,
54162306a36Sopenharmony_ci			unsigned int flags, struct dlm_rsb **r_ret)
54262306a36Sopenharmony_ci{
54362306a36Sopenharmony_ci	struct dlm_rsb *r = NULL;
54462306a36Sopenharmony_ci	int our_nodeid = dlm_our_nodeid();
54562306a36Sopenharmony_ci	int from_local = 0;
54662306a36Sopenharmony_ci	int from_other = 0;
54762306a36Sopenharmony_ci	int from_dir = 0;
54862306a36Sopenharmony_ci	int create = 0;
54962306a36Sopenharmony_ci	int error;
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci	if (flags & R_RECEIVE_REQUEST) {
55262306a36Sopenharmony_ci		if (from_nodeid == dir_nodeid)
55362306a36Sopenharmony_ci			from_dir = 1;
55462306a36Sopenharmony_ci		else
55562306a36Sopenharmony_ci			from_other = 1;
55662306a36Sopenharmony_ci	} else if (flags & R_REQUEST) {
55762306a36Sopenharmony_ci		from_local = 1;
55862306a36Sopenharmony_ci	}
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci	/*
56162306a36Sopenharmony_ci	 * flags & R_RECEIVE_RECOVER is from dlm_recover_master_copy, so
56262306a36Sopenharmony_ci	 * from_nodeid has sent us a lock in dlm_recover_locks, believing
56362306a36Sopenharmony_ci	 * we're the new master.  Our local recovery may not have set
56462306a36Sopenharmony_ci	 * res_master_nodeid to our_nodeid yet, so allow either.  Don't
56562306a36Sopenharmony_ci	 * create the rsb; dlm_recover_process_copy() will handle EBADR
56662306a36Sopenharmony_ci	 * by resending.
56762306a36Sopenharmony_ci	 *
56862306a36Sopenharmony_ci	 * If someone sends us a request, we are the dir node, and we do
56962306a36Sopenharmony_ci	 * not find the rsb anywhere, then recreate it.  This happens if
57062306a36Sopenharmony_ci	 * someone sends us a request after we have removed/freed an rsb
57162306a36Sopenharmony_ci	 * from our toss list.  (They sent a request instead of lookup
57262306a36Sopenharmony_ci	 * because they are using an rsb from their toss list.)
57362306a36Sopenharmony_ci	 */
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci	if (from_local || from_dir ||
57662306a36Sopenharmony_ci	    (from_other && (dir_nodeid == our_nodeid))) {
57762306a36Sopenharmony_ci		create = 1;
57862306a36Sopenharmony_ci	}
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci retry:
58162306a36Sopenharmony_ci	if (create) {
58262306a36Sopenharmony_ci		error = pre_rsb_struct(ls);
58362306a36Sopenharmony_ci		if (error < 0)
58462306a36Sopenharmony_ci			goto out;
58562306a36Sopenharmony_ci	}
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci	spin_lock(&ls->ls_rsbtbl[b].lock);
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_ci	error = dlm_search_rsb_tree(&ls->ls_rsbtbl[b].keep, name, len, &r);
59062306a36Sopenharmony_ci	if (error)
59162306a36Sopenharmony_ci		goto do_toss;
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci	/*
59462306a36Sopenharmony_ci	 * rsb is active, so we can't check master_nodeid without lock_rsb.
59562306a36Sopenharmony_ci	 */
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci	kref_get(&r->res_ref);
59862306a36Sopenharmony_ci	goto out_unlock;
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci do_toss:
60262306a36Sopenharmony_ci	error = dlm_search_rsb_tree(&ls->ls_rsbtbl[b].toss, name, len, &r);
60362306a36Sopenharmony_ci	if (error)
60462306a36Sopenharmony_ci		goto do_new;
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci	/*
60762306a36Sopenharmony_ci	 * rsb found inactive (master_nodeid may be out of date unless
60862306a36Sopenharmony_ci	 * we are the dir_nodeid or were the master)  No other thread
60962306a36Sopenharmony_ci	 * is using this rsb because it's on the toss list, so we can
61062306a36Sopenharmony_ci	 * look at or update res_master_nodeid without lock_rsb.
61162306a36Sopenharmony_ci	 */
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci	if ((r->res_master_nodeid != our_nodeid) && from_other) {
61462306a36Sopenharmony_ci		/* our rsb was not master, and another node (not the dir node)
61562306a36Sopenharmony_ci		   has sent us a request */
61662306a36Sopenharmony_ci		log_debug(ls, "find_rsb toss from_other %d master %d dir %d %s",
61762306a36Sopenharmony_ci			  from_nodeid, r->res_master_nodeid, dir_nodeid,
61862306a36Sopenharmony_ci			  r->res_name);
61962306a36Sopenharmony_ci		error = -ENOTBLK;
62062306a36Sopenharmony_ci		goto out_unlock;
62162306a36Sopenharmony_ci	}
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci	if ((r->res_master_nodeid != our_nodeid) && from_dir) {
62462306a36Sopenharmony_ci		/* don't think this should ever happen */
62562306a36Sopenharmony_ci		log_error(ls, "find_rsb toss from_dir %d master %d",
62662306a36Sopenharmony_ci			  from_nodeid, r->res_master_nodeid);
62762306a36Sopenharmony_ci		dlm_print_rsb(r);
62862306a36Sopenharmony_ci		/* fix it and go on */
62962306a36Sopenharmony_ci		r->res_master_nodeid = our_nodeid;
63062306a36Sopenharmony_ci		r->res_nodeid = 0;
63162306a36Sopenharmony_ci		rsb_clear_flag(r, RSB_MASTER_UNCERTAIN);
63262306a36Sopenharmony_ci		r->res_first_lkid = 0;
63362306a36Sopenharmony_ci	}
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci	if (from_local && (r->res_master_nodeid != our_nodeid)) {
63662306a36Sopenharmony_ci		/* Because we have held no locks on this rsb,
63762306a36Sopenharmony_ci		   res_master_nodeid could have become stale. */
63862306a36Sopenharmony_ci		rsb_set_flag(r, RSB_MASTER_UNCERTAIN);
63962306a36Sopenharmony_ci		r->res_first_lkid = 0;
64062306a36Sopenharmony_ci	}
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ci	rb_erase(&r->res_hashnode, &ls->ls_rsbtbl[b].toss);
64362306a36Sopenharmony_ci	error = rsb_insert(r, &ls->ls_rsbtbl[b].keep);
64462306a36Sopenharmony_ci	goto out_unlock;
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci do_new:
64862306a36Sopenharmony_ci	/*
64962306a36Sopenharmony_ci	 * rsb not found
65062306a36Sopenharmony_ci	 */
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci	if (error == -EBADR && !create)
65362306a36Sopenharmony_ci		goto out_unlock;
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ci	error = get_rsb_struct(ls, name, len, &r);
65662306a36Sopenharmony_ci	if (error == -EAGAIN) {
65762306a36Sopenharmony_ci		spin_unlock(&ls->ls_rsbtbl[b].lock);
65862306a36Sopenharmony_ci		goto retry;
65962306a36Sopenharmony_ci	}
66062306a36Sopenharmony_ci	if (error)
66162306a36Sopenharmony_ci		goto out_unlock;
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_ci	r->res_hash = hash;
66462306a36Sopenharmony_ci	r->res_bucket = b;
66562306a36Sopenharmony_ci	r->res_dir_nodeid = dir_nodeid;
66662306a36Sopenharmony_ci	kref_init(&r->res_ref);
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_ci	if (from_dir) {
66962306a36Sopenharmony_ci		/* want to see how often this happens */
67062306a36Sopenharmony_ci		log_debug(ls, "find_rsb new from_dir %d recreate %s",
67162306a36Sopenharmony_ci			  from_nodeid, r->res_name);
67262306a36Sopenharmony_ci		r->res_master_nodeid = our_nodeid;
67362306a36Sopenharmony_ci		r->res_nodeid = 0;
67462306a36Sopenharmony_ci		goto out_add;
67562306a36Sopenharmony_ci	}
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_ci	if (from_other && (dir_nodeid != our_nodeid)) {
67862306a36Sopenharmony_ci		/* should never happen */
67962306a36Sopenharmony_ci		log_error(ls, "find_rsb new from_other %d dir %d our %d %s",
68062306a36Sopenharmony_ci			  from_nodeid, dir_nodeid, our_nodeid, r->res_name);
68162306a36Sopenharmony_ci		dlm_free_rsb(r);
68262306a36Sopenharmony_ci		r = NULL;
68362306a36Sopenharmony_ci		error = -ENOTBLK;
68462306a36Sopenharmony_ci		goto out_unlock;
68562306a36Sopenharmony_ci	}
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ci	if (from_other) {
68862306a36Sopenharmony_ci		log_debug(ls, "find_rsb new from_other %d dir %d %s",
68962306a36Sopenharmony_ci			  from_nodeid, dir_nodeid, r->res_name);
69062306a36Sopenharmony_ci	}
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci	if (dir_nodeid == our_nodeid) {
69362306a36Sopenharmony_ci		/* When we are the dir nodeid, we can set the master
69462306a36Sopenharmony_ci		   node immediately */
69562306a36Sopenharmony_ci		r->res_master_nodeid = our_nodeid;
69662306a36Sopenharmony_ci		r->res_nodeid = 0;
69762306a36Sopenharmony_ci	} else {
69862306a36Sopenharmony_ci		/* set_master will send_lookup to dir_nodeid */
69962306a36Sopenharmony_ci		r->res_master_nodeid = 0;
70062306a36Sopenharmony_ci		r->res_nodeid = -1;
70162306a36Sopenharmony_ci	}
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_ci out_add:
70462306a36Sopenharmony_ci	error = rsb_insert(r, &ls->ls_rsbtbl[b].keep);
70562306a36Sopenharmony_ci out_unlock:
70662306a36Sopenharmony_ci	spin_unlock(&ls->ls_rsbtbl[b].lock);
70762306a36Sopenharmony_ci out:
70862306a36Sopenharmony_ci	*r_ret = r;
70962306a36Sopenharmony_ci	return error;
71062306a36Sopenharmony_ci}
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_ci/* During recovery, other nodes can send us new MSTCPY locks (from
71362306a36Sopenharmony_ci   dlm_recover_locks) before we've made ourself master (in
71462306a36Sopenharmony_ci   dlm_recover_masters). */
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_cistatic int find_rsb_nodir(struct dlm_ls *ls, const void *name, int len,
71762306a36Sopenharmony_ci			  uint32_t hash, uint32_t b,
71862306a36Sopenharmony_ci			  int dir_nodeid, int from_nodeid,
71962306a36Sopenharmony_ci			  unsigned int flags, struct dlm_rsb **r_ret)
72062306a36Sopenharmony_ci{
72162306a36Sopenharmony_ci	struct dlm_rsb *r = NULL;
72262306a36Sopenharmony_ci	int our_nodeid = dlm_our_nodeid();
72362306a36Sopenharmony_ci	int recover = (flags & R_RECEIVE_RECOVER);
72462306a36Sopenharmony_ci	int error;
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_ci retry:
72762306a36Sopenharmony_ci	error = pre_rsb_struct(ls);
72862306a36Sopenharmony_ci	if (error < 0)
72962306a36Sopenharmony_ci		goto out;
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci	spin_lock(&ls->ls_rsbtbl[b].lock);
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci	error = dlm_search_rsb_tree(&ls->ls_rsbtbl[b].keep, name, len, &r);
73462306a36Sopenharmony_ci	if (error)
73562306a36Sopenharmony_ci		goto do_toss;
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_ci	/*
73862306a36Sopenharmony_ci	 * rsb is active, so we can't check master_nodeid without lock_rsb.
73962306a36Sopenharmony_ci	 */
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_ci	kref_get(&r->res_ref);
74262306a36Sopenharmony_ci	goto out_unlock;
74362306a36Sopenharmony_ci
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_ci do_toss:
74662306a36Sopenharmony_ci	error = dlm_search_rsb_tree(&ls->ls_rsbtbl[b].toss, name, len, &r);
74762306a36Sopenharmony_ci	if (error)
74862306a36Sopenharmony_ci		goto do_new;
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci	/*
75162306a36Sopenharmony_ci	 * rsb found inactive. No other thread is using this rsb because
75262306a36Sopenharmony_ci	 * it's on the toss list, so we can look at or update
75362306a36Sopenharmony_ci	 * res_master_nodeid without lock_rsb.
75462306a36Sopenharmony_ci	 */
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_ci	if (!recover && (r->res_master_nodeid != our_nodeid) && from_nodeid) {
75762306a36Sopenharmony_ci		/* our rsb is not master, and another node has sent us a
75862306a36Sopenharmony_ci		   request; this should never happen */
75962306a36Sopenharmony_ci		log_error(ls, "find_rsb toss from_nodeid %d master %d dir %d",
76062306a36Sopenharmony_ci			  from_nodeid, r->res_master_nodeid, dir_nodeid);
76162306a36Sopenharmony_ci		dlm_print_rsb(r);
76262306a36Sopenharmony_ci		error = -ENOTBLK;
76362306a36Sopenharmony_ci		goto out_unlock;
76462306a36Sopenharmony_ci	}
76562306a36Sopenharmony_ci
76662306a36Sopenharmony_ci	if (!recover && (r->res_master_nodeid != our_nodeid) &&
76762306a36Sopenharmony_ci	    (dir_nodeid == our_nodeid)) {
76862306a36Sopenharmony_ci		/* our rsb is not master, and we are dir; may as well fix it;
76962306a36Sopenharmony_ci		   this should never happen */
77062306a36Sopenharmony_ci		log_error(ls, "find_rsb toss our %d master %d dir %d",
77162306a36Sopenharmony_ci			  our_nodeid, r->res_master_nodeid, dir_nodeid);
77262306a36Sopenharmony_ci		dlm_print_rsb(r);
77362306a36Sopenharmony_ci		r->res_master_nodeid = our_nodeid;
77462306a36Sopenharmony_ci		r->res_nodeid = 0;
77562306a36Sopenharmony_ci	}
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_ci	rb_erase(&r->res_hashnode, &ls->ls_rsbtbl[b].toss);
77862306a36Sopenharmony_ci	error = rsb_insert(r, &ls->ls_rsbtbl[b].keep);
77962306a36Sopenharmony_ci	goto out_unlock;
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_ci
78262306a36Sopenharmony_ci do_new:
78362306a36Sopenharmony_ci	/*
78462306a36Sopenharmony_ci	 * rsb not found
78562306a36Sopenharmony_ci	 */
78662306a36Sopenharmony_ci
78762306a36Sopenharmony_ci	error = get_rsb_struct(ls, name, len, &r);
78862306a36Sopenharmony_ci	if (error == -EAGAIN) {
78962306a36Sopenharmony_ci		spin_unlock(&ls->ls_rsbtbl[b].lock);
79062306a36Sopenharmony_ci		goto retry;
79162306a36Sopenharmony_ci	}
79262306a36Sopenharmony_ci	if (error)
79362306a36Sopenharmony_ci		goto out_unlock;
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_ci	r->res_hash = hash;
79662306a36Sopenharmony_ci	r->res_bucket = b;
79762306a36Sopenharmony_ci	r->res_dir_nodeid = dir_nodeid;
79862306a36Sopenharmony_ci	r->res_master_nodeid = dir_nodeid;
79962306a36Sopenharmony_ci	r->res_nodeid = (dir_nodeid == our_nodeid) ? 0 : dir_nodeid;
80062306a36Sopenharmony_ci	kref_init(&r->res_ref);
80162306a36Sopenharmony_ci
80262306a36Sopenharmony_ci	error = rsb_insert(r, &ls->ls_rsbtbl[b].keep);
80362306a36Sopenharmony_ci out_unlock:
80462306a36Sopenharmony_ci	spin_unlock(&ls->ls_rsbtbl[b].lock);
80562306a36Sopenharmony_ci out:
80662306a36Sopenharmony_ci	*r_ret = r;
80762306a36Sopenharmony_ci	return error;
80862306a36Sopenharmony_ci}
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_cistatic int find_rsb(struct dlm_ls *ls, const void *name, int len,
81162306a36Sopenharmony_ci		    int from_nodeid, unsigned int flags,
81262306a36Sopenharmony_ci		    struct dlm_rsb **r_ret)
81362306a36Sopenharmony_ci{
81462306a36Sopenharmony_ci	uint32_t hash, b;
81562306a36Sopenharmony_ci	int dir_nodeid;
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_ci	if (len > DLM_RESNAME_MAXLEN)
81862306a36Sopenharmony_ci		return -EINVAL;
81962306a36Sopenharmony_ci
82062306a36Sopenharmony_ci	hash = jhash(name, len, 0);
82162306a36Sopenharmony_ci	b = hash & (ls->ls_rsbtbl_size - 1);
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_ci	dir_nodeid = dlm_hash2nodeid(ls, hash);
82462306a36Sopenharmony_ci
82562306a36Sopenharmony_ci	if (dlm_no_directory(ls))
82662306a36Sopenharmony_ci		return find_rsb_nodir(ls, name, len, hash, b, dir_nodeid,
82762306a36Sopenharmony_ci				      from_nodeid, flags, r_ret);
82862306a36Sopenharmony_ci	else
82962306a36Sopenharmony_ci		return find_rsb_dir(ls, name, len, hash, b, dir_nodeid,
83062306a36Sopenharmony_ci				      from_nodeid, flags, r_ret);
83162306a36Sopenharmony_ci}
83262306a36Sopenharmony_ci
83362306a36Sopenharmony_ci/* we have received a request and found that res_master_nodeid != our_nodeid,
83462306a36Sopenharmony_ci   so we need to return an error or make ourself the master */
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_cistatic int validate_master_nodeid(struct dlm_ls *ls, struct dlm_rsb *r,
83762306a36Sopenharmony_ci				  int from_nodeid)
83862306a36Sopenharmony_ci{
83962306a36Sopenharmony_ci	if (dlm_no_directory(ls)) {
84062306a36Sopenharmony_ci		log_error(ls, "find_rsb keep from_nodeid %d master %d dir %d",
84162306a36Sopenharmony_ci			  from_nodeid, r->res_master_nodeid,
84262306a36Sopenharmony_ci			  r->res_dir_nodeid);
84362306a36Sopenharmony_ci		dlm_print_rsb(r);
84462306a36Sopenharmony_ci		return -ENOTBLK;
84562306a36Sopenharmony_ci	}
84662306a36Sopenharmony_ci
84762306a36Sopenharmony_ci	if (from_nodeid != r->res_dir_nodeid) {
84862306a36Sopenharmony_ci		/* our rsb is not master, and another node (not the dir node)
84962306a36Sopenharmony_ci	   	   has sent us a request.  this is much more common when our
85062306a36Sopenharmony_ci	   	   master_nodeid is zero, so limit debug to non-zero.  */
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_ci		if (r->res_master_nodeid) {
85362306a36Sopenharmony_ci			log_debug(ls, "validate master from_other %d master %d "
85462306a36Sopenharmony_ci				  "dir %d first %x %s", from_nodeid,
85562306a36Sopenharmony_ci				  r->res_master_nodeid, r->res_dir_nodeid,
85662306a36Sopenharmony_ci				  r->res_first_lkid, r->res_name);
85762306a36Sopenharmony_ci		}
85862306a36Sopenharmony_ci		return -ENOTBLK;
85962306a36Sopenharmony_ci	} else {
86062306a36Sopenharmony_ci		/* our rsb is not master, but the dir nodeid has sent us a
86162306a36Sopenharmony_ci	   	   request; this could happen with master 0 / res_nodeid -1 */
86262306a36Sopenharmony_ci
86362306a36Sopenharmony_ci		if (r->res_master_nodeid) {
86462306a36Sopenharmony_ci			log_error(ls, "validate master from_dir %d master %d "
86562306a36Sopenharmony_ci				  "first %x %s",
86662306a36Sopenharmony_ci				  from_nodeid, r->res_master_nodeid,
86762306a36Sopenharmony_ci				  r->res_first_lkid, r->res_name);
86862306a36Sopenharmony_ci		}
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_ci		r->res_master_nodeid = dlm_our_nodeid();
87162306a36Sopenharmony_ci		r->res_nodeid = 0;
87262306a36Sopenharmony_ci		return 0;
87362306a36Sopenharmony_ci	}
87462306a36Sopenharmony_ci}
87562306a36Sopenharmony_ci
87662306a36Sopenharmony_cistatic void __dlm_master_lookup(struct dlm_ls *ls, struct dlm_rsb *r, int our_nodeid,
87762306a36Sopenharmony_ci				int from_nodeid, bool toss_list, unsigned int flags,
87862306a36Sopenharmony_ci				int *r_nodeid, int *result)
87962306a36Sopenharmony_ci{
88062306a36Sopenharmony_ci	int fix_master = (flags & DLM_LU_RECOVER_MASTER);
88162306a36Sopenharmony_ci	int from_master = (flags & DLM_LU_RECOVER_DIR);
88262306a36Sopenharmony_ci
88362306a36Sopenharmony_ci	if (r->res_dir_nodeid != our_nodeid) {
88462306a36Sopenharmony_ci		/* should not happen, but may as well fix it and carry on */
88562306a36Sopenharmony_ci		log_error(ls, "%s res_dir %d our %d %s", __func__,
88662306a36Sopenharmony_ci			  r->res_dir_nodeid, our_nodeid, r->res_name);
88762306a36Sopenharmony_ci		r->res_dir_nodeid = our_nodeid;
88862306a36Sopenharmony_ci	}
88962306a36Sopenharmony_ci
89062306a36Sopenharmony_ci	if (fix_master && dlm_is_removed(ls, r->res_master_nodeid)) {
89162306a36Sopenharmony_ci		/* Recovery uses this function to set a new master when
89262306a36Sopenharmony_ci		 * the previous master failed.  Setting NEW_MASTER will
89362306a36Sopenharmony_ci		 * force dlm_recover_masters to call recover_master on this
89462306a36Sopenharmony_ci		 * rsb even though the res_nodeid is no longer removed.
89562306a36Sopenharmony_ci		 */
89662306a36Sopenharmony_ci
89762306a36Sopenharmony_ci		r->res_master_nodeid = from_nodeid;
89862306a36Sopenharmony_ci		r->res_nodeid = from_nodeid;
89962306a36Sopenharmony_ci		rsb_set_flag(r, RSB_NEW_MASTER);
90062306a36Sopenharmony_ci
90162306a36Sopenharmony_ci		if (toss_list) {
90262306a36Sopenharmony_ci			/* I don't think we should ever find it on toss list. */
90362306a36Sopenharmony_ci			log_error(ls, "%s fix_master on toss", __func__);
90462306a36Sopenharmony_ci			dlm_dump_rsb(r);
90562306a36Sopenharmony_ci		}
90662306a36Sopenharmony_ci	}
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_ci	if (from_master && (r->res_master_nodeid != from_nodeid)) {
90962306a36Sopenharmony_ci		/* this will happen if from_nodeid became master during
91062306a36Sopenharmony_ci		 * a previous recovery cycle, and we aborted the previous
91162306a36Sopenharmony_ci		 * cycle before recovering this master value
91262306a36Sopenharmony_ci		 */
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_ci		log_limit(ls, "%s from_master %d master_nodeid %d res_nodeid %d first %x %s",
91562306a36Sopenharmony_ci			  __func__, from_nodeid, r->res_master_nodeid,
91662306a36Sopenharmony_ci			  r->res_nodeid, r->res_first_lkid, r->res_name);
91762306a36Sopenharmony_ci
91862306a36Sopenharmony_ci		if (r->res_master_nodeid == our_nodeid) {
91962306a36Sopenharmony_ci			log_error(ls, "from_master %d our_master", from_nodeid);
92062306a36Sopenharmony_ci			dlm_dump_rsb(r);
92162306a36Sopenharmony_ci			goto ret_assign;
92262306a36Sopenharmony_ci		}
92362306a36Sopenharmony_ci
92462306a36Sopenharmony_ci		r->res_master_nodeid = from_nodeid;
92562306a36Sopenharmony_ci		r->res_nodeid = from_nodeid;
92662306a36Sopenharmony_ci		rsb_set_flag(r, RSB_NEW_MASTER);
92762306a36Sopenharmony_ci	}
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_ci	if (!r->res_master_nodeid) {
93062306a36Sopenharmony_ci		/* this will happen if recovery happens while we're looking
93162306a36Sopenharmony_ci		 * up the master for this rsb
93262306a36Sopenharmony_ci		 */
93362306a36Sopenharmony_ci
93462306a36Sopenharmony_ci		log_debug(ls, "%s master 0 to %d first %x %s", __func__,
93562306a36Sopenharmony_ci			  from_nodeid, r->res_first_lkid, r->res_name);
93662306a36Sopenharmony_ci		r->res_master_nodeid = from_nodeid;
93762306a36Sopenharmony_ci		r->res_nodeid = from_nodeid;
93862306a36Sopenharmony_ci	}
93962306a36Sopenharmony_ci
94062306a36Sopenharmony_ci	if (!from_master && !fix_master &&
94162306a36Sopenharmony_ci	    (r->res_master_nodeid == from_nodeid)) {
94262306a36Sopenharmony_ci		/* this can happen when the master sends remove, the dir node
94362306a36Sopenharmony_ci		 * finds the rsb on the keep list and ignores the remove,
94462306a36Sopenharmony_ci		 * and the former master sends a lookup
94562306a36Sopenharmony_ci		 */
94662306a36Sopenharmony_ci
94762306a36Sopenharmony_ci		log_limit(ls, "%s from master %d flags %x first %x %s",
94862306a36Sopenharmony_ci			  __func__, from_nodeid, flags, r->res_first_lkid,
94962306a36Sopenharmony_ci			  r->res_name);
95062306a36Sopenharmony_ci	}
95162306a36Sopenharmony_ci
95262306a36Sopenharmony_ci ret_assign:
95362306a36Sopenharmony_ci	*r_nodeid = r->res_master_nodeid;
95462306a36Sopenharmony_ci	if (result)
95562306a36Sopenharmony_ci		*result = DLM_LU_MATCH;
95662306a36Sopenharmony_ci}
95762306a36Sopenharmony_ci
95862306a36Sopenharmony_ci/*
95962306a36Sopenharmony_ci * We're the dir node for this res and another node wants to know the
96062306a36Sopenharmony_ci * master nodeid.  During normal operation (non recovery) this is only
96162306a36Sopenharmony_ci * called from receive_lookup(); master lookups when the local node is
96262306a36Sopenharmony_ci * the dir node are done by find_rsb().
96362306a36Sopenharmony_ci *
96462306a36Sopenharmony_ci * normal operation, we are the dir node for a resource
96562306a36Sopenharmony_ci * . _request_lock
96662306a36Sopenharmony_ci * . set_master
96762306a36Sopenharmony_ci * . send_lookup
96862306a36Sopenharmony_ci * . receive_lookup
96962306a36Sopenharmony_ci * . dlm_master_lookup flags 0
97062306a36Sopenharmony_ci *
97162306a36Sopenharmony_ci * recover directory, we are rebuilding dir for all resources
97262306a36Sopenharmony_ci * . dlm_recover_directory
97362306a36Sopenharmony_ci * . dlm_rcom_names
97462306a36Sopenharmony_ci *   remote node sends back the rsb names it is master of and we are dir of
97562306a36Sopenharmony_ci * . dlm_master_lookup RECOVER_DIR (fix_master 0, from_master 1)
97662306a36Sopenharmony_ci *   we either create new rsb setting remote node as master, or find existing
97762306a36Sopenharmony_ci *   rsb and set master to be the remote node.
97862306a36Sopenharmony_ci *
97962306a36Sopenharmony_ci * recover masters, we are finding the new master for resources
98062306a36Sopenharmony_ci * . dlm_recover_masters
98162306a36Sopenharmony_ci * . recover_master
98262306a36Sopenharmony_ci * . dlm_send_rcom_lookup
98362306a36Sopenharmony_ci * . receive_rcom_lookup
98462306a36Sopenharmony_ci * . dlm_master_lookup RECOVER_MASTER (fix_master 1, from_master 0)
98562306a36Sopenharmony_ci */
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_ciint dlm_master_lookup(struct dlm_ls *ls, int from_nodeid, const char *name,
98862306a36Sopenharmony_ci		      int len, unsigned int flags, int *r_nodeid, int *result)
98962306a36Sopenharmony_ci{
99062306a36Sopenharmony_ci	struct dlm_rsb *r = NULL;
99162306a36Sopenharmony_ci	uint32_t hash, b;
99262306a36Sopenharmony_ci	int our_nodeid = dlm_our_nodeid();
99362306a36Sopenharmony_ci	int dir_nodeid, error;
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_ci	if (len > DLM_RESNAME_MAXLEN)
99662306a36Sopenharmony_ci		return -EINVAL;
99762306a36Sopenharmony_ci
99862306a36Sopenharmony_ci	if (from_nodeid == our_nodeid) {
99962306a36Sopenharmony_ci		log_error(ls, "dlm_master_lookup from our_nodeid %d flags %x",
100062306a36Sopenharmony_ci			  our_nodeid, flags);
100162306a36Sopenharmony_ci		return -EINVAL;
100262306a36Sopenharmony_ci	}
100362306a36Sopenharmony_ci
100462306a36Sopenharmony_ci	hash = jhash(name, len, 0);
100562306a36Sopenharmony_ci	b = hash & (ls->ls_rsbtbl_size - 1);
100662306a36Sopenharmony_ci
100762306a36Sopenharmony_ci	dir_nodeid = dlm_hash2nodeid(ls, hash);
100862306a36Sopenharmony_ci	if (dir_nodeid != our_nodeid) {
100962306a36Sopenharmony_ci		log_error(ls, "dlm_master_lookup from %d dir %d our %d h %x %d",
101062306a36Sopenharmony_ci			  from_nodeid, dir_nodeid, our_nodeid, hash,
101162306a36Sopenharmony_ci			  ls->ls_num_nodes);
101262306a36Sopenharmony_ci		*r_nodeid = -1;
101362306a36Sopenharmony_ci		return -EINVAL;
101462306a36Sopenharmony_ci	}
101562306a36Sopenharmony_ci
101662306a36Sopenharmony_ci retry:
101762306a36Sopenharmony_ci	error = pre_rsb_struct(ls);
101862306a36Sopenharmony_ci	if (error < 0)
101962306a36Sopenharmony_ci		return error;
102062306a36Sopenharmony_ci
102162306a36Sopenharmony_ci	spin_lock(&ls->ls_rsbtbl[b].lock);
102262306a36Sopenharmony_ci	error = dlm_search_rsb_tree(&ls->ls_rsbtbl[b].keep, name, len, &r);
102362306a36Sopenharmony_ci	if (!error) {
102462306a36Sopenharmony_ci		/* because the rsb is active, we need to lock_rsb before
102562306a36Sopenharmony_ci		 * checking/changing re_master_nodeid
102662306a36Sopenharmony_ci		 */
102762306a36Sopenharmony_ci
102862306a36Sopenharmony_ci		hold_rsb(r);
102962306a36Sopenharmony_ci		spin_unlock(&ls->ls_rsbtbl[b].lock);
103062306a36Sopenharmony_ci		lock_rsb(r);
103162306a36Sopenharmony_ci
103262306a36Sopenharmony_ci		__dlm_master_lookup(ls, r, our_nodeid, from_nodeid, false,
103362306a36Sopenharmony_ci				    flags, r_nodeid, result);
103462306a36Sopenharmony_ci
103562306a36Sopenharmony_ci		/* the rsb was active */
103662306a36Sopenharmony_ci		unlock_rsb(r);
103762306a36Sopenharmony_ci		put_rsb(r);
103862306a36Sopenharmony_ci
103962306a36Sopenharmony_ci		return 0;
104062306a36Sopenharmony_ci	}
104162306a36Sopenharmony_ci
104262306a36Sopenharmony_ci	error = dlm_search_rsb_tree(&ls->ls_rsbtbl[b].toss, name, len, &r);
104362306a36Sopenharmony_ci	if (error)
104462306a36Sopenharmony_ci		goto not_found;
104562306a36Sopenharmony_ci
104662306a36Sopenharmony_ci	/* because the rsb is inactive (on toss list), it's not refcounted
104762306a36Sopenharmony_ci	 * and lock_rsb is not used, but is protected by the rsbtbl lock
104862306a36Sopenharmony_ci	 */
104962306a36Sopenharmony_ci
105062306a36Sopenharmony_ci	__dlm_master_lookup(ls, r, our_nodeid, from_nodeid, true, flags,
105162306a36Sopenharmony_ci			    r_nodeid, result);
105262306a36Sopenharmony_ci
105362306a36Sopenharmony_ci	r->res_toss_time = jiffies;
105462306a36Sopenharmony_ci	/* the rsb was inactive (on toss list) */
105562306a36Sopenharmony_ci	spin_unlock(&ls->ls_rsbtbl[b].lock);
105662306a36Sopenharmony_ci
105762306a36Sopenharmony_ci	return 0;
105862306a36Sopenharmony_ci
105962306a36Sopenharmony_ci not_found:
106062306a36Sopenharmony_ci	error = get_rsb_struct(ls, name, len, &r);
106162306a36Sopenharmony_ci	if (error == -EAGAIN) {
106262306a36Sopenharmony_ci		spin_unlock(&ls->ls_rsbtbl[b].lock);
106362306a36Sopenharmony_ci		goto retry;
106462306a36Sopenharmony_ci	}
106562306a36Sopenharmony_ci	if (error)
106662306a36Sopenharmony_ci		goto out_unlock;
106762306a36Sopenharmony_ci
106862306a36Sopenharmony_ci	r->res_hash = hash;
106962306a36Sopenharmony_ci	r->res_bucket = b;
107062306a36Sopenharmony_ci	r->res_dir_nodeid = our_nodeid;
107162306a36Sopenharmony_ci	r->res_master_nodeid = from_nodeid;
107262306a36Sopenharmony_ci	r->res_nodeid = from_nodeid;
107362306a36Sopenharmony_ci	kref_init(&r->res_ref);
107462306a36Sopenharmony_ci	r->res_toss_time = jiffies;
107562306a36Sopenharmony_ci
107662306a36Sopenharmony_ci	error = rsb_insert(r, &ls->ls_rsbtbl[b].toss);
107762306a36Sopenharmony_ci	if (error) {
107862306a36Sopenharmony_ci		/* should never happen */
107962306a36Sopenharmony_ci		dlm_free_rsb(r);
108062306a36Sopenharmony_ci		spin_unlock(&ls->ls_rsbtbl[b].lock);
108162306a36Sopenharmony_ci		goto retry;
108262306a36Sopenharmony_ci	}
108362306a36Sopenharmony_ci
108462306a36Sopenharmony_ci	if (result)
108562306a36Sopenharmony_ci		*result = DLM_LU_ADD;
108662306a36Sopenharmony_ci	*r_nodeid = from_nodeid;
108762306a36Sopenharmony_ci out_unlock:
108862306a36Sopenharmony_ci	spin_unlock(&ls->ls_rsbtbl[b].lock);
108962306a36Sopenharmony_ci	return error;
109062306a36Sopenharmony_ci}
109162306a36Sopenharmony_ci
109262306a36Sopenharmony_cistatic void dlm_dump_rsb_hash(struct dlm_ls *ls, uint32_t hash)
109362306a36Sopenharmony_ci{
109462306a36Sopenharmony_ci	struct rb_node *n;
109562306a36Sopenharmony_ci	struct dlm_rsb *r;
109662306a36Sopenharmony_ci	int i;
109762306a36Sopenharmony_ci
109862306a36Sopenharmony_ci	for (i = 0; i < ls->ls_rsbtbl_size; i++) {
109962306a36Sopenharmony_ci		spin_lock(&ls->ls_rsbtbl[i].lock);
110062306a36Sopenharmony_ci		for (n = rb_first(&ls->ls_rsbtbl[i].keep); n; n = rb_next(n)) {
110162306a36Sopenharmony_ci			r = rb_entry(n, struct dlm_rsb, res_hashnode);
110262306a36Sopenharmony_ci			if (r->res_hash == hash)
110362306a36Sopenharmony_ci				dlm_dump_rsb(r);
110462306a36Sopenharmony_ci		}
110562306a36Sopenharmony_ci		spin_unlock(&ls->ls_rsbtbl[i].lock);
110662306a36Sopenharmony_ci	}
110762306a36Sopenharmony_ci}
110862306a36Sopenharmony_ci
110962306a36Sopenharmony_civoid dlm_dump_rsb_name(struct dlm_ls *ls, const char *name, int len)
111062306a36Sopenharmony_ci{
111162306a36Sopenharmony_ci	struct dlm_rsb *r = NULL;
111262306a36Sopenharmony_ci	uint32_t hash, b;
111362306a36Sopenharmony_ci	int error;
111462306a36Sopenharmony_ci
111562306a36Sopenharmony_ci	hash = jhash(name, len, 0);
111662306a36Sopenharmony_ci	b = hash & (ls->ls_rsbtbl_size - 1);
111762306a36Sopenharmony_ci
111862306a36Sopenharmony_ci	spin_lock(&ls->ls_rsbtbl[b].lock);
111962306a36Sopenharmony_ci	error = dlm_search_rsb_tree(&ls->ls_rsbtbl[b].keep, name, len, &r);
112062306a36Sopenharmony_ci	if (!error)
112162306a36Sopenharmony_ci		goto out_dump;
112262306a36Sopenharmony_ci
112362306a36Sopenharmony_ci	error = dlm_search_rsb_tree(&ls->ls_rsbtbl[b].toss, name, len, &r);
112462306a36Sopenharmony_ci	if (error)
112562306a36Sopenharmony_ci		goto out;
112662306a36Sopenharmony_ci out_dump:
112762306a36Sopenharmony_ci	dlm_dump_rsb(r);
112862306a36Sopenharmony_ci out:
112962306a36Sopenharmony_ci	spin_unlock(&ls->ls_rsbtbl[b].lock);
113062306a36Sopenharmony_ci}
113162306a36Sopenharmony_ci
113262306a36Sopenharmony_cistatic void toss_rsb(struct kref *kref)
113362306a36Sopenharmony_ci{
113462306a36Sopenharmony_ci	struct dlm_rsb *r = container_of(kref, struct dlm_rsb, res_ref);
113562306a36Sopenharmony_ci	struct dlm_ls *ls = r->res_ls;
113662306a36Sopenharmony_ci
113762306a36Sopenharmony_ci	DLM_ASSERT(list_empty(&r->res_root_list), dlm_print_rsb(r););
113862306a36Sopenharmony_ci	kref_init(&r->res_ref);
113962306a36Sopenharmony_ci	rb_erase(&r->res_hashnode, &ls->ls_rsbtbl[r->res_bucket].keep);
114062306a36Sopenharmony_ci	rsb_insert(r, &ls->ls_rsbtbl[r->res_bucket].toss);
114162306a36Sopenharmony_ci	r->res_toss_time = jiffies;
114262306a36Sopenharmony_ci	set_bit(DLM_RTF_SHRINK_BIT, &ls->ls_rsbtbl[r->res_bucket].flags);
114362306a36Sopenharmony_ci	if (r->res_lvbptr) {
114462306a36Sopenharmony_ci		dlm_free_lvb(r->res_lvbptr);
114562306a36Sopenharmony_ci		r->res_lvbptr = NULL;
114662306a36Sopenharmony_ci	}
114762306a36Sopenharmony_ci}
114862306a36Sopenharmony_ci
114962306a36Sopenharmony_ci/* See comment for unhold_lkb */
115062306a36Sopenharmony_ci
115162306a36Sopenharmony_cistatic void unhold_rsb(struct dlm_rsb *r)
115262306a36Sopenharmony_ci{
115362306a36Sopenharmony_ci	int rv;
115462306a36Sopenharmony_ci	rv = kref_put(&r->res_ref, toss_rsb);
115562306a36Sopenharmony_ci	DLM_ASSERT(!rv, dlm_dump_rsb(r););
115662306a36Sopenharmony_ci}
115762306a36Sopenharmony_ci
115862306a36Sopenharmony_cistatic void kill_rsb(struct kref *kref)
115962306a36Sopenharmony_ci{
116062306a36Sopenharmony_ci	struct dlm_rsb *r = container_of(kref, struct dlm_rsb, res_ref);
116162306a36Sopenharmony_ci
116262306a36Sopenharmony_ci	/* All work is done after the return from kref_put() so we
116362306a36Sopenharmony_ci	   can release the write_lock before the remove and free. */
116462306a36Sopenharmony_ci
116562306a36Sopenharmony_ci	DLM_ASSERT(list_empty(&r->res_lookup), dlm_dump_rsb(r););
116662306a36Sopenharmony_ci	DLM_ASSERT(list_empty(&r->res_grantqueue), dlm_dump_rsb(r););
116762306a36Sopenharmony_ci	DLM_ASSERT(list_empty(&r->res_convertqueue), dlm_dump_rsb(r););
116862306a36Sopenharmony_ci	DLM_ASSERT(list_empty(&r->res_waitqueue), dlm_dump_rsb(r););
116962306a36Sopenharmony_ci	DLM_ASSERT(list_empty(&r->res_root_list), dlm_dump_rsb(r););
117062306a36Sopenharmony_ci	DLM_ASSERT(list_empty(&r->res_recover_list), dlm_dump_rsb(r););
117162306a36Sopenharmony_ci}
117262306a36Sopenharmony_ci
117362306a36Sopenharmony_ci/* Attaching/detaching lkb's from rsb's is for rsb reference counting.
117462306a36Sopenharmony_ci   The rsb must exist as long as any lkb's for it do. */
117562306a36Sopenharmony_ci
117662306a36Sopenharmony_cistatic void attach_lkb(struct dlm_rsb *r, struct dlm_lkb *lkb)
117762306a36Sopenharmony_ci{
117862306a36Sopenharmony_ci	hold_rsb(r);
117962306a36Sopenharmony_ci	lkb->lkb_resource = r;
118062306a36Sopenharmony_ci}
118162306a36Sopenharmony_ci
118262306a36Sopenharmony_cistatic void detach_lkb(struct dlm_lkb *lkb)
118362306a36Sopenharmony_ci{
118462306a36Sopenharmony_ci	if (lkb->lkb_resource) {
118562306a36Sopenharmony_ci		put_rsb(lkb->lkb_resource);
118662306a36Sopenharmony_ci		lkb->lkb_resource = NULL;
118762306a36Sopenharmony_ci	}
118862306a36Sopenharmony_ci}
118962306a36Sopenharmony_ci
119062306a36Sopenharmony_cistatic int _create_lkb(struct dlm_ls *ls, struct dlm_lkb **lkb_ret,
119162306a36Sopenharmony_ci		       int start, int end)
119262306a36Sopenharmony_ci{
119362306a36Sopenharmony_ci	struct dlm_lkb *lkb;
119462306a36Sopenharmony_ci	int rv;
119562306a36Sopenharmony_ci
119662306a36Sopenharmony_ci	lkb = dlm_allocate_lkb(ls);
119762306a36Sopenharmony_ci	if (!lkb)
119862306a36Sopenharmony_ci		return -ENOMEM;
119962306a36Sopenharmony_ci
120062306a36Sopenharmony_ci	lkb->lkb_last_bast_mode = -1;
120162306a36Sopenharmony_ci	lkb->lkb_nodeid = -1;
120262306a36Sopenharmony_ci	lkb->lkb_grmode = DLM_LOCK_IV;
120362306a36Sopenharmony_ci	kref_init(&lkb->lkb_ref);
120462306a36Sopenharmony_ci	INIT_LIST_HEAD(&lkb->lkb_ownqueue);
120562306a36Sopenharmony_ci	INIT_LIST_HEAD(&lkb->lkb_rsb_lookup);
120662306a36Sopenharmony_ci	INIT_LIST_HEAD(&lkb->lkb_cb_list);
120762306a36Sopenharmony_ci	INIT_LIST_HEAD(&lkb->lkb_callbacks);
120862306a36Sopenharmony_ci	spin_lock_init(&lkb->lkb_cb_lock);
120962306a36Sopenharmony_ci	INIT_WORK(&lkb->lkb_cb_work, dlm_callback_work);
121062306a36Sopenharmony_ci
121162306a36Sopenharmony_ci	idr_preload(GFP_NOFS);
121262306a36Sopenharmony_ci	spin_lock(&ls->ls_lkbidr_spin);
121362306a36Sopenharmony_ci	rv = idr_alloc(&ls->ls_lkbidr, lkb, start, end, GFP_NOWAIT);
121462306a36Sopenharmony_ci	if (rv >= 0)
121562306a36Sopenharmony_ci		lkb->lkb_id = rv;
121662306a36Sopenharmony_ci	spin_unlock(&ls->ls_lkbidr_spin);
121762306a36Sopenharmony_ci	idr_preload_end();
121862306a36Sopenharmony_ci
121962306a36Sopenharmony_ci	if (rv < 0) {
122062306a36Sopenharmony_ci		log_error(ls, "create_lkb idr error %d", rv);
122162306a36Sopenharmony_ci		dlm_free_lkb(lkb);
122262306a36Sopenharmony_ci		return rv;
122362306a36Sopenharmony_ci	}
122462306a36Sopenharmony_ci
122562306a36Sopenharmony_ci	*lkb_ret = lkb;
122662306a36Sopenharmony_ci	return 0;
122762306a36Sopenharmony_ci}
122862306a36Sopenharmony_ci
122962306a36Sopenharmony_cistatic int create_lkb(struct dlm_ls *ls, struct dlm_lkb **lkb_ret)
123062306a36Sopenharmony_ci{
123162306a36Sopenharmony_ci	return _create_lkb(ls, lkb_ret, 1, 0);
123262306a36Sopenharmony_ci}
123362306a36Sopenharmony_ci
123462306a36Sopenharmony_cistatic int find_lkb(struct dlm_ls *ls, uint32_t lkid, struct dlm_lkb **lkb_ret)
123562306a36Sopenharmony_ci{
123662306a36Sopenharmony_ci	struct dlm_lkb *lkb;
123762306a36Sopenharmony_ci
123862306a36Sopenharmony_ci	spin_lock(&ls->ls_lkbidr_spin);
123962306a36Sopenharmony_ci	lkb = idr_find(&ls->ls_lkbidr, lkid);
124062306a36Sopenharmony_ci	if (lkb)
124162306a36Sopenharmony_ci		kref_get(&lkb->lkb_ref);
124262306a36Sopenharmony_ci	spin_unlock(&ls->ls_lkbidr_spin);
124362306a36Sopenharmony_ci
124462306a36Sopenharmony_ci	*lkb_ret = lkb;
124562306a36Sopenharmony_ci	return lkb ? 0 : -ENOENT;
124662306a36Sopenharmony_ci}
124762306a36Sopenharmony_ci
124862306a36Sopenharmony_cistatic void kill_lkb(struct kref *kref)
124962306a36Sopenharmony_ci{
125062306a36Sopenharmony_ci	struct dlm_lkb *lkb = container_of(kref, struct dlm_lkb, lkb_ref);
125162306a36Sopenharmony_ci
125262306a36Sopenharmony_ci	/* All work is done after the return from kref_put() so we
125362306a36Sopenharmony_ci	   can release the write_lock before the detach_lkb */
125462306a36Sopenharmony_ci
125562306a36Sopenharmony_ci	DLM_ASSERT(!lkb->lkb_status, dlm_print_lkb(lkb););
125662306a36Sopenharmony_ci}
125762306a36Sopenharmony_ci
125862306a36Sopenharmony_ci/* __put_lkb() is used when an lkb may not have an rsb attached to
125962306a36Sopenharmony_ci   it so we need to provide the lockspace explicitly */
126062306a36Sopenharmony_ci
126162306a36Sopenharmony_cistatic int __put_lkb(struct dlm_ls *ls, struct dlm_lkb *lkb)
126262306a36Sopenharmony_ci{
126362306a36Sopenharmony_ci	uint32_t lkid = lkb->lkb_id;
126462306a36Sopenharmony_ci	int rv;
126562306a36Sopenharmony_ci
126662306a36Sopenharmony_ci	rv = kref_put_lock(&lkb->lkb_ref, kill_lkb,
126762306a36Sopenharmony_ci			   &ls->ls_lkbidr_spin);
126862306a36Sopenharmony_ci	if (rv) {
126962306a36Sopenharmony_ci		idr_remove(&ls->ls_lkbidr, lkid);
127062306a36Sopenharmony_ci		spin_unlock(&ls->ls_lkbidr_spin);
127162306a36Sopenharmony_ci
127262306a36Sopenharmony_ci		detach_lkb(lkb);
127362306a36Sopenharmony_ci
127462306a36Sopenharmony_ci		/* for local/process lkbs, lvbptr points to caller's lksb */
127562306a36Sopenharmony_ci		if (lkb->lkb_lvbptr && is_master_copy(lkb))
127662306a36Sopenharmony_ci			dlm_free_lvb(lkb->lkb_lvbptr);
127762306a36Sopenharmony_ci		dlm_free_lkb(lkb);
127862306a36Sopenharmony_ci	}
127962306a36Sopenharmony_ci
128062306a36Sopenharmony_ci	return rv;
128162306a36Sopenharmony_ci}
128262306a36Sopenharmony_ci
128362306a36Sopenharmony_ciint dlm_put_lkb(struct dlm_lkb *lkb)
128462306a36Sopenharmony_ci{
128562306a36Sopenharmony_ci	struct dlm_ls *ls;
128662306a36Sopenharmony_ci
128762306a36Sopenharmony_ci	DLM_ASSERT(lkb->lkb_resource, dlm_print_lkb(lkb););
128862306a36Sopenharmony_ci	DLM_ASSERT(lkb->lkb_resource->res_ls, dlm_print_lkb(lkb););
128962306a36Sopenharmony_ci
129062306a36Sopenharmony_ci	ls = lkb->lkb_resource->res_ls;
129162306a36Sopenharmony_ci	return __put_lkb(ls, lkb);
129262306a36Sopenharmony_ci}
129362306a36Sopenharmony_ci
129462306a36Sopenharmony_ci/* This is only called to add a reference when the code already holds
129562306a36Sopenharmony_ci   a valid reference to the lkb, so there's no need for locking. */
129662306a36Sopenharmony_ci
129762306a36Sopenharmony_cistatic inline void hold_lkb(struct dlm_lkb *lkb)
129862306a36Sopenharmony_ci{
129962306a36Sopenharmony_ci	kref_get(&lkb->lkb_ref);
130062306a36Sopenharmony_ci}
130162306a36Sopenharmony_ci
130262306a36Sopenharmony_cistatic void unhold_lkb_assert(struct kref *kref)
130362306a36Sopenharmony_ci{
130462306a36Sopenharmony_ci	struct dlm_lkb *lkb = container_of(kref, struct dlm_lkb, lkb_ref);
130562306a36Sopenharmony_ci
130662306a36Sopenharmony_ci	DLM_ASSERT(false, dlm_print_lkb(lkb););
130762306a36Sopenharmony_ci}
130862306a36Sopenharmony_ci
130962306a36Sopenharmony_ci/* This is called when we need to remove a reference and are certain
131062306a36Sopenharmony_ci   it's not the last ref.  e.g. del_lkb is always called between a
131162306a36Sopenharmony_ci   find_lkb/put_lkb and is always the inverse of a previous add_lkb.
131262306a36Sopenharmony_ci   put_lkb would work fine, but would involve unnecessary locking */
131362306a36Sopenharmony_ci
131462306a36Sopenharmony_cistatic inline void unhold_lkb(struct dlm_lkb *lkb)
131562306a36Sopenharmony_ci{
131662306a36Sopenharmony_ci	kref_put(&lkb->lkb_ref, unhold_lkb_assert);
131762306a36Sopenharmony_ci}
131862306a36Sopenharmony_ci
131962306a36Sopenharmony_cistatic void lkb_add_ordered(struct list_head *new, struct list_head *head,
132062306a36Sopenharmony_ci			    int mode)
132162306a36Sopenharmony_ci{
132262306a36Sopenharmony_ci	struct dlm_lkb *lkb = NULL, *iter;
132362306a36Sopenharmony_ci
132462306a36Sopenharmony_ci	list_for_each_entry(iter, head, lkb_statequeue)
132562306a36Sopenharmony_ci		if (iter->lkb_rqmode < mode) {
132662306a36Sopenharmony_ci			lkb = iter;
132762306a36Sopenharmony_ci			list_add_tail(new, &iter->lkb_statequeue);
132862306a36Sopenharmony_ci			break;
132962306a36Sopenharmony_ci		}
133062306a36Sopenharmony_ci
133162306a36Sopenharmony_ci	if (!lkb)
133262306a36Sopenharmony_ci		list_add_tail(new, head);
133362306a36Sopenharmony_ci}
133462306a36Sopenharmony_ci
133562306a36Sopenharmony_ci/* add/remove lkb to rsb's grant/convert/wait queue */
133662306a36Sopenharmony_ci
133762306a36Sopenharmony_cistatic void add_lkb(struct dlm_rsb *r, struct dlm_lkb *lkb, int status)
133862306a36Sopenharmony_ci{
133962306a36Sopenharmony_ci	kref_get(&lkb->lkb_ref);
134062306a36Sopenharmony_ci
134162306a36Sopenharmony_ci	DLM_ASSERT(!lkb->lkb_status, dlm_print_lkb(lkb););
134262306a36Sopenharmony_ci
134362306a36Sopenharmony_ci	lkb->lkb_timestamp = ktime_get();
134462306a36Sopenharmony_ci
134562306a36Sopenharmony_ci	lkb->lkb_status = status;
134662306a36Sopenharmony_ci
134762306a36Sopenharmony_ci	switch (status) {
134862306a36Sopenharmony_ci	case DLM_LKSTS_WAITING:
134962306a36Sopenharmony_ci		if (lkb->lkb_exflags & DLM_LKF_HEADQUE)
135062306a36Sopenharmony_ci			list_add(&lkb->lkb_statequeue, &r->res_waitqueue);
135162306a36Sopenharmony_ci		else
135262306a36Sopenharmony_ci			list_add_tail(&lkb->lkb_statequeue, &r->res_waitqueue);
135362306a36Sopenharmony_ci		break;
135462306a36Sopenharmony_ci	case DLM_LKSTS_GRANTED:
135562306a36Sopenharmony_ci		/* convention says granted locks kept in order of grmode */
135662306a36Sopenharmony_ci		lkb_add_ordered(&lkb->lkb_statequeue, &r->res_grantqueue,
135762306a36Sopenharmony_ci				lkb->lkb_grmode);
135862306a36Sopenharmony_ci		break;
135962306a36Sopenharmony_ci	case DLM_LKSTS_CONVERT:
136062306a36Sopenharmony_ci		if (lkb->lkb_exflags & DLM_LKF_HEADQUE)
136162306a36Sopenharmony_ci			list_add(&lkb->lkb_statequeue, &r->res_convertqueue);
136262306a36Sopenharmony_ci		else
136362306a36Sopenharmony_ci			list_add_tail(&lkb->lkb_statequeue,
136462306a36Sopenharmony_ci				      &r->res_convertqueue);
136562306a36Sopenharmony_ci		break;
136662306a36Sopenharmony_ci	default:
136762306a36Sopenharmony_ci		DLM_ASSERT(0, dlm_print_lkb(lkb); printk("sts=%d\n", status););
136862306a36Sopenharmony_ci	}
136962306a36Sopenharmony_ci}
137062306a36Sopenharmony_ci
137162306a36Sopenharmony_cistatic void del_lkb(struct dlm_rsb *r, struct dlm_lkb *lkb)
137262306a36Sopenharmony_ci{
137362306a36Sopenharmony_ci	lkb->lkb_status = 0;
137462306a36Sopenharmony_ci	list_del(&lkb->lkb_statequeue);
137562306a36Sopenharmony_ci	unhold_lkb(lkb);
137662306a36Sopenharmony_ci}
137762306a36Sopenharmony_ci
137862306a36Sopenharmony_cistatic void move_lkb(struct dlm_rsb *r, struct dlm_lkb *lkb, int sts)
137962306a36Sopenharmony_ci{
138062306a36Sopenharmony_ci	hold_lkb(lkb);
138162306a36Sopenharmony_ci	del_lkb(r, lkb);
138262306a36Sopenharmony_ci	add_lkb(r, lkb, sts);
138362306a36Sopenharmony_ci	unhold_lkb(lkb);
138462306a36Sopenharmony_ci}
138562306a36Sopenharmony_ci
138662306a36Sopenharmony_cistatic int msg_reply_type(int mstype)
138762306a36Sopenharmony_ci{
138862306a36Sopenharmony_ci	switch (mstype) {
138962306a36Sopenharmony_ci	case DLM_MSG_REQUEST:
139062306a36Sopenharmony_ci		return DLM_MSG_REQUEST_REPLY;
139162306a36Sopenharmony_ci	case DLM_MSG_CONVERT:
139262306a36Sopenharmony_ci		return DLM_MSG_CONVERT_REPLY;
139362306a36Sopenharmony_ci	case DLM_MSG_UNLOCK:
139462306a36Sopenharmony_ci		return DLM_MSG_UNLOCK_REPLY;
139562306a36Sopenharmony_ci	case DLM_MSG_CANCEL:
139662306a36Sopenharmony_ci		return DLM_MSG_CANCEL_REPLY;
139762306a36Sopenharmony_ci	case DLM_MSG_LOOKUP:
139862306a36Sopenharmony_ci		return DLM_MSG_LOOKUP_REPLY;
139962306a36Sopenharmony_ci	}
140062306a36Sopenharmony_ci	return -1;
140162306a36Sopenharmony_ci}
140262306a36Sopenharmony_ci
140362306a36Sopenharmony_ci/* add/remove lkb from global waiters list of lkb's waiting for
140462306a36Sopenharmony_ci   a reply from a remote node */
140562306a36Sopenharmony_ci
140662306a36Sopenharmony_cistatic int add_to_waiters(struct dlm_lkb *lkb, int mstype, int to_nodeid)
140762306a36Sopenharmony_ci{
140862306a36Sopenharmony_ci	struct dlm_ls *ls = lkb->lkb_resource->res_ls;
140962306a36Sopenharmony_ci	int error = 0;
141062306a36Sopenharmony_ci	int wc;
141162306a36Sopenharmony_ci
141262306a36Sopenharmony_ci	mutex_lock(&ls->ls_waiters_mutex);
141362306a36Sopenharmony_ci
141462306a36Sopenharmony_ci	if (is_overlap_unlock(lkb) ||
141562306a36Sopenharmony_ci	    (is_overlap_cancel(lkb) && (mstype == DLM_MSG_CANCEL))) {
141662306a36Sopenharmony_ci		error = -EINVAL;
141762306a36Sopenharmony_ci		goto out;
141862306a36Sopenharmony_ci	}
141962306a36Sopenharmony_ci
142062306a36Sopenharmony_ci	if (lkb->lkb_wait_type || is_overlap_cancel(lkb)) {
142162306a36Sopenharmony_ci		switch (mstype) {
142262306a36Sopenharmony_ci		case DLM_MSG_UNLOCK:
142362306a36Sopenharmony_ci			set_bit(DLM_IFL_OVERLAP_UNLOCK_BIT, &lkb->lkb_iflags);
142462306a36Sopenharmony_ci			break;
142562306a36Sopenharmony_ci		case DLM_MSG_CANCEL:
142662306a36Sopenharmony_ci			set_bit(DLM_IFL_OVERLAP_CANCEL_BIT, &lkb->lkb_iflags);
142762306a36Sopenharmony_ci			break;
142862306a36Sopenharmony_ci		default:
142962306a36Sopenharmony_ci			error = -EBUSY;
143062306a36Sopenharmony_ci			goto out;
143162306a36Sopenharmony_ci		}
143262306a36Sopenharmony_ci		wc = atomic_inc_return(&lkb->lkb_wait_count);
143362306a36Sopenharmony_ci		hold_lkb(lkb);
143462306a36Sopenharmony_ci
143562306a36Sopenharmony_ci		log_debug(ls, "addwait %x cur %d overlap %d count %d f %x",
143662306a36Sopenharmony_ci			  lkb->lkb_id, lkb->lkb_wait_type, mstype, wc,
143762306a36Sopenharmony_ci			  dlm_iflags_val(lkb));
143862306a36Sopenharmony_ci		goto out;
143962306a36Sopenharmony_ci	}
144062306a36Sopenharmony_ci
144162306a36Sopenharmony_ci	wc = atomic_fetch_inc(&lkb->lkb_wait_count);
144262306a36Sopenharmony_ci	DLM_ASSERT(!wc, dlm_print_lkb(lkb); printk("wait_count %d\n", wc););
144362306a36Sopenharmony_ci	lkb->lkb_wait_type = mstype;
144462306a36Sopenharmony_ci	lkb->lkb_wait_nodeid = to_nodeid; /* for debugging */
144562306a36Sopenharmony_ci	hold_lkb(lkb);
144662306a36Sopenharmony_ci	list_add(&lkb->lkb_wait_reply, &ls->ls_waiters);
144762306a36Sopenharmony_ci out:
144862306a36Sopenharmony_ci	if (error)
144962306a36Sopenharmony_ci		log_error(ls, "addwait error %x %d flags %x %d %d %s",
145062306a36Sopenharmony_ci			  lkb->lkb_id, error, dlm_iflags_val(lkb), mstype,
145162306a36Sopenharmony_ci			  lkb->lkb_wait_type, lkb->lkb_resource->res_name);
145262306a36Sopenharmony_ci	mutex_unlock(&ls->ls_waiters_mutex);
145362306a36Sopenharmony_ci	return error;
145462306a36Sopenharmony_ci}
145562306a36Sopenharmony_ci
145662306a36Sopenharmony_ci/* We clear the RESEND flag because we might be taking an lkb off the waiters
145762306a36Sopenharmony_ci   list as part of process_requestqueue (e.g. a lookup that has an optimized
145862306a36Sopenharmony_ci   request reply on the requestqueue) between dlm_recover_waiters_pre() which
145962306a36Sopenharmony_ci   set RESEND and dlm_recover_waiters_post() */
146062306a36Sopenharmony_ci
146162306a36Sopenharmony_cistatic int _remove_from_waiters(struct dlm_lkb *lkb, int mstype,
146262306a36Sopenharmony_ci				const struct dlm_message *ms)
146362306a36Sopenharmony_ci{
146462306a36Sopenharmony_ci	struct dlm_ls *ls = lkb->lkb_resource->res_ls;
146562306a36Sopenharmony_ci	int overlap_done = 0;
146662306a36Sopenharmony_ci
146762306a36Sopenharmony_ci	if (mstype == DLM_MSG_UNLOCK_REPLY &&
146862306a36Sopenharmony_ci	    test_and_clear_bit(DLM_IFL_OVERLAP_UNLOCK_BIT, &lkb->lkb_iflags)) {
146962306a36Sopenharmony_ci		log_debug(ls, "remwait %x unlock_reply overlap", lkb->lkb_id);
147062306a36Sopenharmony_ci		overlap_done = 1;
147162306a36Sopenharmony_ci		goto out_del;
147262306a36Sopenharmony_ci	}
147362306a36Sopenharmony_ci
147462306a36Sopenharmony_ci	if (mstype == DLM_MSG_CANCEL_REPLY &&
147562306a36Sopenharmony_ci	    test_and_clear_bit(DLM_IFL_OVERLAP_CANCEL_BIT, &lkb->lkb_iflags)) {
147662306a36Sopenharmony_ci		log_debug(ls, "remwait %x cancel_reply overlap", lkb->lkb_id);
147762306a36Sopenharmony_ci		overlap_done = 1;
147862306a36Sopenharmony_ci		goto out_del;
147962306a36Sopenharmony_ci	}
148062306a36Sopenharmony_ci
148162306a36Sopenharmony_ci	/* Cancel state was preemptively cleared by a successful convert,
148262306a36Sopenharmony_ci	   see next comment, nothing to do. */
148362306a36Sopenharmony_ci
148462306a36Sopenharmony_ci	if ((mstype == DLM_MSG_CANCEL_REPLY) &&
148562306a36Sopenharmony_ci	    (lkb->lkb_wait_type != DLM_MSG_CANCEL)) {
148662306a36Sopenharmony_ci		log_debug(ls, "remwait %x cancel_reply wait_type %d",
148762306a36Sopenharmony_ci			  lkb->lkb_id, lkb->lkb_wait_type);
148862306a36Sopenharmony_ci		return -1;
148962306a36Sopenharmony_ci	}
149062306a36Sopenharmony_ci
149162306a36Sopenharmony_ci	/* Remove for the convert reply, and premptively remove for the
149262306a36Sopenharmony_ci	   cancel reply.  A convert has been granted while there's still
149362306a36Sopenharmony_ci	   an outstanding cancel on it (the cancel is moot and the result
149462306a36Sopenharmony_ci	   in the cancel reply should be 0).  We preempt the cancel reply
149562306a36Sopenharmony_ci	   because the app gets the convert result and then can follow up
149662306a36Sopenharmony_ci	   with another op, like convert.  This subsequent op would see the
149762306a36Sopenharmony_ci	   lingering state of the cancel and fail with -EBUSY. */
149862306a36Sopenharmony_ci
149962306a36Sopenharmony_ci	if ((mstype == DLM_MSG_CONVERT_REPLY) &&
150062306a36Sopenharmony_ci	    (lkb->lkb_wait_type == DLM_MSG_CONVERT) && ms && !ms->m_result &&
150162306a36Sopenharmony_ci	    test_and_clear_bit(DLM_IFL_OVERLAP_CANCEL_BIT, &lkb->lkb_iflags)) {
150262306a36Sopenharmony_ci		log_debug(ls, "remwait %x convert_reply zap overlap_cancel",
150362306a36Sopenharmony_ci			  lkb->lkb_id);
150462306a36Sopenharmony_ci		lkb->lkb_wait_type = 0;
150562306a36Sopenharmony_ci		atomic_dec(&lkb->lkb_wait_count);
150662306a36Sopenharmony_ci		unhold_lkb(lkb);
150762306a36Sopenharmony_ci		goto out_del;
150862306a36Sopenharmony_ci	}
150962306a36Sopenharmony_ci
151062306a36Sopenharmony_ci	/* N.B. type of reply may not always correspond to type of original
151162306a36Sopenharmony_ci	   msg due to lookup->request optimization, verify others? */
151262306a36Sopenharmony_ci
151362306a36Sopenharmony_ci	if (lkb->lkb_wait_type) {
151462306a36Sopenharmony_ci		lkb->lkb_wait_type = 0;
151562306a36Sopenharmony_ci		goto out_del;
151662306a36Sopenharmony_ci	}
151762306a36Sopenharmony_ci
151862306a36Sopenharmony_ci	log_error(ls, "remwait error %x remote %d %x msg %d flags %x no wait",
151962306a36Sopenharmony_ci		  lkb->lkb_id, ms ? le32_to_cpu(ms->m_header.h_nodeid) : 0,
152062306a36Sopenharmony_ci		  lkb->lkb_remid, mstype, dlm_iflags_val(lkb));
152162306a36Sopenharmony_ci	return -1;
152262306a36Sopenharmony_ci
152362306a36Sopenharmony_ci out_del:
152462306a36Sopenharmony_ci	/* the force-unlock/cancel has completed and we haven't recvd a reply
152562306a36Sopenharmony_ci	   to the op that was in progress prior to the unlock/cancel; we
152662306a36Sopenharmony_ci	   give up on any reply to the earlier op.  FIXME: not sure when/how
152762306a36Sopenharmony_ci	   this would happen */
152862306a36Sopenharmony_ci
152962306a36Sopenharmony_ci	if (overlap_done && lkb->lkb_wait_type) {
153062306a36Sopenharmony_ci		log_error(ls, "remwait error %x reply %d wait_type %d overlap",
153162306a36Sopenharmony_ci			  lkb->lkb_id, mstype, lkb->lkb_wait_type);
153262306a36Sopenharmony_ci		atomic_dec(&lkb->lkb_wait_count);
153362306a36Sopenharmony_ci		unhold_lkb(lkb);
153462306a36Sopenharmony_ci		lkb->lkb_wait_type = 0;
153562306a36Sopenharmony_ci	}
153662306a36Sopenharmony_ci
153762306a36Sopenharmony_ci	DLM_ASSERT(atomic_read(&lkb->lkb_wait_count), dlm_print_lkb(lkb););
153862306a36Sopenharmony_ci
153962306a36Sopenharmony_ci	clear_bit(DLM_IFL_RESEND_BIT, &lkb->lkb_iflags);
154062306a36Sopenharmony_ci	if (atomic_dec_and_test(&lkb->lkb_wait_count))
154162306a36Sopenharmony_ci		list_del_init(&lkb->lkb_wait_reply);
154262306a36Sopenharmony_ci	unhold_lkb(lkb);
154362306a36Sopenharmony_ci	return 0;
154462306a36Sopenharmony_ci}
154562306a36Sopenharmony_ci
154662306a36Sopenharmony_cistatic int remove_from_waiters(struct dlm_lkb *lkb, int mstype)
154762306a36Sopenharmony_ci{
154862306a36Sopenharmony_ci	struct dlm_ls *ls = lkb->lkb_resource->res_ls;
154962306a36Sopenharmony_ci	int error;
155062306a36Sopenharmony_ci
155162306a36Sopenharmony_ci	mutex_lock(&ls->ls_waiters_mutex);
155262306a36Sopenharmony_ci	error = _remove_from_waiters(lkb, mstype, NULL);
155362306a36Sopenharmony_ci	mutex_unlock(&ls->ls_waiters_mutex);
155462306a36Sopenharmony_ci	return error;
155562306a36Sopenharmony_ci}
155662306a36Sopenharmony_ci
155762306a36Sopenharmony_ci/* Handles situations where we might be processing a "fake" or "local" reply in
155862306a36Sopenharmony_ci   which we can't try to take waiters_mutex again. */
155962306a36Sopenharmony_ci
156062306a36Sopenharmony_cistatic int remove_from_waiters_ms(struct dlm_lkb *lkb,
156162306a36Sopenharmony_ci				  const struct dlm_message *ms, bool local)
156262306a36Sopenharmony_ci{
156362306a36Sopenharmony_ci	struct dlm_ls *ls = lkb->lkb_resource->res_ls;
156462306a36Sopenharmony_ci	int error;
156562306a36Sopenharmony_ci
156662306a36Sopenharmony_ci	if (!local)
156762306a36Sopenharmony_ci		mutex_lock(&ls->ls_waiters_mutex);
156862306a36Sopenharmony_ci	error = _remove_from_waiters(lkb, le32_to_cpu(ms->m_type), ms);
156962306a36Sopenharmony_ci	if (!local)
157062306a36Sopenharmony_ci		mutex_unlock(&ls->ls_waiters_mutex);
157162306a36Sopenharmony_ci	return error;
157262306a36Sopenharmony_ci}
157362306a36Sopenharmony_ci
157462306a36Sopenharmony_cistatic void shrink_bucket(struct dlm_ls *ls, int b)
157562306a36Sopenharmony_ci{
157662306a36Sopenharmony_ci	struct rb_node *n, *next;
157762306a36Sopenharmony_ci	struct dlm_rsb *r;
157862306a36Sopenharmony_ci	char *name;
157962306a36Sopenharmony_ci	int our_nodeid = dlm_our_nodeid();
158062306a36Sopenharmony_ci	int remote_count = 0;
158162306a36Sopenharmony_ci	int need_shrink = 0;
158262306a36Sopenharmony_ci	int i, len, rv;
158362306a36Sopenharmony_ci
158462306a36Sopenharmony_ci	memset(&ls->ls_remove_lens, 0, sizeof(int) * DLM_REMOVE_NAMES_MAX);
158562306a36Sopenharmony_ci
158662306a36Sopenharmony_ci	spin_lock(&ls->ls_rsbtbl[b].lock);
158762306a36Sopenharmony_ci
158862306a36Sopenharmony_ci	if (!test_bit(DLM_RTF_SHRINK_BIT, &ls->ls_rsbtbl[b].flags)) {
158962306a36Sopenharmony_ci		spin_unlock(&ls->ls_rsbtbl[b].lock);
159062306a36Sopenharmony_ci		return;
159162306a36Sopenharmony_ci	}
159262306a36Sopenharmony_ci
159362306a36Sopenharmony_ci	for (n = rb_first(&ls->ls_rsbtbl[b].toss); n; n = next) {
159462306a36Sopenharmony_ci		next = rb_next(n);
159562306a36Sopenharmony_ci		r = rb_entry(n, struct dlm_rsb, res_hashnode);
159662306a36Sopenharmony_ci
159762306a36Sopenharmony_ci		/* If we're the directory record for this rsb, and
159862306a36Sopenharmony_ci		   we're not the master of it, then we need to wait
159962306a36Sopenharmony_ci		   for the master node to send us a dir remove for
160062306a36Sopenharmony_ci		   before removing the dir record. */
160162306a36Sopenharmony_ci
160262306a36Sopenharmony_ci		if (!dlm_no_directory(ls) &&
160362306a36Sopenharmony_ci		    (r->res_master_nodeid != our_nodeid) &&
160462306a36Sopenharmony_ci		    (dlm_dir_nodeid(r) == our_nodeid)) {
160562306a36Sopenharmony_ci			continue;
160662306a36Sopenharmony_ci		}
160762306a36Sopenharmony_ci
160862306a36Sopenharmony_ci		need_shrink = 1;
160962306a36Sopenharmony_ci
161062306a36Sopenharmony_ci		if (!time_after_eq(jiffies, r->res_toss_time +
161162306a36Sopenharmony_ci				   dlm_config.ci_toss_secs * HZ)) {
161262306a36Sopenharmony_ci			continue;
161362306a36Sopenharmony_ci		}
161462306a36Sopenharmony_ci
161562306a36Sopenharmony_ci		if (!dlm_no_directory(ls) &&
161662306a36Sopenharmony_ci		    (r->res_master_nodeid == our_nodeid) &&
161762306a36Sopenharmony_ci		    (dlm_dir_nodeid(r) != our_nodeid)) {
161862306a36Sopenharmony_ci
161962306a36Sopenharmony_ci			/* We're the master of this rsb but we're not
162062306a36Sopenharmony_ci			   the directory record, so we need to tell the
162162306a36Sopenharmony_ci			   dir node to remove the dir record. */
162262306a36Sopenharmony_ci
162362306a36Sopenharmony_ci			ls->ls_remove_lens[remote_count] = r->res_length;
162462306a36Sopenharmony_ci			memcpy(ls->ls_remove_names[remote_count], r->res_name,
162562306a36Sopenharmony_ci			       DLM_RESNAME_MAXLEN);
162662306a36Sopenharmony_ci			remote_count++;
162762306a36Sopenharmony_ci
162862306a36Sopenharmony_ci			if (remote_count >= DLM_REMOVE_NAMES_MAX)
162962306a36Sopenharmony_ci				break;
163062306a36Sopenharmony_ci			continue;
163162306a36Sopenharmony_ci		}
163262306a36Sopenharmony_ci
163362306a36Sopenharmony_ci		if (!kref_put(&r->res_ref, kill_rsb)) {
163462306a36Sopenharmony_ci			log_error(ls, "tossed rsb in use %s", r->res_name);
163562306a36Sopenharmony_ci			continue;
163662306a36Sopenharmony_ci		}
163762306a36Sopenharmony_ci
163862306a36Sopenharmony_ci		rb_erase(&r->res_hashnode, &ls->ls_rsbtbl[b].toss);
163962306a36Sopenharmony_ci		dlm_free_rsb(r);
164062306a36Sopenharmony_ci	}
164162306a36Sopenharmony_ci
164262306a36Sopenharmony_ci	if (need_shrink)
164362306a36Sopenharmony_ci		set_bit(DLM_RTF_SHRINK_BIT, &ls->ls_rsbtbl[b].flags);
164462306a36Sopenharmony_ci	else
164562306a36Sopenharmony_ci		clear_bit(DLM_RTF_SHRINK_BIT, &ls->ls_rsbtbl[b].flags);
164662306a36Sopenharmony_ci	spin_unlock(&ls->ls_rsbtbl[b].lock);
164762306a36Sopenharmony_ci
164862306a36Sopenharmony_ci	/*
164962306a36Sopenharmony_ci	 * While searching for rsb's to free, we found some that require
165062306a36Sopenharmony_ci	 * remote removal.  We leave them in place and find them again here
165162306a36Sopenharmony_ci	 * so there is a very small gap between removing them from the toss
165262306a36Sopenharmony_ci	 * list and sending the removal.  Keeping this gap small is
165362306a36Sopenharmony_ci	 * important to keep us (the master node) from being out of sync
165462306a36Sopenharmony_ci	 * with the remote dir node for very long.
165562306a36Sopenharmony_ci	 */
165662306a36Sopenharmony_ci
165762306a36Sopenharmony_ci	for (i = 0; i < remote_count; i++) {
165862306a36Sopenharmony_ci		name = ls->ls_remove_names[i];
165962306a36Sopenharmony_ci		len = ls->ls_remove_lens[i];
166062306a36Sopenharmony_ci
166162306a36Sopenharmony_ci		spin_lock(&ls->ls_rsbtbl[b].lock);
166262306a36Sopenharmony_ci		rv = dlm_search_rsb_tree(&ls->ls_rsbtbl[b].toss, name, len, &r);
166362306a36Sopenharmony_ci		if (rv) {
166462306a36Sopenharmony_ci			spin_unlock(&ls->ls_rsbtbl[b].lock);
166562306a36Sopenharmony_ci			log_debug(ls, "remove_name not toss %s", name);
166662306a36Sopenharmony_ci			continue;
166762306a36Sopenharmony_ci		}
166862306a36Sopenharmony_ci
166962306a36Sopenharmony_ci		if (r->res_master_nodeid != our_nodeid) {
167062306a36Sopenharmony_ci			spin_unlock(&ls->ls_rsbtbl[b].lock);
167162306a36Sopenharmony_ci			log_debug(ls, "remove_name master %d dir %d our %d %s",
167262306a36Sopenharmony_ci				  r->res_master_nodeid, r->res_dir_nodeid,
167362306a36Sopenharmony_ci				  our_nodeid, name);
167462306a36Sopenharmony_ci			continue;
167562306a36Sopenharmony_ci		}
167662306a36Sopenharmony_ci
167762306a36Sopenharmony_ci		if (r->res_dir_nodeid == our_nodeid) {
167862306a36Sopenharmony_ci			/* should never happen */
167962306a36Sopenharmony_ci			spin_unlock(&ls->ls_rsbtbl[b].lock);
168062306a36Sopenharmony_ci			log_error(ls, "remove_name dir %d master %d our %d %s",
168162306a36Sopenharmony_ci				  r->res_dir_nodeid, r->res_master_nodeid,
168262306a36Sopenharmony_ci				  our_nodeid, name);
168362306a36Sopenharmony_ci			continue;
168462306a36Sopenharmony_ci		}
168562306a36Sopenharmony_ci
168662306a36Sopenharmony_ci		if (!time_after_eq(jiffies, r->res_toss_time +
168762306a36Sopenharmony_ci				   dlm_config.ci_toss_secs * HZ)) {
168862306a36Sopenharmony_ci			spin_unlock(&ls->ls_rsbtbl[b].lock);
168962306a36Sopenharmony_ci			log_debug(ls, "remove_name toss_time %lu now %lu %s",
169062306a36Sopenharmony_ci				  r->res_toss_time, jiffies, name);
169162306a36Sopenharmony_ci			continue;
169262306a36Sopenharmony_ci		}
169362306a36Sopenharmony_ci
169462306a36Sopenharmony_ci		if (!kref_put(&r->res_ref, kill_rsb)) {
169562306a36Sopenharmony_ci			spin_unlock(&ls->ls_rsbtbl[b].lock);
169662306a36Sopenharmony_ci			log_error(ls, "remove_name in use %s", name);
169762306a36Sopenharmony_ci			continue;
169862306a36Sopenharmony_ci		}
169962306a36Sopenharmony_ci
170062306a36Sopenharmony_ci		rb_erase(&r->res_hashnode, &ls->ls_rsbtbl[b].toss);
170162306a36Sopenharmony_ci		send_remove(r);
170262306a36Sopenharmony_ci		spin_unlock(&ls->ls_rsbtbl[b].lock);
170362306a36Sopenharmony_ci
170462306a36Sopenharmony_ci		dlm_free_rsb(r);
170562306a36Sopenharmony_ci	}
170662306a36Sopenharmony_ci}
170762306a36Sopenharmony_ci
170862306a36Sopenharmony_civoid dlm_scan_rsbs(struct dlm_ls *ls)
170962306a36Sopenharmony_ci{
171062306a36Sopenharmony_ci	int i;
171162306a36Sopenharmony_ci
171262306a36Sopenharmony_ci	for (i = 0; i < ls->ls_rsbtbl_size; i++) {
171362306a36Sopenharmony_ci		shrink_bucket(ls, i);
171462306a36Sopenharmony_ci		if (dlm_locking_stopped(ls))
171562306a36Sopenharmony_ci			break;
171662306a36Sopenharmony_ci		cond_resched();
171762306a36Sopenharmony_ci	}
171862306a36Sopenharmony_ci}
171962306a36Sopenharmony_ci
172062306a36Sopenharmony_ci/* lkb is master or local copy */
172162306a36Sopenharmony_ci
172262306a36Sopenharmony_cistatic void set_lvb_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)
172362306a36Sopenharmony_ci{
172462306a36Sopenharmony_ci	int b, len = r->res_ls->ls_lvblen;
172562306a36Sopenharmony_ci
172662306a36Sopenharmony_ci	/* b=1 lvb returned to caller
172762306a36Sopenharmony_ci	   b=0 lvb written to rsb or invalidated
172862306a36Sopenharmony_ci	   b=-1 do nothing */
172962306a36Sopenharmony_ci
173062306a36Sopenharmony_ci	b =  dlm_lvb_operations[lkb->lkb_grmode + 1][lkb->lkb_rqmode + 1];
173162306a36Sopenharmony_ci
173262306a36Sopenharmony_ci	if (b == 1) {
173362306a36Sopenharmony_ci		if (!lkb->lkb_lvbptr)
173462306a36Sopenharmony_ci			return;
173562306a36Sopenharmony_ci
173662306a36Sopenharmony_ci		if (!(lkb->lkb_exflags & DLM_LKF_VALBLK))
173762306a36Sopenharmony_ci			return;
173862306a36Sopenharmony_ci
173962306a36Sopenharmony_ci		if (!r->res_lvbptr)
174062306a36Sopenharmony_ci			return;
174162306a36Sopenharmony_ci
174262306a36Sopenharmony_ci		memcpy(lkb->lkb_lvbptr, r->res_lvbptr, len);
174362306a36Sopenharmony_ci		lkb->lkb_lvbseq = r->res_lvbseq;
174462306a36Sopenharmony_ci
174562306a36Sopenharmony_ci	} else if (b == 0) {
174662306a36Sopenharmony_ci		if (lkb->lkb_exflags & DLM_LKF_IVVALBLK) {
174762306a36Sopenharmony_ci			rsb_set_flag(r, RSB_VALNOTVALID);
174862306a36Sopenharmony_ci			return;
174962306a36Sopenharmony_ci		}
175062306a36Sopenharmony_ci
175162306a36Sopenharmony_ci		if (!lkb->lkb_lvbptr)
175262306a36Sopenharmony_ci			return;
175362306a36Sopenharmony_ci
175462306a36Sopenharmony_ci		if (!(lkb->lkb_exflags & DLM_LKF_VALBLK))
175562306a36Sopenharmony_ci			return;
175662306a36Sopenharmony_ci
175762306a36Sopenharmony_ci		if (!r->res_lvbptr)
175862306a36Sopenharmony_ci			r->res_lvbptr = dlm_allocate_lvb(r->res_ls);
175962306a36Sopenharmony_ci
176062306a36Sopenharmony_ci		if (!r->res_lvbptr)
176162306a36Sopenharmony_ci			return;
176262306a36Sopenharmony_ci
176362306a36Sopenharmony_ci		memcpy(r->res_lvbptr, lkb->lkb_lvbptr, len);
176462306a36Sopenharmony_ci		r->res_lvbseq++;
176562306a36Sopenharmony_ci		lkb->lkb_lvbseq = r->res_lvbseq;
176662306a36Sopenharmony_ci		rsb_clear_flag(r, RSB_VALNOTVALID);
176762306a36Sopenharmony_ci	}
176862306a36Sopenharmony_ci
176962306a36Sopenharmony_ci	if (rsb_flag(r, RSB_VALNOTVALID))
177062306a36Sopenharmony_ci		set_bit(DLM_SBF_VALNOTVALID_BIT, &lkb->lkb_sbflags);
177162306a36Sopenharmony_ci}
177262306a36Sopenharmony_ci
177362306a36Sopenharmony_cistatic void set_lvb_unlock(struct dlm_rsb *r, struct dlm_lkb *lkb)
177462306a36Sopenharmony_ci{
177562306a36Sopenharmony_ci	if (lkb->lkb_grmode < DLM_LOCK_PW)
177662306a36Sopenharmony_ci		return;
177762306a36Sopenharmony_ci
177862306a36Sopenharmony_ci	if (lkb->lkb_exflags & DLM_LKF_IVVALBLK) {
177962306a36Sopenharmony_ci		rsb_set_flag(r, RSB_VALNOTVALID);
178062306a36Sopenharmony_ci		return;
178162306a36Sopenharmony_ci	}
178262306a36Sopenharmony_ci
178362306a36Sopenharmony_ci	if (!lkb->lkb_lvbptr)
178462306a36Sopenharmony_ci		return;
178562306a36Sopenharmony_ci
178662306a36Sopenharmony_ci	if (!(lkb->lkb_exflags & DLM_LKF_VALBLK))
178762306a36Sopenharmony_ci		return;
178862306a36Sopenharmony_ci
178962306a36Sopenharmony_ci	if (!r->res_lvbptr)
179062306a36Sopenharmony_ci		r->res_lvbptr = dlm_allocate_lvb(r->res_ls);
179162306a36Sopenharmony_ci
179262306a36Sopenharmony_ci	if (!r->res_lvbptr)
179362306a36Sopenharmony_ci		return;
179462306a36Sopenharmony_ci
179562306a36Sopenharmony_ci	memcpy(r->res_lvbptr, lkb->lkb_lvbptr, r->res_ls->ls_lvblen);
179662306a36Sopenharmony_ci	r->res_lvbseq++;
179762306a36Sopenharmony_ci	rsb_clear_flag(r, RSB_VALNOTVALID);
179862306a36Sopenharmony_ci}
179962306a36Sopenharmony_ci
180062306a36Sopenharmony_ci/* lkb is process copy (pc) */
180162306a36Sopenharmony_ci
180262306a36Sopenharmony_cistatic void set_lvb_lock_pc(struct dlm_rsb *r, struct dlm_lkb *lkb,
180362306a36Sopenharmony_ci			    const struct dlm_message *ms)
180462306a36Sopenharmony_ci{
180562306a36Sopenharmony_ci	int b;
180662306a36Sopenharmony_ci
180762306a36Sopenharmony_ci	if (!lkb->lkb_lvbptr)
180862306a36Sopenharmony_ci		return;
180962306a36Sopenharmony_ci
181062306a36Sopenharmony_ci	if (!(lkb->lkb_exflags & DLM_LKF_VALBLK))
181162306a36Sopenharmony_ci		return;
181262306a36Sopenharmony_ci
181362306a36Sopenharmony_ci	b = dlm_lvb_operations[lkb->lkb_grmode + 1][lkb->lkb_rqmode + 1];
181462306a36Sopenharmony_ci	if (b == 1) {
181562306a36Sopenharmony_ci		int len = receive_extralen(ms);
181662306a36Sopenharmony_ci		if (len > r->res_ls->ls_lvblen)
181762306a36Sopenharmony_ci			len = r->res_ls->ls_lvblen;
181862306a36Sopenharmony_ci		memcpy(lkb->lkb_lvbptr, ms->m_extra, len);
181962306a36Sopenharmony_ci		lkb->lkb_lvbseq = le32_to_cpu(ms->m_lvbseq);
182062306a36Sopenharmony_ci	}
182162306a36Sopenharmony_ci}
182262306a36Sopenharmony_ci
182362306a36Sopenharmony_ci/* Manipulate lkb's on rsb's convert/granted/waiting queues
182462306a36Sopenharmony_ci   remove_lock -- used for unlock, removes lkb from granted
182562306a36Sopenharmony_ci   revert_lock -- used for cancel, moves lkb from convert to granted
182662306a36Sopenharmony_ci   grant_lock  -- used for request and convert, adds lkb to granted or
182762306a36Sopenharmony_ci                  moves lkb from convert or waiting to granted
182862306a36Sopenharmony_ci
182962306a36Sopenharmony_ci   Each of these is used for master or local copy lkb's.  There is
183062306a36Sopenharmony_ci   also a _pc() variation used to make the corresponding change on
183162306a36Sopenharmony_ci   a process copy (pc) lkb. */
183262306a36Sopenharmony_ci
183362306a36Sopenharmony_cistatic void _remove_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)
183462306a36Sopenharmony_ci{
183562306a36Sopenharmony_ci	del_lkb(r, lkb);
183662306a36Sopenharmony_ci	lkb->lkb_grmode = DLM_LOCK_IV;
183762306a36Sopenharmony_ci	/* this unhold undoes the original ref from create_lkb()
183862306a36Sopenharmony_ci	   so this leads to the lkb being freed */
183962306a36Sopenharmony_ci	unhold_lkb(lkb);
184062306a36Sopenharmony_ci}
184162306a36Sopenharmony_ci
184262306a36Sopenharmony_cistatic void remove_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)
184362306a36Sopenharmony_ci{
184462306a36Sopenharmony_ci	set_lvb_unlock(r, lkb);
184562306a36Sopenharmony_ci	_remove_lock(r, lkb);
184662306a36Sopenharmony_ci}
184762306a36Sopenharmony_ci
184862306a36Sopenharmony_cistatic void remove_lock_pc(struct dlm_rsb *r, struct dlm_lkb *lkb)
184962306a36Sopenharmony_ci{
185062306a36Sopenharmony_ci	_remove_lock(r, lkb);
185162306a36Sopenharmony_ci}
185262306a36Sopenharmony_ci
185362306a36Sopenharmony_ci/* returns: 0 did nothing
185462306a36Sopenharmony_ci	    1 moved lock to granted
185562306a36Sopenharmony_ci	   -1 removed lock */
185662306a36Sopenharmony_ci
185762306a36Sopenharmony_cistatic int revert_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)
185862306a36Sopenharmony_ci{
185962306a36Sopenharmony_ci	int rv = 0;
186062306a36Sopenharmony_ci
186162306a36Sopenharmony_ci	lkb->lkb_rqmode = DLM_LOCK_IV;
186262306a36Sopenharmony_ci
186362306a36Sopenharmony_ci	switch (lkb->lkb_status) {
186462306a36Sopenharmony_ci	case DLM_LKSTS_GRANTED:
186562306a36Sopenharmony_ci		break;
186662306a36Sopenharmony_ci	case DLM_LKSTS_CONVERT:
186762306a36Sopenharmony_ci		move_lkb(r, lkb, DLM_LKSTS_GRANTED);
186862306a36Sopenharmony_ci		rv = 1;
186962306a36Sopenharmony_ci		break;
187062306a36Sopenharmony_ci	case DLM_LKSTS_WAITING:
187162306a36Sopenharmony_ci		del_lkb(r, lkb);
187262306a36Sopenharmony_ci		lkb->lkb_grmode = DLM_LOCK_IV;
187362306a36Sopenharmony_ci		/* this unhold undoes the original ref from create_lkb()
187462306a36Sopenharmony_ci		   so this leads to the lkb being freed */
187562306a36Sopenharmony_ci		unhold_lkb(lkb);
187662306a36Sopenharmony_ci		rv = -1;
187762306a36Sopenharmony_ci		break;
187862306a36Sopenharmony_ci	default:
187962306a36Sopenharmony_ci		log_print("invalid status for revert %d", lkb->lkb_status);
188062306a36Sopenharmony_ci	}
188162306a36Sopenharmony_ci	return rv;
188262306a36Sopenharmony_ci}
188362306a36Sopenharmony_ci
188462306a36Sopenharmony_cistatic int revert_lock_pc(struct dlm_rsb *r, struct dlm_lkb *lkb)
188562306a36Sopenharmony_ci{
188662306a36Sopenharmony_ci	return revert_lock(r, lkb);
188762306a36Sopenharmony_ci}
188862306a36Sopenharmony_ci
188962306a36Sopenharmony_cistatic void _grant_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)
189062306a36Sopenharmony_ci{
189162306a36Sopenharmony_ci	if (lkb->lkb_grmode != lkb->lkb_rqmode) {
189262306a36Sopenharmony_ci		lkb->lkb_grmode = lkb->lkb_rqmode;
189362306a36Sopenharmony_ci		if (lkb->lkb_status)
189462306a36Sopenharmony_ci			move_lkb(r, lkb, DLM_LKSTS_GRANTED);
189562306a36Sopenharmony_ci		else
189662306a36Sopenharmony_ci			add_lkb(r, lkb, DLM_LKSTS_GRANTED);
189762306a36Sopenharmony_ci	}
189862306a36Sopenharmony_ci
189962306a36Sopenharmony_ci	lkb->lkb_rqmode = DLM_LOCK_IV;
190062306a36Sopenharmony_ci	lkb->lkb_highbast = 0;
190162306a36Sopenharmony_ci}
190262306a36Sopenharmony_ci
190362306a36Sopenharmony_cistatic void grant_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)
190462306a36Sopenharmony_ci{
190562306a36Sopenharmony_ci	set_lvb_lock(r, lkb);
190662306a36Sopenharmony_ci	_grant_lock(r, lkb);
190762306a36Sopenharmony_ci}
190862306a36Sopenharmony_ci
190962306a36Sopenharmony_cistatic void grant_lock_pc(struct dlm_rsb *r, struct dlm_lkb *lkb,
191062306a36Sopenharmony_ci			  const struct dlm_message *ms)
191162306a36Sopenharmony_ci{
191262306a36Sopenharmony_ci	set_lvb_lock_pc(r, lkb, ms);
191362306a36Sopenharmony_ci	_grant_lock(r, lkb);
191462306a36Sopenharmony_ci}
191562306a36Sopenharmony_ci
191662306a36Sopenharmony_ci/* called by grant_pending_locks() which means an async grant message must
191762306a36Sopenharmony_ci   be sent to the requesting node in addition to granting the lock if the
191862306a36Sopenharmony_ci   lkb belongs to a remote node. */
191962306a36Sopenharmony_ci
192062306a36Sopenharmony_cistatic void grant_lock_pending(struct dlm_rsb *r, struct dlm_lkb *lkb)
192162306a36Sopenharmony_ci{
192262306a36Sopenharmony_ci	grant_lock(r, lkb);
192362306a36Sopenharmony_ci	if (is_master_copy(lkb))
192462306a36Sopenharmony_ci		send_grant(r, lkb);
192562306a36Sopenharmony_ci	else
192662306a36Sopenharmony_ci		queue_cast(r, lkb, 0);
192762306a36Sopenharmony_ci}
192862306a36Sopenharmony_ci
192962306a36Sopenharmony_ci/* The special CONVDEADLK, ALTPR and ALTCW flags allow the master to
193062306a36Sopenharmony_ci   change the granted/requested modes.  We're munging things accordingly in
193162306a36Sopenharmony_ci   the process copy.
193262306a36Sopenharmony_ci   CONVDEADLK: our grmode may have been forced down to NL to resolve a
193362306a36Sopenharmony_ci   conversion deadlock
193462306a36Sopenharmony_ci   ALTPR/ALTCW: our rqmode may have been changed to PR or CW to become
193562306a36Sopenharmony_ci   compatible with other granted locks */
193662306a36Sopenharmony_ci
193762306a36Sopenharmony_cistatic void munge_demoted(struct dlm_lkb *lkb)
193862306a36Sopenharmony_ci{
193962306a36Sopenharmony_ci	if (lkb->lkb_rqmode == DLM_LOCK_IV || lkb->lkb_grmode == DLM_LOCK_IV) {
194062306a36Sopenharmony_ci		log_print("munge_demoted %x invalid modes gr %d rq %d",
194162306a36Sopenharmony_ci			  lkb->lkb_id, lkb->lkb_grmode, lkb->lkb_rqmode);
194262306a36Sopenharmony_ci		return;
194362306a36Sopenharmony_ci	}
194462306a36Sopenharmony_ci
194562306a36Sopenharmony_ci	lkb->lkb_grmode = DLM_LOCK_NL;
194662306a36Sopenharmony_ci}
194762306a36Sopenharmony_ci
194862306a36Sopenharmony_cistatic void munge_altmode(struct dlm_lkb *lkb, const struct dlm_message *ms)
194962306a36Sopenharmony_ci{
195062306a36Sopenharmony_ci	if (ms->m_type != cpu_to_le32(DLM_MSG_REQUEST_REPLY) &&
195162306a36Sopenharmony_ci	    ms->m_type != cpu_to_le32(DLM_MSG_GRANT)) {
195262306a36Sopenharmony_ci		log_print("munge_altmode %x invalid reply type %d",
195362306a36Sopenharmony_ci			  lkb->lkb_id, le32_to_cpu(ms->m_type));
195462306a36Sopenharmony_ci		return;
195562306a36Sopenharmony_ci	}
195662306a36Sopenharmony_ci
195762306a36Sopenharmony_ci	if (lkb->lkb_exflags & DLM_LKF_ALTPR)
195862306a36Sopenharmony_ci		lkb->lkb_rqmode = DLM_LOCK_PR;
195962306a36Sopenharmony_ci	else if (lkb->lkb_exflags & DLM_LKF_ALTCW)
196062306a36Sopenharmony_ci		lkb->lkb_rqmode = DLM_LOCK_CW;
196162306a36Sopenharmony_ci	else {
196262306a36Sopenharmony_ci		log_print("munge_altmode invalid exflags %x", lkb->lkb_exflags);
196362306a36Sopenharmony_ci		dlm_print_lkb(lkb);
196462306a36Sopenharmony_ci	}
196562306a36Sopenharmony_ci}
196662306a36Sopenharmony_ci
196762306a36Sopenharmony_cistatic inline int first_in_list(struct dlm_lkb *lkb, struct list_head *head)
196862306a36Sopenharmony_ci{
196962306a36Sopenharmony_ci	struct dlm_lkb *first = list_entry(head->next, struct dlm_lkb,
197062306a36Sopenharmony_ci					   lkb_statequeue);
197162306a36Sopenharmony_ci	if (lkb->lkb_id == first->lkb_id)
197262306a36Sopenharmony_ci		return 1;
197362306a36Sopenharmony_ci
197462306a36Sopenharmony_ci	return 0;
197562306a36Sopenharmony_ci}
197662306a36Sopenharmony_ci
197762306a36Sopenharmony_ci/* Check if the given lkb conflicts with another lkb on the queue. */
197862306a36Sopenharmony_ci
197962306a36Sopenharmony_cistatic int queue_conflict(struct list_head *head, struct dlm_lkb *lkb)
198062306a36Sopenharmony_ci{
198162306a36Sopenharmony_ci	struct dlm_lkb *this;
198262306a36Sopenharmony_ci
198362306a36Sopenharmony_ci	list_for_each_entry(this, head, lkb_statequeue) {
198462306a36Sopenharmony_ci		if (this == lkb)
198562306a36Sopenharmony_ci			continue;
198662306a36Sopenharmony_ci		if (!modes_compat(this, lkb))
198762306a36Sopenharmony_ci			return 1;
198862306a36Sopenharmony_ci	}
198962306a36Sopenharmony_ci	return 0;
199062306a36Sopenharmony_ci}
199162306a36Sopenharmony_ci
199262306a36Sopenharmony_ci/*
199362306a36Sopenharmony_ci * "A conversion deadlock arises with a pair of lock requests in the converting
199462306a36Sopenharmony_ci * queue for one resource.  The granted mode of each lock blocks the requested
199562306a36Sopenharmony_ci * mode of the other lock."
199662306a36Sopenharmony_ci *
199762306a36Sopenharmony_ci * Part 2: if the granted mode of lkb is preventing an earlier lkb in the
199862306a36Sopenharmony_ci * convert queue from being granted, then deadlk/demote lkb.
199962306a36Sopenharmony_ci *
200062306a36Sopenharmony_ci * Example:
200162306a36Sopenharmony_ci * Granted Queue: empty
200262306a36Sopenharmony_ci * Convert Queue: NL->EX (first lock)
200362306a36Sopenharmony_ci *                PR->EX (second lock)
200462306a36Sopenharmony_ci *
200562306a36Sopenharmony_ci * The first lock can't be granted because of the granted mode of the second
200662306a36Sopenharmony_ci * lock and the second lock can't be granted because it's not first in the
200762306a36Sopenharmony_ci * list.  We either cancel lkb's conversion (PR->EX) and return EDEADLK, or we
200862306a36Sopenharmony_ci * demote the granted mode of lkb (from PR to NL) if it has the CONVDEADLK
200962306a36Sopenharmony_ci * flag set and return DEMOTED in the lksb flags.
201062306a36Sopenharmony_ci *
201162306a36Sopenharmony_ci * Originally, this function detected conv-deadlk in a more limited scope:
201262306a36Sopenharmony_ci * - if !modes_compat(lkb1, lkb2) && !modes_compat(lkb2, lkb1), or
201362306a36Sopenharmony_ci * - if lkb1 was the first entry in the queue (not just earlier), and was
201462306a36Sopenharmony_ci *   blocked by the granted mode of lkb2, and there was nothing on the
201562306a36Sopenharmony_ci *   granted queue preventing lkb1 from being granted immediately, i.e.
201662306a36Sopenharmony_ci *   lkb2 was the only thing preventing lkb1 from being granted.
201762306a36Sopenharmony_ci *
201862306a36Sopenharmony_ci * That second condition meant we'd only say there was conv-deadlk if
201962306a36Sopenharmony_ci * resolving it (by demotion) would lead to the first lock on the convert
202062306a36Sopenharmony_ci * queue being granted right away.  It allowed conversion deadlocks to exist
202162306a36Sopenharmony_ci * between locks on the convert queue while they couldn't be granted anyway.
202262306a36Sopenharmony_ci *
202362306a36Sopenharmony_ci * Now, we detect and take action on conversion deadlocks immediately when
202462306a36Sopenharmony_ci * they're created, even if they may not be immediately consequential.  If
202562306a36Sopenharmony_ci * lkb1 exists anywhere in the convert queue and lkb2 comes in with a granted
202662306a36Sopenharmony_ci * mode that would prevent lkb1's conversion from being granted, we do a
202762306a36Sopenharmony_ci * deadlk/demote on lkb2 right away and don't let it onto the convert queue.
202862306a36Sopenharmony_ci * I think this means that the lkb_is_ahead condition below should always
202962306a36Sopenharmony_ci * be zero, i.e. there will never be conv-deadlk between two locks that are
203062306a36Sopenharmony_ci * both already on the convert queue.
203162306a36Sopenharmony_ci */
203262306a36Sopenharmony_ci
203362306a36Sopenharmony_cistatic int conversion_deadlock_detect(struct dlm_rsb *r, struct dlm_lkb *lkb2)
203462306a36Sopenharmony_ci{
203562306a36Sopenharmony_ci	struct dlm_lkb *lkb1;
203662306a36Sopenharmony_ci	int lkb_is_ahead = 0;
203762306a36Sopenharmony_ci
203862306a36Sopenharmony_ci	list_for_each_entry(lkb1, &r->res_convertqueue, lkb_statequeue) {
203962306a36Sopenharmony_ci		if (lkb1 == lkb2) {
204062306a36Sopenharmony_ci			lkb_is_ahead = 1;
204162306a36Sopenharmony_ci			continue;
204262306a36Sopenharmony_ci		}
204362306a36Sopenharmony_ci
204462306a36Sopenharmony_ci		if (!lkb_is_ahead) {
204562306a36Sopenharmony_ci			if (!modes_compat(lkb2, lkb1))
204662306a36Sopenharmony_ci				return 1;
204762306a36Sopenharmony_ci		} else {
204862306a36Sopenharmony_ci			if (!modes_compat(lkb2, lkb1) &&
204962306a36Sopenharmony_ci			    !modes_compat(lkb1, lkb2))
205062306a36Sopenharmony_ci				return 1;
205162306a36Sopenharmony_ci		}
205262306a36Sopenharmony_ci	}
205362306a36Sopenharmony_ci	return 0;
205462306a36Sopenharmony_ci}
205562306a36Sopenharmony_ci
205662306a36Sopenharmony_ci/*
205762306a36Sopenharmony_ci * Return 1 if the lock can be granted, 0 otherwise.
205862306a36Sopenharmony_ci * Also detect and resolve conversion deadlocks.
205962306a36Sopenharmony_ci *
206062306a36Sopenharmony_ci * lkb is the lock to be granted
206162306a36Sopenharmony_ci *
206262306a36Sopenharmony_ci * now is 1 if the function is being called in the context of the
206362306a36Sopenharmony_ci * immediate request, it is 0 if called later, after the lock has been
206462306a36Sopenharmony_ci * queued.
206562306a36Sopenharmony_ci *
206662306a36Sopenharmony_ci * recover is 1 if dlm_recover_grant() is trying to grant conversions
206762306a36Sopenharmony_ci * after recovery.
206862306a36Sopenharmony_ci *
206962306a36Sopenharmony_ci * References are from chapter 6 of "VAXcluster Principles" by Roy Davis
207062306a36Sopenharmony_ci */
207162306a36Sopenharmony_ci
207262306a36Sopenharmony_cistatic int _can_be_granted(struct dlm_rsb *r, struct dlm_lkb *lkb, int now,
207362306a36Sopenharmony_ci			   int recover)
207462306a36Sopenharmony_ci{
207562306a36Sopenharmony_ci	int8_t conv = (lkb->lkb_grmode != DLM_LOCK_IV);
207662306a36Sopenharmony_ci
207762306a36Sopenharmony_ci	/*
207862306a36Sopenharmony_ci	 * 6-10: Version 5.4 introduced an option to address the phenomenon of
207962306a36Sopenharmony_ci	 * a new request for a NL mode lock being blocked.
208062306a36Sopenharmony_ci	 *
208162306a36Sopenharmony_ci	 * 6-11: If the optional EXPEDITE flag is used with the new NL mode
208262306a36Sopenharmony_ci	 * request, then it would be granted.  In essence, the use of this flag
208362306a36Sopenharmony_ci	 * tells the Lock Manager to expedite theis request by not considering
208462306a36Sopenharmony_ci	 * what may be in the CONVERTING or WAITING queues...  As of this
208562306a36Sopenharmony_ci	 * writing, the EXPEDITE flag can be used only with new requests for NL
208662306a36Sopenharmony_ci	 * mode locks.  This flag is not valid for conversion requests.
208762306a36Sopenharmony_ci	 *
208862306a36Sopenharmony_ci	 * A shortcut.  Earlier checks return an error if EXPEDITE is used in a
208962306a36Sopenharmony_ci	 * conversion or used with a non-NL requested mode.  We also know an
209062306a36Sopenharmony_ci	 * EXPEDITE request is always granted immediately, so now must always
209162306a36Sopenharmony_ci	 * be 1.  The full condition to grant an expedite request: (now &&
209262306a36Sopenharmony_ci	 * !conv && lkb->rqmode == DLM_LOCK_NL && (flags & EXPEDITE)) can
209362306a36Sopenharmony_ci	 * therefore be shortened to just checking the flag.
209462306a36Sopenharmony_ci	 */
209562306a36Sopenharmony_ci
209662306a36Sopenharmony_ci	if (lkb->lkb_exflags & DLM_LKF_EXPEDITE)
209762306a36Sopenharmony_ci		return 1;
209862306a36Sopenharmony_ci
209962306a36Sopenharmony_ci	/*
210062306a36Sopenharmony_ci	 * A shortcut. Without this, !queue_conflict(grantqueue, lkb) would be
210162306a36Sopenharmony_ci	 * added to the remaining conditions.
210262306a36Sopenharmony_ci	 */
210362306a36Sopenharmony_ci
210462306a36Sopenharmony_ci	if (queue_conflict(&r->res_grantqueue, lkb))
210562306a36Sopenharmony_ci		return 0;
210662306a36Sopenharmony_ci
210762306a36Sopenharmony_ci	/*
210862306a36Sopenharmony_ci	 * 6-3: By default, a conversion request is immediately granted if the
210962306a36Sopenharmony_ci	 * requested mode is compatible with the modes of all other granted
211062306a36Sopenharmony_ci	 * locks
211162306a36Sopenharmony_ci	 */
211262306a36Sopenharmony_ci
211362306a36Sopenharmony_ci	if (queue_conflict(&r->res_convertqueue, lkb))
211462306a36Sopenharmony_ci		return 0;
211562306a36Sopenharmony_ci
211662306a36Sopenharmony_ci	/*
211762306a36Sopenharmony_ci	 * The RECOVER_GRANT flag means dlm_recover_grant() is granting
211862306a36Sopenharmony_ci	 * locks for a recovered rsb, on which lkb's have been rebuilt.
211962306a36Sopenharmony_ci	 * The lkb's may have been rebuilt on the queues in a different
212062306a36Sopenharmony_ci	 * order than they were in on the previous master.  So, granting
212162306a36Sopenharmony_ci	 * queued conversions in order after recovery doesn't make sense
212262306a36Sopenharmony_ci	 * since the order hasn't been preserved anyway.  The new order
212362306a36Sopenharmony_ci	 * could also have created a new "in place" conversion deadlock.
212462306a36Sopenharmony_ci	 * (e.g. old, failed master held granted EX, with PR->EX, NL->EX.
212562306a36Sopenharmony_ci	 * After recovery, there would be no granted locks, and possibly
212662306a36Sopenharmony_ci	 * NL->EX, PR->EX, an in-place conversion deadlock.)  So, after
212762306a36Sopenharmony_ci	 * recovery, grant conversions without considering order.
212862306a36Sopenharmony_ci	 */
212962306a36Sopenharmony_ci
213062306a36Sopenharmony_ci	if (conv && recover)
213162306a36Sopenharmony_ci		return 1;
213262306a36Sopenharmony_ci
213362306a36Sopenharmony_ci	/*
213462306a36Sopenharmony_ci	 * 6-5: But the default algorithm for deciding whether to grant or
213562306a36Sopenharmony_ci	 * queue conversion requests does not by itself guarantee that such
213662306a36Sopenharmony_ci	 * requests are serviced on a "first come first serve" basis.  This, in
213762306a36Sopenharmony_ci	 * turn, can lead to a phenomenon known as "indefinate postponement".
213862306a36Sopenharmony_ci	 *
213962306a36Sopenharmony_ci	 * 6-7: This issue is dealt with by using the optional QUECVT flag with
214062306a36Sopenharmony_ci	 * the system service employed to request a lock conversion.  This flag
214162306a36Sopenharmony_ci	 * forces certain conversion requests to be queued, even if they are
214262306a36Sopenharmony_ci	 * compatible with the granted modes of other locks on the same
214362306a36Sopenharmony_ci	 * resource.  Thus, the use of this flag results in conversion requests
214462306a36Sopenharmony_ci	 * being ordered on a "first come first servce" basis.
214562306a36Sopenharmony_ci	 *
214662306a36Sopenharmony_ci	 * DCT: This condition is all about new conversions being able to occur
214762306a36Sopenharmony_ci	 * "in place" while the lock remains on the granted queue (assuming
214862306a36Sopenharmony_ci	 * nothing else conflicts.)  IOW if QUECVT isn't set, a conversion
214962306a36Sopenharmony_ci	 * doesn't _have_ to go onto the convert queue where it's processed in
215062306a36Sopenharmony_ci	 * order.  The "now" variable is necessary to distinguish converts
215162306a36Sopenharmony_ci	 * being received and processed for the first time now, because once a
215262306a36Sopenharmony_ci	 * convert is moved to the conversion queue the condition below applies
215362306a36Sopenharmony_ci	 * requiring fifo granting.
215462306a36Sopenharmony_ci	 */
215562306a36Sopenharmony_ci
215662306a36Sopenharmony_ci	if (now && conv && !(lkb->lkb_exflags & DLM_LKF_QUECVT))
215762306a36Sopenharmony_ci		return 1;
215862306a36Sopenharmony_ci
215962306a36Sopenharmony_ci	/*
216062306a36Sopenharmony_ci	 * Even if the convert is compat with all granted locks,
216162306a36Sopenharmony_ci	 * QUECVT forces it behind other locks on the convert queue.
216262306a36Sopenharmony_ci	 */
216362306a36Sopenharmony_ci
216462306a36Sopenharmony_ci	if (now && conv && (lkb->lkb_exflags & DLM_LKF_QUECVT)) {
216562306a36Sopenharmony_ci		if (list_empty(&r->res_convertqueue))
216662306a36Sopenharmony_ci			return 1;
216762306a36Sopenharmony_ci		else
216862306a36Sopenharmony_ci			return 0;
216962306a36Sopenharmony_ci	}
217062306a36Sopenharmony_ci
217162306a36Sopenharmony_ci	/*
217262306a36Sopenharmony_ci	 * The NOORDER flag is set to avoid the standard vms rules on grant
217362306a36Sopenharmony_ci	 * order.
217462306a36Sopenharmony_ci	 */
217562306a36Sopenharmony_ci
217662306a36Sopenharmony_ci	if (lkb->lkb_exflags & DLM_LKF_NOORDER)
217762306a36Sopenharmony_ci		return 1;
217862306a36Sopenharmony_ci
217962306a36Sopenharmony_ci	/*
218062306a36Sopenharmony_ci	 * 6-3: Once in that queue [CONVERTING], a conversion request cannot be
218162306a36Sopenharmony_ci	 * granted until all other conversion requests ahead of it are granted
218262306a36Sopenharmony_ci	 * and/or canceled.
218362306a36Sopenharmony_ci	 */
218462306a36Sopenharmony_ci
218562306a36Sopenharmony_ci	if (!now && conv && first_in_list(lkb, &r->res_convertqueue))
218662306a36Sopenharmony_ci		return 1;
218762306a36Sopenharmony_ci
218862306a36Sopenharmony_ci	/*
218962306a36Sopenharmony_ci	 * 6-4: By default, a new request is immediately granted only if all
219062306a36Sopenharmony_ci	 * three of the following conditions are satisfied when the request is
219162306a36Sopenharmony_ci	 * issued:
219262306a36Sopenharmony_ci	 * - The queue of ungranted conversion requests for the resource is
219362306a36Sopenharmony_ci	 *   empty.
219462306a36Sopenharmony_ci	 * - The queue of ungranted new requests for the resource is empty.
219562306a36Sopenharmony_ci	 * - The mode of the new request is compatible with the most
219662306a36Sopenharmony_ci	 *   restrictive mode of all granted locks on the resource.
219762306a36Sopenharmony_ci	 */
219862306a36Sopenharmony_ci
219962306a36Sopenharmony_ci	if (now && !conv && list_empty(&r->res_convertqueue) &&
220062306a36Sopenharmony_ci	    list_empty(&r->res_waitqueue))
220162306a36Sopenharmony_ci		return 1;
220262306a36Sopenharmony_ci
220362306a36Sopenharmony_ci	/*
220462306a36Sopenharmony_ci	 * 6-4: Once a lock request is in the queue of ungranted new requests,
220562306a36Sopenharmony_ci	 * it cannot be granted until the queue of ungranted conversion
220662306a36Sopenharmony_ci	 * requests is empty, all ungranted new requests ahead of it are
220762306a36Sopenharmony_ci	 * granted and/or canceled, and it is compatible with the granted mode
220862306a36Sopenharmony_ci	 * of the most restrictive lock granted on the resource.
220962306a36Sopenharmony_ci	 */
221062306a36Sopenharmony_ci
221162306a36Sopenharmony_ci	if (!now && !conv && list_empty(&r->res_convertqueue) &&
221262306a36Sopenharmony_ci	    first_in_list(lkb, &r->res_waitqueue))
221362306a36Sopenharmony_ci		return 1;
221462306a36Sopenharmony_ci
221562306a36Sopenharmony_ci	return 0;
221662306a36Sopenharmony_ci}
221762306a36Sopenharmony_ci
221862306a36Sopenharmony_cistatic int can_be_granted(struct dlm_rsb *r, struct dlm_lkb *lkb, int now,
221962306a36Sopenharmony_ci			  int recover, int *err)
222062306a36Sopenharmony_ci{
222162306a36Sopenharmony_ci	int rv;
222262306a36Sopenharmony_ci	int8_t alt = 0, rqmode = lkb->lkb_rqmode;
222362306a36Sopenharmony_ci	int8_t is_convert = (lkb->lkb_grmode != DLM_LOCK_IV);
222462306a36Sopenharmony_ci
222562306a36Sopenharmony_ci	if (err)
222662306a36Sopenharmony_ci		*err = 0;
222762306a36Sopenharmony_ci
222862306a36Sopenharmony_ci	rv = _can_be_granted(r, lkb, now, recover);
222962306a36Sopenharmony_ci	if (rv)
223062306a36Sopenharmony_ci		goto out;
223162306a36Sopenharmony_ci
223262306a36Sopenharmony_ci	/*
223362306a36Sopenharmony_ci	 * The CONVDEADLK flag is non-standard and tells the dlm to resolve
223462306a36Sopenharmony_ci	 * conversion deadlocks by demoting grmode to NL, otherwise the dlm
223562306a36Sopenharmony_ci	 * cancels one of the locks.
223662306a36Sopenharmony_ci	 */
223762306a36Sopenharmony_ci
223862306a36Sopenharmony_ci	if (is_convert && can_be_queued(lkb) &&
223962306a36Sopenharmony_ci	    conversion_deadlock_detect(r, lkb)) {
224062306a36Sopenharmony_ci		if (lkb->lkb_exflags & DLM_LKF_CONVDEADLK) {
224162306a36Sopenharmony_ci			lkb->lkb_grmode = DLM_LOCK_NL;
224262306a36Sopenharmony_ci			set_bit(DLM_SBF_DEMOTED_BIT, &lkb->lkb_sbflags);
224362306a36Sopenharmony_ci		} else if (err) {
224462306a36Sopenharmony_ci			*err = -EDEADLK;
224562306a36Sopenharmony_ci		} else {
224662306a36Sopenharmony_ci			log_print("can_be_granted deadlock %x now %d",
224762306a36Sopenharmony_ci				  lkb->lkb_id, now);
224862306a36Sopenharmony_ci			dlm_dump_rsb(r);
224962306a36Sopenharmony_ci		}
225062306a36Sopenharmony_ci		goto out;
225162306a36Sopenharmony_ci	}
225262306a36Sopenharmony_ci
225362306a36Sopenharmony_ci	/*
225462306a36Sopenharmony_ci	 * The ALTPR and ALTCW flags are non-standard and tell the dlm to try
225562306a36Sopenharmony_ci	 * to grant a request in a mode other than the normal rqmode.  It's a
225662306a36Sopenharmony_ci	 * simple way to provide a big optimization to applications that can
225762306a36Sopenharmony_ci	 * use them.
225862306a36Sopenharmony_ci	 */
225962306a36Sopenharmony_ci
226062306a36Sopenharmony_ci	if (rqmode != DLM_LOCK_PR && (lkb->lkb_exflags & DLM_LKF_ALTPR))
226162306a36Sopenharmony_ci		alt = DLM_LOCK_PR;
226262306a36Sopenharmony_ci	else if (rqmode != DLM_LOCK_CW && (lkb->lkb_exflags & DLM_LKF_ALTCW))
226362306a36Sopenharmony_ci		alt = DLM_LOCK_CW;
226462306a36Sopenharmony_ci
226562306a36Sopenharmony_ci	if (alt) {
226662306a36Sopenharmony_ci		lkb->lkb_rqmode = alt;
226762306a36Sopenharmony_ci		rv = _can_be_granted(r, lkb, now, 0);
226862306a36Sopenharmony_ci		if (rv)
226962306a36Sopenharmony_ci			set_bit(DLM_SBF_ALTMODE_BIT, &lkb->lkb_sbflags);
227062306a36Sopenharmony_ci		else
227162306a36Sopenharmony_ci			lkb->lkb_rqmode = rqmode;
227262306a36Sopenharmony_ci	}
227362306a36Sopenharmony_ci out:
227462306a36Sopenharmony_ci	return rv;
227562306a36Sopenharmony_ci}
227662306a36Sopenharmony_ci
227762306a36Sopenharmony_ci/* Returns the highest requested mode of all blocked conversions; sets
227862306a36Sopenharmony_ci   cw if there's a blocked conversion to DLM_LOCK_CW. */
227962306a36Sopenharmony_ci
228062306a36Sopenharmony_cistatic int grant_pending_convert(struct dlm_rsb *r, int high, int *cw,
228162306a36Sopenharmony_ci				 unsigned int *count)
228262306a36Sopenharmony_ci{
228362306a36Sopenharmony_ci	struct dlm_lkb *lkb, *s;
228462306a36Sopenharmony_ci	int recover = rsb_flag(r, RSB_RECOVER_GRANT);
228562306a36Sopenharmony_ci	int hi, demoted, quit, grant_restart, demote_restart;
228662306a36Sopenharmony_ci	int deadlk;
228762306a36Sopenharmony_ci
228862306a36Sopenharmony_ci	quit = 0;
228962306a36Sopenharmony_ci restart:
229062306a36Sopenharmony_ci	grant_restart = 0;
229162306a36Sopenharmony_ci	demote_restart = 0;
229262306a36Sopenharmony_ci	hi = DLM_LOCK_IV;
229362306a36Sopenharmony_ci
229462306a36Sopenharmony_ci	list_for_each_entry_safe(lkb, s, &r->res_convertqueue, lkb_statequeue) {
229562306a36Sopenharmony_ci		demoted = is_demoted(lkb);
229662306a36Sopenharmony_ci		deadlk = 0;
229762306a36Sopenharmony_ci
229862306a36Sopenharmony_ci		if (can_be_granted(r, lkb, 0, recover, &deadlk)) {
229962306a36Sopenharmony_ci			grant_lock_pending(r, lkb);
230062306a36Sopenharmony_ci			grant_restart = 1;
230162306a36Sopenharmony_ci			if (count)
230262306a36Sopenharmony_ci				(*count)++;
230362306a36Sopenharmony_ci			continue;
230462306a36Sopenharmony_ci		}
230562306a36Sopenharmony_ci
230662306a36Sopenharmony_ci		if (!demoted && is_demoted(lkb)) {
230762306a36Sopenharmony_ci			log_print("WARN: pending demoted %x node %d %s",
230862306a36Sopenharmony_ci				  lkb->lkb_id, lkb->lkb_nodeid, r->res_name);
230962306a36Sopenharmony_ci			demote_restart = 1;
231062306a36Sopenharmony_ci			continue;
231162306a36Sopenharmony_ci		}
231262306a36Sopenharmony_ci
231362306a36Sopenharmony_ci		if (deadlk) {
231462306a36Sopenharmony_ci			/*
231562306a36Sopenharmony_ci			 * If DLM_LKB_NODLKWT flag is set and conversion
231662306a36Sopenharmony_ci			 * deadlock is detected, we request blocking AST and
231762306a36Sopenharmony_ci			 * down (or cancel) conversion.
231862306a36Sopenharmony_ci			 */
231962306a36Sopenharmony_ci			if (lkb->lkb_exflags & DLM_LKF_NODLCKWT) {
232062306a36Sopenharmony_ci				if (lkb->lkb_highbast < lkb->lkb_rqmode) {
232162306a36Sopenharmony_ci					queue_bast(r, lkb, lkb->lkb_rqmode);
232262306a36Sopenharmony_ci					lkb->lkb_highbast = lkb->lkb_rqmode;
232362306a36Sopenharmony_ci				}
232462306a36Sopenharmony_ci			} else {
232562306a36Sopenharmony_ci				log_print("WARN: pending deadlock %x node %d %s",
232662306a36Sopenharmony_ci					  lkb->lkb_id, lkb->lkb_nodeid,
232762306a36Sopenharmony_ci					  r->res_name);
232862306a36Sopenharmony_ci				dlm_dump_rsb(r);
232962306a36Sopenharmony_ci			}
233062306a36Sopenharmony_ci			continue;
233162306a36Sopenharmony_ci		}
233262306a36Sopenharmony_ci
233362306a36Sopenharmony_ci		hi = max_t(int, lkb->lkb_rqmode, hi);
233462306a36Sopenharmony_ci
233562306a36Sopenharmony_ci		if (cw && lkb->lkb_rqmode == DLM_LOCK_CW)
233662306a36Sopenharmony_ci			*cw = 1;
233762306a36Sopenharmony_ci	}
233862306a36Sopenharmony_ci
233962306a36Sopenharmony_ci	if (grant_restart)
234062306a36Sopenharmony_ci		goto restart;
234162306a36Sopenharmony_ci	if (demote_restart && !quit) {
234262306a36Sopenharmony_ci		quit = 1;
234362306a36Sopenharmony_ci		goto restart;
234462306a36Sopenharmony_ci	}
234562306a36Sopenharmony_ci
234662306a36Sopenharmony_ci	return max_t(int, high, hi);
234762306a36Sopenharmony_ci}
234862306a36Sopenharmony_ci
234962306a36Sopenharmony_cistatic int grant_pending_wait(struct dlm_rsb *r, int high, int *cw,
235062306a36Sopenharmony_ci			      unsigned int *count)
235162306a36Sopenharmony_ci{
235262306a36Sopenharmony_ci	struct dlm_lkb *lkb, *s;
235362306a36Sopenharmony_ci
235462306a36Sopenharmony_ci	list_for_each_entry_safe(lkb, s, &r->res_waitqueue, lkb_statequeue) {
235562306a36Sopenharmony_ci		if (can_be_granted(r, lkb, 0, 0, NULL)) {
235662306a36Sopenharmony_ci			grant_lock_pending(r, lkb);
235762306a36Sopenharmony_ci			if (count)
235862306a36Sopenharmony_ci				(*count)++;
235962306a36Sopenharmony_ci		} else {
236062306a36Sopenharmony_ci			high = max_t(int, lkb->lkb_rqmode, high);
236162306a36Sopenharmony_ci			if (lkb->lkb_rqmode == DLM_LOCK_CW)
236262306a36Sopenharmony_ci				*cw = 1;
236362306a36Sopenharmony_ci		}
236462306a36Sopenharmony_ci	}
236562306a36Sopenharmony_ci
236662306a36Sopenharmony_ci	return high;
236762306a36Sopenharmony_ci}
236862306a36Sopenharmony_ci
236962306a36Sopenharmony_ci/* cw of 1 means there's a lock with a rqmode of DLM_LOCK_CW that's blocked
237062306a36Sopenharmony_ci   on either the convert or waiting queue.
237162306a36Sopenharmony_ci   high is the largest rqmode of all locks blocked on the convert or
237262306a36Sopenharmony_ci   waiting queue. */
237362306a36Sopenharmony_ci
237462306a36Sopenharmony_cistatic int lock_requires_bast(struct dlm_lkb *gr, int high, int cw)
237562306a36Sopenharmony_ci{
237662306a36Sopenharmony_ci	if (gr->lkb_grmode == DLM_LOCK_PR && cw) {
237762306a36Sopenharmony_ci		if (gr->lkb_highbast < DLM_LOCK_EX)
237862306a36Sopenharmony_ci			return 1;
237962306a36Sopenharmony_ci		return 0;
238062306a36Sopenharmony_ci	}
238162306a36Sopenharmony_ci
238262306a36Sopenharmony_ci	if (gr->lkb_highbast < high &&
238362306a36Sopenharmony_ci	    !__dlm_compat_matrix[gr->lkb_grmode+1][high+1])
238462306a36Sopenharmony_ci		return 1;
238562306a36Sopenharmony_ci	return 0;
238662306a36Sopenharmony_ci}
238762306a36Sopenharmony_ci
238862306a36Sopenharmony_cistatic void grant_pending_locks(struct dlm_rsb *r, unsigned int *count)
238962306a36Sopenharmony_ci{
239062306a36Sopenharmony_ci	struct dlm_lkb *lkb, *s;
239162306a36Sopenharmony_ci	int high = DLM_LOCK_IV;
239262306a36Sopenharmony_ci	int cw = 0;
239362306a36Sopenharmony_ci
239462306a36Sopenharmony_ci	if (!is_master(r)) {
239562306a36Sopenharmony_ci		log_print("grant_pending_locks r nodeid %d", r->res_nodeid);
239662306a36Sopenharmony_ci		dlm_dump_rsb(r);
239762306a36Sopenharmony_ci		return;
239862306a36Sopenharmony_ci	}
239962306a36Sopenharmony_ci
240062306a36Sopenharmony_ci	high = grant_pending_convert(r, high, &cw, count);
240162306a36Sopenharmony_ci	high = grant_pending_wait(r, high, &cw, count);
240262306a36Sopenharmony_ci
240362306a36Sopenharmony_ci	if (high == DLM_LOCK_IV)
240462306a36Sopenharmony_ci		return;
240562306a36Sopenharmony_ci
240662306a36Sopenharmony_ci	/*
240762306a36Sopenharmony_ci	 * If there are locks left on the wait/convert queue then send blocking
240862306a36Sopenharmony_ci	 * ASTs to granted locks based on the largest requested mode (high)
240962306a36Sopenharmony_ci	 * found above.
241062306a36Sopenharmony_ci	 */
241162306a36Sopenharmony_ci
241262306a36Sopenharmony_ci	list_for_each_entry_safe(lkb, s, &r->res_grantqueue, lkb_statequeue) {
241362306a36Sopenharmony_ci		if (lkb->lkb_bastfn && lock_requires_bast(lkb, high, cw)) {
241462306a36Sopenharmony_ci			if (cw && high == DLM_LOCK_PR &&
241562306a36Sopenharmony_ci			    lkb->lkb_grmode == DLM_LOCK_PR)
241662306a36Sopenharmony_ci				queue_bast(r, lkb, DLM_LOCK_CW);
241762306a36Sopenharmony_ci			else
241862306a36Sopenharmony_ci				queue_bast(r, lkb, high);
241962306a36Sopenharmony_ci			lkb->lkb_highbast = high;
242062306a36Sopenharmony_ci		}
242162306a36Sopenharmony_ci	}
242262306a36Sopenharmony_ci}
242362306a36Sopenharmony_ci
242462306a36Sopenharmony_cistatic int modes_require_bast(struct dlm_lkb *gr, struct dlm_lkb *rq)
242562306a36Sopenharmony_ci{
242662306a36Sopenharmony_ci	if ((gr->lkb_grmode == DLM_LOCK_PR && rq->lkb_rqmode == DLM_LOCK_CW) ||
242762306a36Sopenharmony_ci	    (gr->lkb_grmode == DLM_LOCK_CW && rq->lkb_rqmode == DLM_LOCK_PR)) {
242862306a36Sopenharmony_ci		if (gr->lkb_highbast < DLM_LOCK_EX)
242962306a36Sopenharmony_ci			return 1;
243062306a36Sopenharmony_ci		return 0;
243162306a36Sopenharmony_ci	}
243262306a36Sopenharmony_ci
243362306a36Sopenharmony_ci	if (gr->lkb_highbast < rq->lkb_rqmode && !modes_compat(gr, rq))
243462306a36Sopenharmony_ci		return 1;
243562306a36Sopenharmony_ci	return 0;
243662306a36Sopenharmony_ci}
243762306a36Sopenharmony_ci
243862306a36Sopenharmony_cistatic void send_bast_queue(struct dlm_rsb *r, struct list_head *head,
243962306a36Sopenharmony_ci			    struct dlm_lkb *lkb)
244062306a36Sopenharmony_ci{
244162306a36Sopenharmony_ci	struct dlm_lkb *gr;
244262306a36Sopenharmony_ci
244362306a36Sopenharmony_ci	list_for_each_entry(gr, head, lkb_statequeue) {
244462306a36Sopenharmony_ci		/* skip self when sending basts to convertqueue */
244562306a36Sopenharmony_ci		if (gr == lkb)
244662306a36Sopenharmony_ci			continue;
244762306a36Sopenharmony_ci		if (gr->lkb_bastfn && modes_require_bast(gr, lkb)) {
244862306a36Sopenharmony_ci			queue_bast(r, gr, lkb->lkb_rqmode);
244962306a36Sopenharmony_ci			gr->lkb_highbast = lkb->lkb_rqmode;
245062306a36Sopenharmony_ci		}
245162306a36Sopenharmony_ci	}
245262306a36Sopenharmony_ci}
245362306a36Sopenharmony_ci
245462306a36Sopenharmony_cistatic void send_blocking_asts(struct dlm_rsb *r, struct dlm_lkb *lkb)
245562306a36Sopenharmony_ci{
245662306a36Sopenharmony_ci	send_bast_queue(r, &r->res_grantqueue, lkb);
245762306a36Sopenharmony_ci}
245862306a36Sopenharmony_ci
245962306a36Sopenharmony_cistatic void send_blocking_asts_all(struct dlm_rsb *r, struct dlm_lkb *lkb)
246062306a36Sopenharmony_ci{
246162306a36Sopenharmony_ci	send_bast_queue(r, &r->res_grantqueue, lkb);
246262306a36Sopenharmony_ci	send_bast_queue(r, &r->res_convertqueue, lkb);
246362306a36Sopenharmony_ci}
246462306a36Sopenharmony_ci
246562306a36Sopenharmony_ci/* set_master(r, lkb) -- set the master nodeid of a resource
246662306a36Sopenharmony_ci
246762306a36Sopenharmony_ci   The purpose of this function is to set the nodeid field in the given
246862306a36Sopenharmony_ci   lkb using the nodeid field in the given rsb.  If the rsb's nodeid is
246962306a36Sopenharmony_ci   known, it can just be copied to the lkb and the function will return
247062306a36Sopenharmony_ci   0.  If the rsb's nodeid is _not_ known, it needs to be looked up
247162306a36Sopenharmony_ci   before it can be copied to the lkb.
247262306a36Sopenharmony_ci
247362306a36Sopenharmony_ci   When the rsb nodeid is being looked up remotely, the initial lkb
247462306a36Sopenharmony_ci   causing the lookup is kept on the ls_waiters list waiting for the
247562306a36Sopenharmony_ci   lookup reply.  Other lkb's waiting for the same rsb lookup are kept
247662306a36Sopenharmony_ci   on the rsb's res_lookup list until the master is verified.
247762306a36Sopenharmony_ci
247862306a36Sopenharmony_ci   Return values:
247962306a36Sopenharmony_ci   0: nodeid is set in rsb/lkb and the caller should go ahead and use it
248062306a36Sopenharmony_ci   1: the rsb master is not available and the lkb has been placed on
248162306a36Sopenharmony_ci      a wait queue
248262306a36Sopenharmony_ci*/
248362306a36Sopenharmony_ci
248462306a36Sopenharmony_cistatic int set_master(struct dlm_rsb *r, struct dlm_lkb *lkb)
248562306a36Sopenharmony_ci{
248662306a36Sopenharmony_ci	int our_nodeid = dlm_our_nodeid();
248762306a36Sopenharmony_ci
248862306a36Sopenharmony_ci	if (rsb_flag(r, RSB_MASTER_UNCERTAIN)) {
248962306a36Sopenharmony_ci		rsb_clear_flag(r, RSB_MASTER_UNCERTAIN);
249062306a36Sopenharmony_ci		r->res_first_lkid = lkb->lkb_id;
249162306a36Sopenharmony_ci		lkb->lkb_nodeid = r->res_nodeid;
249262306a36Sopenharmony_ci		return 0;
249362306a36Sopenharmony_ci	}
249462306a36Sopenharmony_ci
249562306a36Sopenharmony_ci	if (r->res_first_lkid && r->res_first_lkid != lkb->lkb_id) {
249662306a36Sopenharmony_ci		list_add_tail(&lkb->lkb_rsb_lookup, &r->res_lookup);
249762306a36Sopenharmony_ci		return 1;
249862306a36Sopenharmony_ci	}
249962306a36Sopenharmony_ci
250062306a36Sopenharmony_ci	if (r->res_master_nodeid == our_nodeid) {
250162306a36Sopenharmony_ci		lkb->lkb_nodeid = 0;
250262306a36Sopenharmony_ci		return 0;
250362306a36Sopenharmony_ci	}
250462306a36Sopenharmony_ci
250562306a36Sopenharmony_ci	if (r->res_master_nodeid) {
250662306a36Sopenharmony_ci		lkb->lkb_nodeid = r->res_master_nodeid;
250762306a36Sopenharmony_ci		return 0;
250862306a36Sopenharmony_ci	}
250962306a36Sopenharmony_ci
251062306a36Sopenharmony_ci	if (dlm_dir_nodeid(r) == our_nodeid) {
251162306a36Sopenharmony_ci		/* This is a somewhat unusual case; find_rsb will usually
251262306a36Sopenharmony_ci		   have set res_master_nodeid when dir nodeid is local, but
251362306a36Sopenharmony_ci		   there are cases where we become the dir node after we've
251462306a36Sopenharmony_ci		   past find_rsb and go through _request_lock again.
251562306a36Sopenharmony_ci		   confirm_master() or process_lookup_list() needs to be
251662306a36Sopenharmony_ci		   called after this. */
251762306a36Sopenharmony_ci		log_debug(r->res_ls, "set_master %x self master %d dir %d %s",
251862306a36Sopenharmony_ci			  lkb->lkb_id, r->res_master_nodeid, r->res_dir_nodeid,
251962306a36Sopenharmony_ci			  r->res_name);
252062306a36Sopenharmony_ci		r->res_master_nodeid = our_nodeid;
252162306a36Sopenharmony_ci		r->res_nodeid = 0;
252262306a36Sopenharmony_ci		lkb->lkb_nodeid = 0;
252362306a36Sopenharmony_ci		return 0;
252462306a36Sopenharmony_ci	}
252562306a36Sopenharmony_ci
252662306a36Sopenharmony_ci	r->res_first_lkid = lkb->lkb_id;
252762306a36Sopenharmony_ci	send_lookup(r, lkb);
252862306a36Sopenharmony_ci	return 1;
252962306a36Sopenharmony_ci}
253062306a36Sopenharmony_ci
253162306a36Sopenharmony_cistatic void process_lookup_list(struct dlm_rsb *r)
253262306a36Sopenharmony_ci{
253362306a36Sopenharmony_ci	struct dlm_lkb *lkb, *safe;
253462306a36Sopenharmony_ci
253562306a36Sopenharmony_ci	list_for_each_entry_safe(lkb, safe, &r->res_lookup, lkb_rsb_lookup) {
253662306a36Sopenharmony_ci		list_del_init(&lkb->lkb_rsb_lookup);
253762306a36Sopenharmony_ci		_request_lock(r, lkb);
253862306a36Sopenharmony_ci		schedule();
253962306a36Sopenharmony_ci	}
254062306a36Sopenharmony_ci}
254162306a36Sopenharmony_ci
254262306a36Sopenharmony_ci/* confirm_master -- confirm (or deny) an rsb's master nodeid */
254362306a36Sopenharmony_ci
254462306a36Sopenharmony_cistatic void confirm_master(struct dlm_rsb *r, int error)
254562306a36Sopenharmony_ci{
254662306a36Sopenharmony_ci	struct dlm_lkb *lkb;
254762306a36Sopenharmony_ci
254862306a36Sopenharmony_ci	if (!r->res_first_lkid)
254962306a36Sopenharmony_ci		return;
255062306a36Sopenharmony_ci
255162306a36Sopenharmony_ci	switch (error) {
255262306a36Sopenharmony_ci	case 0:
255362306a36Sopenharmony_ci	case -EINPROGRESS:
255462306a36Sopenharmony_ci		r->res_first_lkid = 0;
255562306a36Sopenharmony_ci		process_lookup_list(r);
255662306a36Sopenharmony_ci		break;
255762306a36Sopenharmony_ci
255862306a36Sopenharmony_ci	case -EAGAIN:
255962306a36Sopenharmony_ci	case -EBADR:
256062306a36Sopenharmony_ci	case -ENOTBLK:
256162306a36Sopenharmony_ci		/* the remote request failed and won't be retried (it was
256262306a36Sopenharmony_ci		   a NOQUEUE, or has been canceled/unlocked); make a waiting
256362306a36Sopenharmony_ci		   lkb the first_lkid */
256462306a36Sopenharmony_ci
256562306a36Sopenharmony_ci		r->res_first_lkid = 0;
256662306a36Sopenharmony_ci
256762306a36Sopenharmony_ci		if (!list_empty(&r->res_lookup)) {
256862306a36Sopenharmony_ci			lkb = list_entry(r->res_lookup.next, struct dlm_lkb,
256962306a36Sopenharmony_ci					 lkb_rsb_lookup);
257062306a36Sopenharmony_ci			list_del_init(&lkb->lkb_rsb_lookup);
257162306a36Sopenharmony_ci			r->res_first_lkid = lkb->lkb_id;
257262306a36Sopenharmony_ci			_request_lock(r, lkb);
257362306a36Sopenharmony_ci		}
257462306a36Sopenharmony_ci		break;
257562306a36Sopenharmony_ci
257662306a36Sopenharmony_ci	default:
257762306a36Sopenharmony_ci		log_error(r->res_ls, "confirm_master unknown error %d", error);
257862306a36Sopenharmony_ci	}
257962306a36Sopenharmony_ci}
258062306a36Sopenharmony_ci
258162306a36Sopenharmony_cistatic int set_lock_args(int mode, struct dlm_lksb *lksb, uint32_t flags,
258262306a36Sopenharmony_ci			 int namelen, void (*ast)(void *astparam),
258362306a36Sopenharmony_ci			 void *astparam,
258462306a36Sopenharmony_ci			 void (*bast)(void *astparam, int mode),
258562306a36Sopenharmony_ci			 struct dlm_args *args)
258662306a36Sopenharmony_ci{
258762306a36Sopenharmony_ci	int rv = -EINVAL;
258862306a36Sopenharmony_ci
258962306a36Sopenharmony_ci	/* check for invalid arg usage */
259062306a36Sopenharmony_ci
259162306a36Sopenharmony_ci	if (mode < 0 || mode > DLM_LOCK_EX)
259262306a36Sopenharmony_ci		goto out;
259362306a36Sopenharmony_ci
259462306a36Sopenharmony_ci	if (!(flags & DLM_LKF_CONVERT) && (namelen > DLM_RESNAME_MAXLEN))
259562306a36Sopenharmony_ci		goto out;
259662306a36Sopenharmony_ci
259762306a36Sopenharmony_ci	if (flags & DLM_LKF_CANCEL)
259862306a36Sopenharmony_ci		goto out;
259962306a36Sopenharmony_ci
260062306a36Sopenharmony_ci	if (flags & DLM_LKF_QUECVT && !(flags & DLM_LKF_CONVERT))
260162306a36Sopenharmony_ci		goto out;
260262306a36Sopenharmony_ci
260362306a36Sopenharmony_ci	if (flags & DLM_LKF_CONVDEADLK && !(flags & DLM_LKF_CONVERT))
260462306a36Sopenharmony_ci		goto out;
260562306a36Sopenharmony_ci
260662306a36Sopenharmony_ci	if (flags & DLM_LKF_CONVDEADLK && flags & DLM_LKF_NOQUEUE)
260762306a36Sopenharmony_ci		goto out;
260862306a36Sopenharmony_ci
260962306a36Sopenharmony_ci	if (flags & DLM_LKF_EXPEDITE && flags & DLM_LKF_CONVERT)
261062306a36Sopenharmony_ci		goto out;
261162306a36Sopenharmony_ci
261262306a36Sopenharmony_ci	if (flags & DLM_LKF_EXPEDITE && flags & DLM_LKF_QUECVT)
261362306a36Sopenharmony_ci		goto out;
261462306a36Sopenharmony_ci
261562306a36Sopenharmony_ci	if (flags & DLM_LKF_EXPEDITE && flags & DLM_LKF_NOQUEUE)
261662306a36Sopenharmony_ci		goto out;
261762306a36Sopenharmony_ci
261862306a36Sopenharmony_ci	if (flags & DLM_LKF_EXPEDITE && mode != DLM_LOCK_NL)
261962306a36Sopenharmony_ci		goto out;
262062306a36Sopenharmony_ci
262162306a36Sopenharmony_ci	if (!ast || !lksb)
262262306a36Sopenharmony_ci		goto out;
262362306a36Sopenharmony_ci
262462306a36Sopenharmony_ci	if (flags & DLM_LKF_VALBLK && !lksb->sb_lvbptr)
262562306a36Sopenharmony_ci		goto out;
262662306a36Sopenharmony_ci
262762306a36Sopenharmony_ci	if (flags & DLM_LKF_CONVERT && !lksb->sb_lkid)
262862306a36Sopenharmony_ci		goto out;
262962306a36Sopenharmony_ci
263062306a36Sopenharmony_ci	/* these args will be copied to the lkb in validate_lock_args,
263162306a36Sopenharmony_ci	   it cannot be done now because when converting locks, fields in
263262306a36Sopenharmony_ci	   an active lkb cannot be modified before locking the rsb */
263362306a36Sopenharmony_ci
263462306a36Sopenharmony_ci	args->flags = flags;
263562306a36Sopenharmony_ci	args->astfn = ast;
263662306a36Sopenharmony_ci	args->astparam = astparam;
263762306a36Sopenharmony_ci	args->bastfn = bast;
263862306a36Sopenharmony_ci	args->mode = mode;
263962306a36Sopenharmony_ci	args->lksb = lksb;
264062306a36Sopenharmony_ci	rv = 0;
264162306a36Sopenharmony_ci out:
264262306a36Sopenharmony_ci	return rv;
264362306a36Sopenharmony_ci}
264462306a36Sopenharmony_ci
264562306a36Sopenharmony_cistatic int set_unlock_args(uint32_t flags, void *astarg, struct dlm_args *args)
264662306a36Sopenharmony_ci{
264762306a36Sopenharmony_ci	if (flags & ~(DLM_LKF_CANCEL | DLM_LKF_VALBLK | DLM_LKF_IVVALBLK |
264862306a36Sopenharmony_ci 		      DLM_LKF_FORCEUNLOCK))
264962306a36Sopenharmony_ci		return -EINVAL;
265062306a36Sopenharmony_ci
265162306a36Sopenharmony_ci	if (flags & DLM_LKF_CANCEL && flags & DLM_LKF_FORCEUNLOCK)
265262306a36Sopenharmony_ci		return -EINVAL;
265362306a36Sopenharmony_ci
265462306a36Sopenharmony_ci	args->flags = flags;
265562306a36Sopenharmony_ci	args->astparam = astarg;
265662306a36Sopenharmony_ci	return 0;
265762306a36Sopenharmony_ci}
265862306a36Sopenharmony_ci
265962306a36Sopenharmony_cistatic int validate_lock_args(struct dlm_ls *ls, struct dlm_lkb *lkb,
266062306a36Sopenharmony_ci			      struct dlm_args *args)
266162306a36Sopenharmony_ci{
266262306a36Sopenharmony_ci	int rv = -EBUSY;
266362306a36Sopenharmony_ci
266462306a36Sopenharmony_ci	if (args->flags & DLM_LKF_CONVERT) {
266562306a36Sopenharmony_ci		if (lkb->lkb_status != DLM_LKSTS_GRANTED)
266662306a36Sopenharmony_ci			goto out;
266762306a36Sopenharmony_ci
266862306a36Sopenharmony_ci		/* lock not allowed if there's any op in progress */
266962306a36Sopenharmony_ci		if (lkb->lkb_wait_type || atomic_read(&lkb->lkb_wait_count))
267062306a36Sopenharmony_ci			goto out;
267162306a36Sopenharmony_ci
267262306a36Sopenharmony_ci		if (is_overlap(lkb))
267362306a36Sopenharmony_ci			goto out;
267462306a36Sopenharmony_ci
267562306a36Sopenharmony_ci		rv = -EINVAL;
267662306a36Sopenharmony_ci		if (test_bit(DLM_IFL_MSTCPY_BIT, &lkb->lkb_iflags))
267762306a36Sopenharmony_ci			goto out;
267862306a36Sopenharmony_ci
267962306a36Sopenharmony_ci		if (args->flags & DLM_LKF_QUECVT &&
268062306a36Sopenharmony_ci		    !__quecvt_compat_matrix[lkb->lkb_grmode+1][args->mode+1])
268162306a36Sopenharmony_ci			goto out;
268262306a36Sopenharmony_ci	}
268362306a36Sopenharmony_ci
268462306a36Sopenharmony_ci	lkb->lkb_exflags = args->flags;
268562306a36Sopenharmony_ci	dlm_set_sbflags_val(lkb, 0);
268662306a36Sopenharmony_ci	lkb->lkb_astfn = args->astfn;
268762306a36Sopenharmony_ci	lkb->lkb_astparam = args->astparam;
268862306a36Sopenharmony_ci	lkb->lkb_bastfn = args->bastfn;
268962306a36Sopenharmony_ci	lkb->lkb_rqmode = args->mode;
269062306a36Sopenharmony_ci	lkb->lkb_lksb = args->lksb;
269162306a36Sopenharmony_ci	lkb->lkb_lvbptr = args->lksb->sb_lvbptr;
269262306a36Sopenharmony_ci	lkb->lkb_ownpid = (int) current->pid;
269362306a36Sopenharmony_ci	rv = 0;
269462306a36Sopenharmony_ci out:
269562306a36Sopenharmony_ci	switch (rv) {
269662306a36Sopenharmony_ci	case 0:
269762306a36Sopenharmony_ci		break;
269862306a36Sopenharmony_ci	case -EINVAL:
269962306a36Sopenharmony_ci		/* annoy the user because dlm usage is wrong */
270062306a36Sopenharmony_ci		WARN_ON(1);
270162306a36Sopenharmony_ci		log_error(ls, "%s %d %x %x %x %d %d %s", __func__,
270262306a36Sopenharmony_ci			  rv, lkb->lkb_id, dlm_iflags_val(lkb), args->flags,
270362306a36Sopenharmony_ci			  lkb->lkb_status, lkb->lkb_wait_type,
270462306a36Sopenharmony_ci			  lkb->lkb_resource->res_name);
270562306a36Sopenharmony_ci		break;
270662306a36Sopenharmony_ci	default:
270762306a36Sopenharmony_ci		log_debug(ls, "%s %d %x %x %x %d %d %s", __func__,
270862306a36Sopenharmony_ci			  rv, lkb->lkb_id, dlm_iflags_val(lkb), args->flags,
270962306a36Sopenharmony_ci			  lkb->lkb_status, lkb->lkb_wait_type,
271062306a36Sopenharmony_ci			  lkb->lkb_resource->res_name);
271162306a36Sopenharmony_ci		break;
271262306a36Sopenharmony_ci	}
271362306a36Sopenharmony_ci
271462306a36Sopenharmony_ci	return rv;
271562306a36Sopenharmony_ci}
271662306a36Sopenharmony_ci
271762306a36Sopenharmony_ci/* when dlm_unlock() sees -EBUSY with CANCEL/FORCEUNLOCK it returns 0
271862306a36Sopenharmony_ci   for success */
271962306a36Sopenharmony_ci
272062306a36Sopenharmony_ci/* note: it's valid for lkb_nodeid/res_nodeid to be -1 when we get here
272162306a36Sopenharmony_ci   because there may be a lookup in progress and it's valid to do
272262306a36Sopenharmony_ci   cancel/unlockf on it */
272362306a36Sopenharmony_ci
272462306a36Sopenharmony_cistatic int validate_unlock_args(struct dlm_lkb *lkb, struct dlm_args *args)
272562306a36Sopenharmony_ci{
272662306a36Sopenharmony_ci	struct dlm_ls *ls = lkb->lkb_resource->res_ls;
272762306a36Sopenharmony_ci	int rv = -EBUSY;
272862306a36Sopenharmony_ci
272962306a36Sopenharmony_ci	/* normal unlock not allowed if there's any op in progress */
273062306a36Sopenharmony_ci	if (!(args->flags & (DLM_LKF_CANCEL | DLM_LKF_FORCEUNLOCK)) &&
273162306a36Sopenharmony_ci	    (lkb->lkb_wait_type || atomic_read(&lkb->lkb_wait_count)))
273262306a36Sopenharmony_ci		goto out;
273362306a36Sopenharmony_ci
273462306a36Sopenharmony_ci	/* an lkb may be waiting for an rsb lookup to complete where the
273562306a36Sopenharmony_ci	   lookup was initiated by another lock */
273662306a36Sopenharmony_ci
273762306a36Sopenharmony_ci	if (!list_empty(&lkb->lkb_rsb_lookup)) {
273862306a36Sopenharmony_ci		if (args->flags & (DLM_LKF_CANCEL | DLM_LKF_FORCEUNLOCK)) {
273962306a36Sopenharmony_ci			log_debug(ls, "unlock on rsb_lookup %x", lkb->lkb_id);
274062306a36Sopenharmony_ci			list_del_init(&lkb->lkb_rsb_lookup);
274162306a36Sopenharmony_ci			queue_cast(lkb->lkb_resource, lkb,
274262306a36Sopenharmony_ci				   args->flags & DLM_LKF_CANCEL ?
274362306a36Sopenharmony_ci				   -DLM_ECANCEL : -DLM_EUNLOCK);
274462306a36Sopenharmony_ci			unhold_lkb(lkb); /* undoes create_lkb() */
274562306a36Sopenharmony_ci		}
274662306a36Sopenharmony_ci		/* caller changes -EBUSY to 0 for CANCEL and FORCEUNLOCK */
274762306a36Sopenharmony_ci		goto out;
274862306a36Sopenharmony_ci	}
274962306a36Sopenharmony_ci
275062306a36Sopenharmony_ci	rv = -EINVAL;
275162306a36Sopenharmony_ci	if (test_bit(DLM_IFL_MSTCPY_BIT, &lkb->lkb_iflags)) {
275262306a36Sopenharmony_ci		log_error(ls, "unlock on MSTCPY %x", lkb->lkb_id);
275362306a36Sopenharmony_ci		dlm_print_lkb(lkb);
275462306a36Sopenharmony_ci		goto out;
275562306a36Sopenharmony_ci	}
275662306a36Sopenharmony_ci
275762306a36Sopenharmony_ci	/* an lkb may still exist even though the lock is EOL'ed due to a
275862306a36Sopenharmony_ci	 * cancel, unlock or failed noqueue request; an app can't use these
275962306a36Sopenharmony_ci	 * locks; return same error as if the lkid had not been found at all
276062306a36Sopenharmony_ci	 */
276162306a36Sopenharmony_ci
276262306a36Sopenharmony_ci	if (test_bit(DLM_IFL_ENDOFLIFE_BIT, &lkb->lkb_iflags)) {
276362306a36Sopenharmony_ci		log_debug(ls, "unlock on ENDOFLIFE %x", lkb->lkb_id);
276462306a36Sopenharmony_ci		rv = -ENOENT;
276562306a36Sopenharmony_ci		goto out;
276662306a36Sopenharmony_ci	}
276762306a36Sopenharmony_ci
276862306a36Sopenharmony_ci	/* cancel not allowed with another cancel/unlock in progress */
276962306a36Sopenharmony_ci
277062306a36Sopenharmony_ci	if (args->flags & DLM_LKF_CANCEL) {
277162306a36Sopenharmony_ci		if (lkb->lkb_exflags & DLM_LKF_CANCEL)
277262306a36Sopenharmony_ci			goto out;
277362306a36Sopenharmony_ci
277462306a36Sopenharmony_ci		if (is_overlap(lkb))
277562306a36Sopenharmony_ci			goto out;
277662306a36Sopenharmony_ci
277762306a36Sopenharmony_ci		if (test_bit(DLM_IFL_RESEND_BIT, &lkb->lkb_iflags)) {
277862306a36Sopenharmony_ci			set_bit(DLM_IFL_OVERLAP_CANCEL_BIT, &lkb->lkb_iflags);
277962306a36Sopenharmony_ci			rv = -EBUSY;
278062306a36Sopenharmony_ci			goto out;
278162306a36Sopenharmony_ci		}
278262306a36Sopenharmony_ci
278362306a36Sopenharmony_ci		/* there's nothing to cancel */
278462306a36Sopenharmony_ci		if (lkb->lkb_status == DLM_LKSTS_GRANTED &&
278562306a36Sopenharmony_ci		    !lkb->lkb_wait_type) {
278662306a36Sopenharmony_ci			rv = -EBUSY;
278762306a36Sopenharmony_ci			goto out;
278862306a36Sopenharmony_ci		}
278962306a36Sopenharmony_ci
279062306a36Sopenharmony_ci		switch (lkb->lkb_wait_type) {
279162306a36Sopenharmony_ci		case DLM_MSG_LOOKUP:
279262306a36Sopenharmony_ci		case DLM_MSG_REQUEST:
279362306a36Sopenharmony_ci			set_bit(DLM_IFL_OVERLAP_CANCEL_BIT, &lkb->lkb_iflags);
279462306a36Sopenharmony_ci			rv = -EBUSY;
279562306a36Sopenharmony_ci			goto out;
279662306a36Sopenharmony_ci		case DLM_MSG_UNLOCK:
279762306a36Sopenharmony_ci		case DLM_MSG_CANCEL:
279862306a36Sopenharmony_ci			goto out;
279962306a36Sopenharmony_ci		}
280062306a36Sopenharmony_ci		/* add_to_waiters() will set OVERLAP_CANCEL */
280162306a36Sopenharmony_ci		goto out_ok;
280262306a36Sopenharmony_ci	}
280362306a36Sopenharmony_ci
280462306a36Sopenharmony_ci	/* do we need to allow a force-unlock if there's a normal unlock
280562306a36Sopenharmony_ci	   already in progress?  in what conditions could the normal unlock
280662306a36Sopenharmony_ci	   fail such that we'd want to send a force-unlock to be sure? */
280762306a36Sopenharmony_ci
280862306a36Sopenharmony_ci	if (args->flags & DLM_LKF_FORCEUNLOCK) {
280962306a36Sopenharmony_ci		if (lkb->lkb_exflags & DLM_LKF_FORCEUNLOCK)
281062306a36Sopenharmony_ci			goto out;
281162306a36Sopenharmony_ci
281262306a36Sopenharmony_ci		if (is_overlap_unlock(lkb))
281362306a36Sopenharmony_ci			goto out;
281462306a36Sopenharmony_ci
281562306a36Sopenharmony_ci		if (test_bit(DLM_IFL_RESEND_BIT, &lkb->lkb_iflags)) {
281662306a36Sopenharmony_ci			set_bit(DLM_IFL_OVERLAP_UNLOCK_BIT, &lkb->lkb_iflags);
281762306a36Sopenharmony_ci			rv = -EBUSY;
281862306a36Sopenharmony_ci			goto out;
281962306a36Sopenharmony_ci		}
282062306a36Sopenharmony_ci
282162306a36Sopenharmony_ci		switch (lkb->lkb_wait_type) {
282262306a36Sopenharmony_ci		case DLM_MSG_LOOKUP:
282362306a36Sopenharmony_ci		case DLM_MSG_REQUEST:
282462306a36Sopenharmony_ci			set_bit(DLM_IFL_OVERLAP_UNLOCK_BIT, &lkb->lkb_iflags);
282562306a36Sopenharmony_ci			rv = -EBUSY;
282662306a36Sopenharmony_ci			goto out;
282762306a36Sopenharmony_ci		case DLM_MSG_UNLOCK:
282862306a36Sopenharmony_ci			goto out;
282962306a36Sopenharmony_ci		}
283062306a36Sopenharmony_ci		/* add_to_waiters() will set OVERLAP_UNLOCK */
283162306a36Sopenharmony_ci	}
283262306a36Sopenharmony_ci
283362306a36Sopenharmony_ci out_ok:
283462306a36Sopenharmony_ci	/* an overlapping op shouldn't blow away exflags from other op */
283562306a36Sopenharmony_ci	lkb->lkb_exflags |= args->flags;
283662306a36Sopenharmony_ci	dlm_set_sbflags_val(lkb, 0);
283762306a36Sopenharmony_ci	lkb->lkb_astparam = args->astparam;
283862306a36Sopenharmony_ci	rv = 0;
283962306a36Sopenharmony_ci out:
284062306a36Sopenharmony_ci	switch (rv) {
284162306a36Sopenharmony_ci	case 0:
284262306a36Sopenharmony_ci		break;
284362306a36Sopenharmony_ci	case -EINVAL:
284462306a36Sopenharmony_ci		/* annoy the user because dlm usage is wrong */
284562306a36Sopenharmony_ci		WARN_ON(1);
284662306a36Sopenharmony_ci		log_error(ls, "%s %d %x %x %x %x %d %s", __func__, rv,
284762306a36Sopenharmony_ci			  lkb->lkb_id, dlm_iflags_val(lkb), lkb->lkb_exflags,
284862306a36Sopenharmony_ci			  args->flags, lkb->lkb_wait_type,
284962306a36Sopenharmony_ci			  lkb->lkb_resource->res_name);
285062306a36Sopenharmony_ci		break;
285162306a36Sopenharmony_ci	default:
285262306a36Sopenharmony_ci		log_debug(ls, "%s %d %x %x %x %x %d %s", __func__, rv,
285362306a36Sopenharmony_ci			  lkb->lkb_id, dlm_iflags_val(lkb), lkb->lkb_exflags,
285462306a36Sopenharmony_ci			  args->flags, lkb->lkb_wait_type,
285562306a36Sopenharmony_ci			  lkb->lkb_resource->res_name);
285662306a36Sopenharmony_ci		break;
285762306a36Sopenharmony_ci	}
285862306a36Sopenharmony_ci
285962306a36Sopenharmony_ci	return rv;
286062306a36Sopenharmony_ci}
286162306a36Sopenharmony_ci
286262306a36Sopenharmony_ci/*
286362306a36Sopenharmony_ci * Four stage 4 varieties:
286462306a36Sopenharmony_ci * do_request(), do_convert(), do_unlock(), do_cancel()
286562306a36Sopenharmony_ci * These are called on the master node for the given lock and
286662306a36Sopenharmony_ci * from the central locking logic.
286762306a36Sopenharmony_ci */
286862306a36Sopenharmony_ci
286962306a36Sopenharmony_cistatic int do_request(struct dlm_rsb *r, struct dlm_lkb *lkb)
287062306a36Sopenharmony_ci{
287162306a36Sopenharmony_ci	int error = 0;
287262306a36Sopenharmony_ci
287362306a36Sopenharmony_ci	if (can_be_granted(r, lkb, 1, 0, NULL)) {
287462306a36Sopenharmony_ci		grant_lock(r, lkb);
287562306a36Sopenharmony_ci		queue_cast(r, lkb, 0);
287662306a36Sopenharmony_ci		goto out;
287762306a36Sopenharmony_ci	}
287862306a36Sopenharmony_ci
287962306a36Sopenharmony_ci	if (can_be_queued(lkb)) {
288062306a36Sopenharmony_ci		error = -EINPROGRESS;
288162306a36Sopenharmony_ci		add_lkb(r, lkb, DLM_LKSTS_WAITING);
288262306a36Sopenharmony_ci		goto out;
288362306a36Sopenharmony_ci	}
288462306a36Sopenharmony_ci
288562306a36Sopenharmony_ci	error = -EAGAIN;
288662306a36Sopenharmony_ci	queue_cast(r, lkb, -EAGAIN);
288762306a36Sopenharmony_ci out:
288862306a36Sopenharmony_ci	return error;
288962306a36Sopenharmony_ci}
289062306a36Sopenharmony_ci
289162306a36Sopenharmony_cistatic void do_request_effects(struct dlm_rsb *r, struct dlm_lkb *lkb,
289262306a36Sopenharmony_ci			       int error)
289362306a36Sopenharmony_ci{
289462306a36Sopenharmony_ci	switch (error) {
289562306a36Sopenharmony_ci	case -EAGAIN:
289662306a36Sopenharmony_ci		if (force_blocking_asts(lkb))
289762306a36Sopenharmony_ci			send_blocking_asts_all(r, lkb);
289862306a36Sopenharmony_ci		break;
289962306a36Sopenharmony_ci	case -EINPROGRESS:
290062306a36Sopenharmony_ci		send_blocking_asts(r, lkb);
290162306a36Sopenharmony_ci		break;
290262306a36Sopenharmony_ci	}
290362306a36Sopenharmony_ci}
290462306a36Sopenharmony_ci
290562306a36Sopenharmony_cistatic int do_convert(struct dlm_rsb *r, struct dlm_lkb *lkb)
290662306a36Sopenharmony_ci{
290762306a36Sopenharmony_ci	int error = 0;
290862306a36Sopenharmony_ci	int deadlk = 0;
290962306a36Sopenharmony_ci
291062306a36Sopenharmony_ci	/* changing an existing lock may allow others to be granted */
291162306a36Sopenharmony_ci
291262306a36Sopenharmony_ci	if (can_be_granted(r, lkb, 1, 0, &deadlk)) {
291362306a36Sopenharmony_ci		grant_lock(r, lkb);
291462306a36Sopenharmony_ci		queue_cast(r, lkb, 0);
291562306a36Sopenharmony_ci		goto out;
291662306a36Sopenharmony_ci	}
291762306a36Sopenharmony_ci
291862306a36Sopenharmony_ci	/* can_be_granted() detected that this lock would block in a conversion
291962306a36Sopenharmony_ci	   deadlock, so we leave it on the granted queue and return EDEADLK in
292062306a36Sopenharmony_ci	   the ast for the convert. */
292162306a36Sopenharmony_ci
292262306a36Sopenharmony_ci	if (deadlk && !(lkb->lkb_exflags & DLM_LKF_NODLCKWT)) {
292362306a36Sopenharmony_ci		/* it's left on the granted queue */
292462306a36Sopenharmony_ci		revert_lock(r, lkb);
292562306a36Sopenharmony_ci		queue_cast(r, lkb, -EDEADLK);
292662306a36Sopenharmony_ci		error = -EDEADLK;
292762306a36Sopenharmony_ci		goto out;
292862306a36Sopenharmony_ci	}
292962306a36Sopenharmony_ci
293062306a36Sopenharmony_ci	/* is_demoted() means the can_be_granted() above set the grmode
293162306a36Sopenharmony_ci	   to NL, and left us on the granted queue.  This auto-demotion
293262306a36Sopenharmony_ci	   (due to CONVDEADLK) might mean other locks, and/or this lock, are
293362306a36Sopenharmony_ci	   now grantable.  We have to try to grant other converting locks
293462306a36Sopenharmony_ci	   before we try again to grant this one. */
293562306a36Sopenharmony_ci
293662306a36Sopenharmony_ci	if (is_demoted(lkb)) {
293762306a36Sopenharmony_ci		grant_pending_convert(r, DLM_LOCK_IV, NULL, NULL);
293862306a36Sopenharmony_ci		if (_can_be_granted(r, lkb, 1, 0)) {
293962306a36Sopenharmony_ci			grant_lock(r, lkb);
294062306a36Sopenharmony_ci			queue_cast(r, lkb, 0);
294162306a36Sopenharmony_ci			goto out;
294262306a36Sopenharmony_ci		}
294362306a36Sopenharmony_ci		/* else fall through and move to convert queue */
294462306a36Sopenharmony_ci	}
294562306a36Sopenharmony_ci
294662306a36Sopenharmony_ci	if (can_be_queued(lkb)) {
294762306a36Sopenharmony_ci		error = -EINPROGRESS;
294862306a36Sopenharmony_ci		del_lkb(r, lkb);
294962306a36Sopenharmony_ci		add_lkb(r, lkb, DLM_LKSTS_CONVERT);
295062306a36Sopenharmony_ci		goto out;
295162306a36Sopenharmony_ci	}
295262306a36Sopenharmony_ci
295362306a36Sopenharmony_ci	error = -EAGAIN;
295462306a36Sopenharmony_ci	queue_cast(r, lkb, -EAGAIN);
295562306a36Sopenharmony_ci out:
295662306a36Sopenharmony_ci	return error;
295762306a36Sopenharmony_ci}
295862306a36Sopenharmony_ci
295962306a36Sopenharmony_cistatic void do_convert_effects(struct dlm_rsb *r, struct dlm_lkb *lkb,
296062306a36Sopenharmony_ci			       int error)
296162306a36Sopenharmony_ci{
296262306a36Sopenharmony_ci	switch (error) {
296362306a36Sopenharmony_ci	case 0:
296462306a36Sopenharmony_ci		grant_pending_locks(r, NULL);
296562306a36Sopenharmony_ci		/* grant_pending_locks also sends basts */
296662306a36Sopenharmony_ci		break;
296762306a36Sopenharmony_ci	case -EAGAIN:
296862306a36Sopenharmony_ci		if (force_blocking_asts(lkb))
296962306a36Sopenharmony_ci			send_blocking_asts_all(r, lkb);
297062306a36Sopenharmony_ci		break;
297162306a36Sopenharmony_ci	case -EINPROGRESS:
297262306a36Sopenharmony_ci		send_blocking_asts(r, lkb);
297362306a36Sopenharmony_ci		break;
297462306a36Sopenharmony_ci	}
297562306a36Sopenharmony_ci}
297662306a36Sopenharmony_ci
297762306a36Sopenharmony_cistatic int do_unlock(struct dlm_rsb *r, struct dlm_lkb *lkb)
297862306a36Sopenharmony_ci{
297962306a36Sopenharmony_ci	remove_lock(r, lkb);
298062306a36Sopenharmony_ci	queue_cast(r, lkb, -DLM_EUNLOCK);
298162306a36Sopenharmony_ci	return -DLM_EUNLOCK;
298262306a36Sopenharmony_ci}
298362306a36Sopenharmony_ci
298462306a36Sopenharmony_cistatic void do_unlock_effects(struct dlm_rsb *r, struct dlm_lkb *lkb,
298562306a36Sopenharmony_ci			      int error)
298662306a36Sopenharmony_ci{
298762306a36Sopenharmony_ci	grant_pending_locks(r, NULL);
298862306a36Sopenharmony_ci}
298962306a36Sopenharmony_ci
299062306a36Sopenharmony_ci/* returns: 0 did nothing, -DLM_ECANCEL canceled lock */
299162306a36Sopenharmony_ci
299262306a36Sopenharmony_cistatic int do_cancel(struct dlm_rsb *r, struct dlm_lkb *lkb)
299362306a36Sopenharmony_ci{
299462306a36Sopenharmony_ci	int error;
299562306a36Sopenharmony_ci
299662306a36Sopenharmony_ci	error = revert_lock(r, lkb);
299762306a36Sopenharmony_ci	if (error) {
299862306a36Sopenharmony_ci		queue_cast(r, lkb, -DLM_ECANCEL);
299962306a36Sopenharmony_ci		return -DLM_ECANCEL;
300062306a36Sopenharmony_ci	}
300162306a36Sopenharmony_ci	return 0;
300262306a36Sopenharmony_ci}
300362306a36Sopenharmony_ci
300462306a36Sopenharmony_cistatic void do_cancel_effects(struct dlm_rsb *r, struct dlm_lkb *lkb,
300562306a36Sopenharmony_ci			      int error)
300662306a36Sopenharmony_ci{
300762306a36Sopenharmony_ci	if (error)
300862306a36Sopenharmony_ci		grant_pending_locks(r, NULL);
300962306a36Sopenharmony_ci}
301062306a36Sopenharmony_ci
301162306a36Sopenharmony_ci/*
301262306a36Sopenharmony_ci * Four stage 3 varieties:
301362306a36Sopenharmony_ci * _request_lock(), _convert_lock(), _unlock_lock(), _cancel_lock()
301462306a36Sopenharmony_ci */
301562306a36Sopenharmony_ci
301662306a36Sopenharmony_ci/* add a new lkb to a possibly new rsb, called by requesting process */
301762306a36Sopenharmony_ci
301862306a36Sopenharmony_cistatic int _request_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)
301962306a36Sopenharmony_ci{
302062306a36Sopenharmony_ci	int error;
302162306a36Sopenharmony_ci
302262306a36Sopenharmony_ci	/* set_master: sets lkb nodeid from r */
302362306a36Sopenharmony_ci
302462306a36Sopenharmony_ci	error = set_master(r, lkb);
302562306a36Sopenharmony_ci	if (error < 0)
302662306a36Sopenharmony_ci		goto out;
302762306a36Sopenharmony_ci	if (error) {
302862306a36Sopenharmony_ci		error = 0;
302962306a36Sopenharmony_ci		goto out;
303062306a36Sopenharmony_ci	}
303162306a36Sopenharmony_ci
303262306a36Sopenharmony_ci	if (is_remote(r)) {
303362306a36Sopenharmony_ci		/* receive_request() calls do_request() on remote node */
303462306a36Sopenharmony_ci		error = send_request(r, lkb);
303562306a36Sopenharmony_ci	} else {
303662306a36Sopenharmony_ci		error = do_request(r, lkb);
303762306a36Sopenharmony_ci		/* for remote locks the request_reply is sent
303862306a36Sopenharmony_ci		   between do_request and do_request_effects */
303962306a36Sopenharmony_ci		do_request_effects(r, lkb, error);
304062306a36Sopenharmony_ci	}
304162306a36Sopenharmony_ci out:
304262306a36Sopenharmony_ci	return error;
304362306a36Sopenharmony_ci}
304462306a36Sopenharmony_ci
304562306a36Sopenharmony_ci/* change some property of an existing lkb, e.g. mode */
304662306a36Sopenharmony_ci
304762306a36Sopenharmony_cistatic int _convert_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)
304862306a36Sopenharmony_ci{
304962306a36Sopenharmony_ci	int error;
305062306a36Sopenharmony_ci
305162306a36Sopenharmony_ci	if (is_remote(r)) {
305262306a36Sopenharmony_ci		/* receive_convert() calls do_convert() on remote node */
305362306a36Sopenharmony_ci		error = send_convert(r, lkb);
305462306a36Sopenharmony_ci	} else {
305562306a36Sopenharmony_ci		error = do_convert(r, lkb);
305662306a36Sopenharmony_ci		/* for remote locks the convert_reply is sent
305762306a36Sopenharmony_ci		   between do_convert and do_convert_effects */
305862306a36Sopenharmony_ci		do_convert_effects(r, lkb, error);
305962306a36Sopenharmony_ci	}
306062306a36Sopenharmony_ci
306162306a36Sopenharmony_ci	return error;
306262306a36Sopenharmony_ci}
306362306a36Sopenharmony_ci
306462306a36Sopenharmony_ci/* remove an existing lkb from the granted queue */
306562306a36Sopenharmony_ci
306662306a36Sopenharmony_cistatic int _unlock_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)
306762306a36Sopenharmony_ci{
306862306a36Sopenharmony_ci	int error;
306962306a36Sopenharmony_ci
307062306a36Sopenharmony_ci	if (is_remote(r)) {
307162306a36Sopenharmony_ci		/* receive_unlock() calls do_unlock() on remote node */
307262306a36Sopenharmony_ci		error = send_unlock(r, lkb);
307362306a36Sopenharmony_ci	} else {
307462306a36Sopenharmony_ci		error = do_unlock(r, lkb);
307562306a36Sopenharmony_ci		/* for remote locks the unlock_reply is sent
307662306a36Sopenharmony_ci		   between do_unlock and do_unlock_effects */
307762306a36Sopenharmony_ci		do_unlock_effects(r, lkb, error);
307862306a36Sopenharmony_ci	}
307962306a36Sopenharmony_ci
308062306a36Sopenharmony_ci	return error;
308162306a36Sopenharmony_ci}
308262306a36Sopenharmony_ci
308362306a36Sopenharmony_ci/* remove an existing lkb from the convert or wait queue */
308462306a36Sopenharmony_ci
308562306a36Sopenharmony_cistatic int _cancel_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)
308662306a36Sopenharmony_ci{
308762306a36Sopenharmony_ci	int error;
308862306a36Sopenharmony_ci
308962306a36Sopenharmony_ci	if (is_remote(r)) {
309062306a36Sopenharmony_ci		/* receive_cancel() calls do_cancel() on remote node */
309162306a36Sopenharmony_ci		error = send_cancel(r, lkb);
309262306a36Sopenharmony_ci	} else {
309362306a36Sopenharmony_ci		error = do_cancel(r, lkb);
309462306a36Sopenharmony_ci		/* for remote locks the cancel_reply is sent
309562306a36Sopenharmony_ci		   between do_cancel and do_cancel_effects */
309662306a36Sopenharmony_ci		do_cancel_effects(r, lkb, error);
309762306a36Sopenharmony_ci	}
309862306a36Sopenharmony_ci
309962306a36Sopenharmony_ci	return error;
310062306a36Sopenharmony_ci}
310162306a36Sopenharmony_ci
310262306a36Sopenharmony_ci/*
310362306a36Sopenharmony_ci * Four stage 2 varieties:
310462306a36Sopenharmony_ci * request_lock(), convert_lock(), unlock_lock(), cancel_lock()
310562306a36Sopenharmony_ci */
310662306a36Sopenharmony_ci
310762306a36Sopenharmony_cistatic int request_lock(struct dlm_ls *ls, struct dlm_lkb *lkb,
310862306a36Sopenharmony_ci			const void *name, int len,
310962306a36Sopenharmony_ci			struct dlm_args *args)
311062306a36Sopenharmony_ci{
311162306a36Sopenharmony_ci	struct dlm_rsb *r;
311262306a36Sopenharmony_ci	int error;
311362306a36Sopenharmony_ci
311462306a36Sopenharmony_ci	error = validate_lock_args(ls, lkb, args);
311562306a36Sopenharmony_ci	if (error)
311662306a36Sopenharmony_ci		return error;
311762306a36Sopenharmony_ci
311862306a36Sopenharmony_ci	error = find_rsb(ls, name, len, 0, R_REQUEST, &r);
311962306a36Sopenharmony_ci	if (error)
312062306a36Sopenharmony_ci		return error;
312162306a36Sopenharmony_ci
312262306a36Sopenharmony_ci	lock_rsb(r);
312362306a36Sopenharmony_ci
312462306a36Sopenharmony_ci	attach_lkb(r, lkb);
312562306a36Sopenharmony_ci	lkb->lkb_lksb->sb_lkid = lkb->lkb_id;
312662306a36Sopenharmony_ci
312762306a36Sopenharmony_ci	error = _request_lock(r, lkb);
312862306a36Sopenharmony_ci
312962306a36Sopenharmony_ci	unlock_rsb(r);
313062306a36Sopenharmony_ci	put_rsb(r);
313162306a36Sopenharmony_ci	return error;
313262306a36Sopenharmony_ci}
313362306a36Sopenharmony_ci
313462306a36Sopenharmony_cistatic int convert_lock(struct dlm_ls *ls, struct dlm_lkb *lkb,
313562306a36Sopenharmony_ci			struct dlm_args *args)
313662306a36Sopenharmony_ci{
313762306a36Sopenharmony_ci	struct dlm_rsb *r;
313862306a36Sopenharmony_ci	int error;
313962306a36Sopenharmony_ci
314062306a36Sopenharmony_ci	r = lkb->lkb_resource;
314162306a36Sopenharmony_ci
314262306a36Sopenharmony_ci	hold_rsb(r);
314362306a36Sopenharmony_ci	lock_rsb(r);
314462306a36Sopenharmony_ci
314562306a36Sopenharmony_ci	error = validate_lock_args(ls, lkb, args);
314662306a36Sopenharmony_ci	if (error)
314762306a36Sopenharmony_ci		goto out;
314862306a36Sopenharmony_ci
314962306a36Sopenharmony_ci	error = _convert_lock(r, lkb);
315062306a36Sopenharmony_ci out:
315162306a36Sopenharmony_ci	unlock_rsb(r);
315262306a36Sopenharmony_ci	put_rsb(r);
315362306a36Sopenharmony_ci	return error;
315462306a36Sopenharmony_ci}
315562306a36Sopenharmony_ci
315662306a36Sopenharmony_cistatic int unlock_lock(struct dlm_ls *ls, struct dlm_lkb *lkb,
315762306a36Sopenharmony_ci		       struct dlm_args *args)
315862306a36Sopenharmony_ci{
315962306a36Sopenharmony_ci	struct dlm_rsb *r;
316062306a36Sopenharmony_ci	int error;
316162306a36Sopenharmony_ci
316262306a36Sopenharmony_ci	r = lkb->lkb_resource;
316362306a36Sopenharmony_ci
316462306a36Sopenharmony_ci	hold_rsb(r);
316562306a36Sopenharmony_ci	lock_rsb(r);
316662306a36Sopenharmony_ci
316762306a36Sopenharmony_ci	error = validate_unlock_args(lkb, args);
316862306a36Sopenharmony_ci	if (error)
316962306a36Sopenharmony_ci		goto out;
317062306a36Sopenharmony_ci
317162306a36Sopenharmony_ci	error = _unlock_lock(r, lkb);
317262306a36Sopenharmony_ci out:
317362306a36Sopenharmony_ci	unlock_rsb(r);
317462306a36Sopenharmony_ci	put_rsb(r);
317562306a36Sopenharmony_ci	return error;
317662306a36Sopenharmony_ci}
317762306a36Sopenharmony_ci
317862306a36Sopenharmony_cistatic int cancel_lock(struct dlm_ls *ls, struct dlm_lkb *lkb,
317962306a36Sopenharmony_ci		       struct dlm_args *args)
318062306a36Sopenharmony_ci{
318162306a36Sopenharmony_ci	struct dlm_rsb *r;
318262306a36Sopenharmony_ci	int error;
318362306a36Sopenharmony_ci
318462306a36Sopenharmony_ci	r = lkb->lkb_resource;
318562306a36Sopenharmony_ci
318662306a36Sopenharmony_ci	hold_rsb(r);
318762306a36Sopenharmony_ci	lock_rsb(r);
318862306a36Sopenharmony_ci
318962306a36Sopenharmony_ci	error = validate_unlock_args(lkb, args);
319062306a36Sopenharmony_ci	if (error)
319162306a36Sopenharmony_ci		goto out;
319262306a36Sopenharmony_ci
319362306a36Sopenharmony_ci	error = _cancel_lock(r, lkb);
319462306a36Sopenharmony_ci out:
319562306a36Sopenharmony_ci	unlock_rsb(r);
319662306a36Sopenharmony_ci	put_rsb(r);
319762306a36Sopenharmony_ci	return error;
319862306a36Sopenharmony_ci}
319962306a36Sopenharmony_ci
320062306a36Sopenharmony_ci/*
320162306a36Sopenharmony_ci * Two stage 1 varieties:  dlm_lock() and dlm_unlock()
320262306a36Sopenharmony_ci */
320362306a36Sopenharmony_ci
320462306a36Sopenharmony_ciint dlm_lock(dlm_lockspace_t *lockspace,
320562306a36Sopenharmony_ci	     int mode,
320662306a36Sopenharmony_ci	     struct dlm_lksb *lksb,
320762306a36Sopenharmony_ci	     uint32_t flags,
320862306a36Sopenharmony_ci	     const void *name,
320962306a36Sopenharmony_ci	     unsigned int namelen,
321062306a36Sopenharmony_ci	     uint32_t parent_lkid,
321162306a36Sopenharmony_ci	     void (*ast) (void *astarg),
321262306a36Sopenharmony_ci	     void *astarg,
321362306a36Sopenharmony_ci	     void (*bast) (void *astarg, int mode))
321462306a36Sopenharmony_ci{
321562306a36Sopenharmony_ci	struct dlm_ls *ls;
321662306a36Sopenharmony_ci	struct dlm_lkb *lkb;
321762306a36Sopenharmony_ci	struct dlm_args args;
321862306a36Sopenharmony_ci	int error, convert = flags & DLM_LKF_CONVERT;
321962306a36Sopenharmony_ci
322062306a36Sopenharmony_ci	ls = dlm_find_lockspace_local(lockspace);
322162306a36Sopenharmony_ci	if (!ls)
322262306a36Sopenharmony_ci		return -EINVAL;
322362306a36Sopenharmony_ci
322462306a36Sopenharmony_ci	dlm_lock_recovery(ls);
322562306a36Sopenharmony_ci
322662306a36Sopenharmony_ci	if (convert)
322762306a36Sopenharmony_ci		error = find_lkb(ls, lksb->sb_lkid, &lkb);
322862306a36Sopenharmony_ci	else
322962306a36Sopenharmony_ci		error = create_lkb(ls, &lkb);
323062306a36Sopenharmony_ci
323162306a36Sopenharmony_ci	if (error)
323262306a36Sopenharmony_ci		goto out;
323362306a36Sopenharmony_ci
323462306a36Sopenharmony_ci	trace_dlm_lock_start(ls, lkb, name, namelen, mode, flags);
323562306a36Sopenharmony_ci
323662306a36Sopenharmony_ci	error = set_lock_args(mode, lksb, flags, namelen, ast, astarg, bast,
323762306a36Sopenharmony_ci			      &args);
323862306a36Sopenharmony_ci	if (error)
323962306a36Sopenharmony_ci		goto out_put;
324062306a36Sopenharmony_ci
324162306a36Sopenharmony_ci	if (convert)
324262306a36Sopenharmony_ci		error = convert_lock(ls, lkb, &args);
324362306a36Sopenharmony_ci	else
324462306a36Sopenharmony_ci		error = request_lock(ls, lkb, name, namelen, &args);
324562306a36Sopenharmony_ci
324662306a36Sopenharmony_ci	if (error == -EINPROGRESS)
324762306a36Sopenharmony_ci		error = 0;
324862306a36Sopenharmony_ci out_put:
324962306a36Sopenharmony_ci	trace_dlm_lock_end(ls, lkb, name, namelen, mode, flags, error, true);
325062306a36Sopenharmony_ci
325162306a36Sopenharmony_ci	if (convert || error)
325262306a36Sopenharmony_ci		__put_lkb(ls, lkb);
325362306a36Sopenharmony_ci	if (error == -EAGAIN || error == -EDEADLK)
325462306a36Sopenharmony_ci		error = 0;
325562306a36Sopenharmony_ci out:
325662306a36Sopenharmony_ci	dlm_unlock_recovery(ls);
325762306a36Sopenharmony_ci	dlm_put_lockspace(ls);
325862306a36Sopenharmony_ci	return error;
325962306a36Sopenharmony_ci}
326062306a36Sopenharmony_ci
326162306a36Sopenharmony_ciint dlm_unlock(dlm_lockspace_t *lockspace,
326262306a36Sopenharmony_ci	       uint32_t lkid,
326362306a36Sopenharmony_ci	       uint32_t flags,
326462306a36Sopenharmony_ci	       struct dlm_lksb *lksb,
326562306a36Sopenharmony_ci	       void *astarg)
326662306a36Sopenharmony_ci{
326762306a36Sopenharmony_ci	struct dlm_ls *ls;
326862306a36Sopenharmony_ci	struct dlm_lkb *lkb;
326962306a36Sopenharmony_ci	struct dlm_args args;
327062306a36Sopenharmony_ci	int error;
327162306a36Sopenharmony_ci
327262306a36Sopenharmony_ci	ls = dlm_find_lockspace_local(lockspace);
327362306a36Sopenharmony_ci	if (!ls)
327462306a36Sopenharmony_ci		return -EINVAL;
327562306a36Sopenharmony_ci
327662306a36Sopenharmony_ci	dlm_lock_recovery(ls);
327762306a36Sopenharmony_ci
327862306a36Sopenharmony_ci	error = find_lkb(ls, lkid, &lkb);
327962306a36Sopenharmony_ci	if (error)
328062306a36Sopenharmony_ci		goto out;
328162306a36Sopenharmony_ci
328262306a36Sopenharmony_ci	trace_dlm_unlock_start(ls, lkb, flags);
328362306a36Sopenharmony_ci
328462306a36Sopenharmony_ci	error = set_unlock_args(flags, astarg, &args);
328562306a36Sopenharmony_ci	if (error)
328662306a36Sopenharmony_ci		goto out_put;
328762306a36Sopenharmony_ci
328862306a36Sopenharmony_ci	if (flags & DLM_LKF_CANCEL)
328962306a36Sopenharmony_ci		error = cancel_lock(ls, lkb, &args);
329062306a36Sopenharmony_ci	else
329162306a36Sopenharmony_ci		error = unlock_lock(ls, lkb, &args);
329262306a36Sopenharmony_ci
329362306a36Sopenharmony_ci	if (error == -DLM_EUNLOCK || error == -DLM_ECANCEL)
329462306a36Sopenharmony_ci		error = 0;
329562306a36Sopenharmony_ci	if (error == -EBUSY && (flags & (DLM_LKF_CANCEL | DLM_LKF_FORCEUNLOCK)))
329662306a36Sopenharmony_ci		error = 0;
329762306a36Sopenharmony_ci out_put:
329862306a36Sopenharmony_ci	trace_dlm_unlock_end(ls, lkb, flags, error);
329962306a36Sopenharmony_ci
330062306a36Sopenharmony_ci	dlm_put_lkb(lkb);
330162306a36Sopenharmony_ci out:
330262306a36Sopenharmony_ci	dlm_unlock_recovery(ls);
330362306a36Sopenharmony_ci	dlm_put_lockspace(ls);
330462306a36Sopenharmony_ci	return error;
330562306a36Sopenharmony_ci}
330662306a36Sopenharmony_ci
330762306a36Sopenharmony_ci/*
330862306a36Sopenharmony_ci * send/receive routines for remote operations and replies
330962306a36Sopenharmony_ci *
331062306a36Sopenharmony_ci * send_args
331162306a36Sopenharmony_ci * send_common
331262306a36Sopenharmony_ci * send_request			receive_request
331362306a36Sopenharmony_ci * send_convert			receive_convert
331462306a36Sopenharmony_ci * send_unlock			receive_unlock
331562306a36Sopenharmony_ci * send_cancel			receive_cancel
331662306a36Sopenharmony_ci * send_grant			receive_grant
331762306a36Sopenharmony_ci * send_bast			receive_bast
331862306a36Sopenharmony_ci * send_lookup			receive_lookup
331962306a36Sopenharmony_ci * send_remove			receive_remove
332062306a36Sopenharmony_ci *
332162306a36Sopenharmony_ci * 				send_common_reply
332262306a36Sopenharmony_ci * receive_request_reply	send_request_reply
332362306a36Sopenharmony_ci * receive_convert_reply	send_convert_reply
332462306a36Sopenharmony_ci * receive_unlock_reply		send_unlock_reply
332562306a36Sopenharmony_ci * receive_cancel_reply		send_cancel_reply
332662306a36Sopenharmony_ci * receive_lookup_reply		send_lookup_reply
332762306a36Sopenharmony_ci */
332862306a36Sopenharmony_ci
332962306a36Sopenharmony_cistatic int _create_message(struct dlm_ls *ls, int mb_len,
333062306a36Sopenharmony_ci			   int to_nodeid, int mstype,
333162306a36Sopenharmony_ci			   struct dlm_message **ms_ret,
333262306a36Sopenharmony_ci			   struct dlm_mhandle **mh_ret,
333362306a36Sopenharmony_ci			   gfp_t allocation)
333462306a36Sopenharmony_ci{
333562306a36Sopenharmony_ci	struct dlm_message *ms;
333662306a36Sopenharmony_ci	struct dlm_mhandle *mh;
333762306a36Sopenharmony_ci	char *mb;
333862306a36Sopenharmony_ci
333962306a36Sopenharmony_ci	/* get_buffer gives us a message handle (mh) that we need to
334062306a36Sopenharmony_ci	   pass into midcomms_commit and a message buffer (mb) that we
334162306a36Sopenharmony_ci	   write our data into */
334262306a36Sopenharmony_ci
334362306a36Sopenharmony_ci	mh = dlm_midcomms_get_mhandle(to_nodeid, mb_len, allocation, &mb);
334462306a36Sopenharmony_ci	if (!mh)
334562306a36Sopenharmony_ci		return -ENOBUFS;
334662306a36Sopenharmony_ci
334762306a36Sopenharmony_ci	ms = (struct dlm_message *) mb;
334862306a36Sopenharmony_ci
334962306a36Sopenharmony_ci	ms->m_header.h_version = cpu_to_le32(DLM_HEADER_MAJOR | DLM_HEADER_MINOR);
335062306a36Sopenharmony_ci	ms->m_header.u.h_lockspace = cpu_to_le32(ls->ls_global_id);
335162306a36Sopenharmony_ci	ms->m_header.h_nodeid = cpu_to_le32(dlm_our_nodeid());
335262306a36Sopenharmony_ci	ms->m_header.h_length = cpu_to_le16(mb_len);
335362306a36Sopenharmony_ci	ms->m_header.h_cmd = DLM_MSG;
335462306a36Sopenharmony_ci
335562306a36Sopenharmony_ci	ms->m_type = cpu_to_le32(mstype);
335662306a36Sopenharmony_ci
335762306a36Sopenharmony_ci	*mh_ret = mh;
335862306a36Sopenharmony_ci	*ms_ret = ms;
335962306a36Sopenharmony_ci	return 0;
336062306a36Sopenharmony_ci}
336162306a36Sopenharmony_ci
336262306a36Sopenharmony_cistatic int create_message(struct dlm_rsb *r, struct dlm_lkb *lkb,
336362306a36Sopenharmony_ci			  int to_nodeid, int mstype,
336462306a36Sopenharmony_ci			  struct dlm_message **ms_ret,
336562306a36Sopenharmony_ci			  struct dlm_mhandle **mh_ret,
336662306a36Sopenharmony_ci			  gfp_t allocation)
336762306a36Sopenharmony_ci{
336862306a36Sopenharmony_ci	int mb_len = sizeof(struct dlm_message);
336962306a36Sopenharmony_ci
337062306a36Sopenharmony_ci	switch (mstype) {
337162306a36Sopenharmony_ci	case DLM_MSG_REQUEST:
337262306a36Sopenharmony_ci	case DLM_MSG_LOOKUP:
337362306a36Sopenharmony_ci	case DLM_MSG_REMOVE:
337462306a36Sopenharmony_ci		mb_len += r->res_length;
337562306a36Sopenharmony_ci		break;
337662306a36Sopenharmony_ci	case DLM_MSG_CONVERT:
337762306a36Sopenharmony_ci	case DLM_MSG_UNLOCK:
337862306a36Sopenharmony_ci	case DLM_MSG_REQUEST_REPLY:
337962306a36Sopenharmony_ci	case DLM_MSG_CONVERT_REPLY:
338062306a36Sopenharmony_ci	case DLM_MSG_GRANT:
338162306a36Sopenharmony_ci		if (lkb && lkb->lkb_lvbptr && (lkb->lkb_exflags & DLM_LKF_VALBLK))
338262306a36Sopenharmony_ci			mb_len += r->res_ls->ls_lvblen;
338362306a36Sopenharmony_ci		break;
338462306a36Sopenharmony_ci	}
338562306a36Sopenharmony_ci
338662306a36Sopenharmony_ci	return _create_message(r->res_ls, mb_len, to_nodeid, mstype,
338762306a36Sopenharmony_ci			       ms_ret, mh_ret, allocation);
338862306a36Sopenharmony_ci}
338962306a36Sopenharmony_ci
339062306a36Sopenharmony_ci/* further lowcomms enhancements or alternate implementations may make
339162306a36Sopenharmony_ci   the return value from this function useful at some point */
339262306a36Sopenharmony_ci
339362306a36Sopenharmony_cistatic int send_message(struct dlm_mhandle *mh, struct dlm_message *ms,
339462306a36Sopenharmony_ci			const void *name, int namelen)
339562306a36Sopenharmony_ci{
339662306a36Sopenharmony_ci	dlm_midcomms_commit_mhandle(mh, name, namelen);
339762306a36Sopenharmony_ci	return 0;
339862306a36Sopenharmony_ci}
339962306a36Sopenharmony_ci
340062306a36Sopenharmony_cistatic void send_args(struct dlm_rsb *r, struct dlm_lkb *lkb,
340162306a36Sopenharmony_ci		      struct dlm_message *ms)
340262306a36Sopenharmony_ci{
340362306a36Sopenharmony_ci	ms->m_nodeid   = cpu_to_le32(lkb->lkb_nodeid);
340462306a36Sopenharmony_ci	ms->m_pid      = cpu_to_le32(lkb->lkb_ownpid);
340562306a36Sopenharmony_ci	ms->m_lkid     = cpu_to_le32(lkb->lkb_id);
340662306a36Sopenharmony_ci	ms->m_remid    = cpu_to_le32(lkb->lkb_remid);
340762306a36Sopenharmony_ci	ms->m_exflags  = cpu_to_le32(lkb->lkb_exflags);
340862306a36Sopenharmony_ci	ms->m_sbflags  = cpu_to_le32(dlm_sbflags_val(lkb));
340962306a36Sopenharmony_ci	ms->m_flags    = cpu_to_le32(dlm_dflags_val(lkb));
341062306a36Sopenharmony_ci	ms->m_lvbseq   = cpu_to_le32(lkb->lkb_lvbseq);
341162306a36Sopenharmony_ci	ms->m_status   = cpu_to_le32(lkb->lkb_status);
341262306a36Sopenharmony_ci	ms->m_grmode   = cpu_to_le32(lkb->lkb_grmode);
341362306a36Sopenharmony_ci	ms->m_rqmode   = cpu_to_le32(lkb->lkb_rqmode);
341462306a36Sopenharmony_ci	ms->m_hash     = cpu_to_le32(r->res_hash);
341562306a36Sopenharmony_ci
341662306a36Sopenharmony_ci	/* m_result and m_bastmode are set from function args,
341762306a36Sopenharmony_ci	   not from lkb fields */
341862306a36Sopenharmony_ci
341962306a36Sopenharmony_ci	if (lkb->lkb_bastfn)
342062306a36Sopenharmony_ci		ms->m_asts |= cpu_to_le32(DLM_CB_BAST);
342162306a36Sopenharmony_ci	if (lkb->lkb_astfn)
342262306a36Sopenharmony_ci		ms->m_asts |= cpu_to_le32(DLM_CB_CAST);
342362306a36Sopenharmony_ci
342462306a36Sopenharmony_ci	/* compare with switch in create_message; send_remove() doesn't
342562306a36Sopenharmony_ci	   use send_args() */
342662306a36Sopenharmony_ci
342762306a36Sopenharmony_ci	switch (ms->m_type) {
342862306a36Sopenharmony_ci	case cpu_to_le32(DLM_MSG_REQUEST):
342962306a36Sopenharmony_ci	case cpu_to_le32(DLM_MSG_LOOKUP):
343062306a36Sopenharmony_ci		memcpy(ms->m_extra, r->res_name, r->res_length);
343162306a36Sopenharmony_ci		break;
343262306a36Sopenharmony_ci	case cpu_to_le32(DLM_MSG_CONVERT):
343362306a36Sopenharmony_ci	case cpu_to_le32(DLM_MSG_UNLOCK):
343462306a36Sopenharmony_ci	case cpu_to_le32(DLM_MSG_REQUEST_REPLY):
343562306a36Sopenharmony_ci	case cpu_to_le32(DLM_MSG_CONVERT_REPLY):
343662306a36Sopenharmony_ci	case cpu_to_le32(DLM_MSG_GRANT):
343762306a36Sopenharmony_ci		if (!lkb->lkb_lvbptr || !(lkb->lkb_exflags & DLM_LKF_VALBLK))
343862306a36Sopenharmony_ci			break;
343962306a36Sopenharmony_ci		memcpy(ms->m_extra, lkb->lkb_lvbptr, r->res_ls->ls_lvblen);
344062306a36Sopenharmony_ci		break;
344162306a36Sopenharmony_ci	}
344262306a36Sopenharmony_ci}
344362306a36Sopenharmony_ci
344462306a36Sopenharmony_cistatic int send_common(struct dlm_rsb *r, struct dlm_lkb *lkb, int mstype)
344562306a36Sopenharmony_ci{
344662306a36Sopenharmony_ci	struct dlm_message *ms;
344762306a36Sopenharmony_ci	struct dlm_mhandle *mh;
344862306a36Sopenharmony_ci	int to_nodeid, error;
344962306a36Sopenharmony_ci
345062306a36Sopenharmony_ci	to_nodeid = r->res_nodeid;
345162306a36Sopenharmony_ci
345262306a36Sopenharmony_ci	error = add_to_waiters(lkb, mstype, to_nodeid);
345362306a36Sopenharmony_ci	if (error)
345462306a36Sopenharmony_ci		return error;
345562306a36Sopenharmony_ci
345662306a36Sopenharmony_ci	error = create_message(r, lkb, to_nodeid, mstype, &ms, &mh, GFP_NOFS);
345762306a36Sopenharmony_ci	if (error)
345862306a36Sopenharmony_ci		goto fail;
345962306a36Sopenharmony_ci
346062306a36Sopenharmony_ci	send_args(r, lkb, ms);
346162306a36Sopenharmony_ci
346262306a36Sopenharmony_ci	error = send_message(mh, ms, r->res_name, r->res_length);
346362306a36Sopenharmony_ci	if (error)
346462306a36Sopenharmony_ci		goto fail;
346562306a36Sopenharmony_ci	return 0;
346662306a36Sopenharmony_ci
346762306a36Sopenharmony_ci fail:
346862306a36Sopenharmony_ci	remove_from_waiters(lkb, msg_reply_type(mstype));
346962306a36Sopenharmony_ci	return error;
347062306a36Sopenharmony_ci}
347162306a36Sopenharmony_ci
347262306a36Sopenharmony_cistatic int send_request(struct dlm_rsb *r, struct dlm_lkb *lkb)
347362306a36Sopenharmony_ci{
347462306a36Sopenharmony_ci	return send_common(r, lkb, DLM_MSG_REQUEST);
347562306a36Sopenharmony_ci}
347662306a36Sopenharmony_ci
347762306a36Sopenharmony_cistatic int send_convert(struct dlm_rsb *r, struct dlm_lkb *lkb)
347862306a36Sopenharmony_ci{
347962306a36Sopenharmony_ci	int error;
348062306a36Sopenharmony_ci
348162306a36Sopenharmony_ci	error = send_common(r, lkb, DLM_MSG_CONVERT);
348262306a36Sopenharmony_ci
348362306a36Sopenharmony_ci	/* down conversions go without a reply from the master */
348462306a36Sopenharmony_ci	if (!error && down_conversion(lkb)) {
348562306a36Sopenharmony_ci		remove_from_waiters(lkb, DLM_MSG_CONVERT_REPLY);
348662306a36Sopenharmony_ci		r->res_ls->ls_local_ms.m_type = cpu_to_le32(DLM_MSG_CONVERT_REPLY);
348762306a36Sopenharmony_ci		r->res_ls->ls_local_ms.m_result = 0;
348862306a36Sopenharmony_ci		__receive_convert_reply(r, lkb, &r->res_ls->ls_local_ms, true);
348962306a36Sopenharmony_ci	}
349062306a36Sopenharmony_ci
349162306a36Sopenharmony_ci	return error;
349262306a36Sopenharmony_ci}
349362306a36Sopenharmony_ci
349462306a36Sopenharmony_ci/* FIXME: if this lkb is the only lock we hold on the rsb, then set
349562306a36Sopenharmony_ci   MASTER_UNCERTAIN to force the next request on the rsb to confirm
349662306a36Sopenharmony_ci   that the master is still correct. */
349762306a36Sopenharmony_ci
349862306a36Sopenharmony_cistatic int send_unlock(struct dlm_rsb *r, struct dlm_lkb *lkb)
349962306a36Sopenharmony_ci{
350062306a36Sopenharmony_ci	return send_common(r, lkb, DLM_MSG_UNLOCK);
350162306a36Sopenharmony_ci}
350262306a36Sopenharmony_ci
350362306a36Sopenharmony_cistatic int send_cancel(struct dlm_rsb *r, struct dlm_lkb *lkb)
350462306a36Sopenharmony_ci{
350562306a36Sopenharmony_ci	return send_common(r, lkb, DLM_MSG_CANCEL);
350662306a36Sopenharmony_ci}
350762306a36Sopenharmony_ci
350862306a36Sopenharmony_cistatic int send_grant(struct dlm_rsb *r, struct dlm_lkb *lkb)
350962306a36Sopenharmony_ci{
351062306a36Sopenharmony_ci	struct dlm_message *ms;
351162306a36Sopenharmony_ci	struct dlm_mhandle *mh;
351262306a36Sopenharmony_ci	int to_nodeid, error;
351362306a36Sopenharmony_ci
351462306a36Sopenharmony_ci	to_nodeid = lkb->lkb_nodeid;
351562306a36Sopenharmony_ci
351662306a36Sopenharmony_ci	error = create_message(r, lkb, to_nodeid, DLM_MSG_GRANT, &ms, &mh,
351762306a36Sopenharmony_ci			       GFP_NOFS);
351862306a36Sopenharmony_ci	if (error)
351962306a36Sopenharmony_ci		goto out;
352062306a36Sopenharmony_ci
352162306a36Sopenharmony_ci	send_args(r, lkb, ms);
352262306a36Sopenharmony_ci
352362306a36Sopenharmony_ci	ms->m_result = 0;
352462306a36Sopenharmony_ci
352562306a36Sopenharmony_ci	error = send_message(mh, ms, r->res_name, r->res_length);
352662306a36Sopenharmony_ci out:
352762306a36Sopenharmony_ci	return error;
352862306a36Sopenharmony_ci}
352962306a36Sopenharmony_ci
353062306a36Sopenharmony_cistatic int send_bast(struct dlm_rsb *r, struct dlm_lkb *lkb, int mode)
353162306a36Sopenharmony_ci{
353262306a36Sopenharmony_ci	struct dlm_message *ms;
353362306a36Sopenharmony_ci	struct dlm_mhandle *mh;
353462306a36Sopenharmony_ci	int to_nodeid, error;
353562306a36Sopenharmony_ci
353662306a36Sopenharmony_ci	to_nodeid = lkb->lkb_nodeid;
353762306a36Sopenharmony_ci
353862306a36Sopenharmony_ci	error = create_message(r, NULL, to_nodeid, DLM_MSG_BAST, &ms, &mh,
353962306a36Sopenharmony_ci			       GFP_NOFS);
354062306a36Sopenharmony_ci	if (error)
354162306a36Sopenharmony_ci		goto out;
354262306a36Sopenharmony_ci
354362306a36Sopenharmony_ci	send_args(r, lkb, ms);
354462306a36Sopenharmony_ci
354562306a36Sopenharmony_ci	ms->m_bastmode = cpu_to_le32(mode);
354662306a36Sopenharmony_ci
354762306a36Sopenharmony_ci	error = send_message(mh, ms, r->res_name, r->res_length);
354862306a36Sopenharmony_ci out:
354962306a36Sopenharmony_ci	return error;
355062306a36Sopenharmony_ci}
355162306a36Sopenharmony_ci
355262306a36Sopenharmony_cistatic int send_lookup(struct dlm_rsb *r, struct dlm_lkb *lkb)
355362306a36Sopenharmony_ci{
355462306a36Sopenharmony_ci	struct dlm_message *ms;
355562306a36Sopenharmony_ci	struct dlm_mhandle *mh;
355662306a36Sopenharmony_ci	int to_nodeid, error;
355762306a36Sopenharmony_ci
355862306a36Sopenharmony_ci	to_nodeid = dlm_dir_nodeid(r);
355962306a36Sopenharmony_ci
356062306a36Sopenharmony_ci	error = add_to_waiters(lkb, DLM_MSG_LOOKUP, to_nodeid);
356162306a36Sopenharmony_ci	if (error)
356262306a36Sopenharmony_ci		return error;
356362306a36Sopenharmony_ci
356462306a36Sopenharmony_ci	error = create_message(r, NULL, to_nodeid, DLM_MSG_LOOKUP, &ms, &mh,
356562306a36Sopenharmony_ci			       GFP_NOFS);
356662306a36Sopenharmony_ci	if (error)
356762306a36Sopenharmony_ci		goto fail;
356862306a36Sopenharmony_ci
356962306a36Sopenharmony_ci	send_args(r, lkb, ms);
357062306a36Sopenharmony_ci
357162306a36Sopenharmony_ci	error = send_message(mh, ms, r->res_name, r->res_length);
357262306a36Sopenharmony_ci	if (error)
357362306a36Sopenharmony_ci		goto fail;
357462306a36Sopenharmony_ci	return 0;
357562306a36Sopenharmony_ci
357662306a36Sopenharmony_ci fail:
357762306a36Sopenharmony_ci	remove_from_waiters(lkb, DLM_MSG_LOOKUP_REPLY);
357862306a36Sopenharmony_ci	return error;
357962306a36Sopenharmony_ci}
358062306a36Sopenharmony_ci
358162306a36Sopenharmony_cistatic int send_remove(struct dlm_rsb *r)
358262306a36Sopenharmony_ci{
358362306a36Sopenharmony_ci	struct dlm_message *ms;
358462306a36Sopenharmony_ci	struct dlm_mhandle *mh;
358562306a36Sopenharmony_ci	int to_nodeid, error;
358662306a36Sopenharmony_ci
358762306a36Sopenharmony_ci	to_nodeid = dlm_dir_nodeid(r);
358862306a36Sopenharmony_ci
358962306a36Sopenharmony_ci	error = create_message(r, NULL, to_nodeid, DLM_MSG_REMOVE, &ms, &mh,
359062306a36Sopenharmony_ci			       GFP_ATOMIC);
359162306a36Sopenharmony_ci	if (error)
359262306a36Sopenharmony_ci		goto out;
359362306a36Sopenharmony_ci
359462306a36Sopenharmony_ci	memcpy(ms->m_extra, r->res_name, r->res_length);
359562306a36Sopenharmony_ci	ms->m_hash = cpu_to_le32(r->res_hash);
359662306a36Sopenharmony_ci
359762306a36Sopenharmony_ci	error = send_message(mh, ms, r->res_name, r->res_length);
359862306a36Sopenharmony_ci out:
359962306a36Sopenharmony_ci	return error;
360062306a36Sopenharmony_ci}
360162306a36Sopenharmony_ci
360262306a36Sopenharmony_cistatic int send_common_reply(struct dlm_rsb *r, struct dlm_lkb *lkb,
360362306a36Sopenharmony_ci			     int mstype, int rv)
360462306a36Sopenharmony_ci{
360562306a36Sopenharmony_ci	struct dlm_message *ms;
360662306a36Sopenharmony_ci	struct dlm_mhandle *mh;
360762306a36Sopenharmony_ci	int to_nodeid, error;
360862306a36Sopenharmony_ci
360962306a36Sopenharmony_ci	to_nodeid = lkb->lkb_nodeid;
361062306a36Sopenharmony_ci
361162306a36Sopenharmony_ci	error = create_message(r, lkb, to_nodeid, mstype, &ms, &mh, GFP_NOFS);
361262306a36Sopenharmony_ci	if (error)
361362306a36Sopenharmony_ci		goto out;
361462306a36Sopenharmony_ci
361562306a36Sopenharmony_ci	send_args(r, lkb, ms);
361662306a36Sopenharmony_ci
361762306a36Sopenharmony_ci	ms->m_result = cpu_to_le32(to_dlm_errno(rv));
361862306a36Sopenharmony_ci
361962306a36Sopenharmony_ci	error = send_message(mh, ms, r->res_name, r->res_length);
362062306a36Sopenharmony_ci out:
362162306a36Sopenharmony_ci	return error;
362262306a36Sopenharmony_ci}
362362306a36Sopenharmony_ci
362462306a36Sopenharmony_cistatic int send_request_reply(struct dlm_rsb *r, struct dlm_lkb *lkb, int rv)
362562306a36Sopenharmony_ci{
362662306a36Sopenharmony_ci	return send_common_reply(r, lkb, DLM_MSG_REQUEST_REPLY, rv);
362762306a36Sopenharmony_ci}
362862306a36Sopenharmony_ci
362962306a36Sopenharmony_cistatic int send_convert_reply(struct dlm_rsb *r, struct dlm_lkb *lkb, int rv)
363062306a36Sopenharmony_ci{
363162306a36Sopenharmony_ci	return send_common_reply(r, lkb, DLM_MSG_CONVERT_REPLY, rv);
363262306a36Sopenharmony_ci}
363362306a36Sopenharmony_ci
363462306a36Sopenharmony_cistatic int send_unlock_reply(struct dlm_rsb *r, struct dlm_lkb *lkb, int rv)
363562306a36Sopenharmony_ci{
363662306a36Sopenharmony_ci	return send_common_reply(r, lkb, DLM_MSG_UNLOCK_REPLY, rv);
363762306a36Sopenharmony_ci}
363862306a36Sopenharmony_ci
363962306a36Sopenharmony_cistatic int send_cancel_reply(struct dlm_rsb *r, struct dlm_lkb *lkb, int rv)
364062306a36Sopenharmony_ci{
364162306a36Sopenharmony_ci	return send_common_reply(r, lkb, DLM_MSG_CANCEL_REPLY, rv);
364262306a36Sopenharmony_ci}
364362306a36Sopenharmony_ci
364462306a36Sopenharmony_cistatic int send_lookup_reply(struct dlm_ls *ls,
364562306a36Sopenharmony_ci			     const struct dlm_message *ms_in, int ret_nodeid,
364662306a36Sopenharmony_ci			     int rv)
364762306a36Sopenharmony_ci{
364862306a36Sopenharmony_ci	struct dlm_rsb *r = &ls->ls_local_rsb;
364962306a36Sopenharmony_ci	struct dlm_message *ms;
365062306a36Sopenharmony_ci	struct dlm_mhandle *mh;
365162306a36Sopenharmony_ci	int error, nodeid = le32_to_cpu(ms_in->m_header.h_nodeid);
365262306a36Sopenharmony_ci
365362306a36Sopenharmony_ci	error = create_message(r, NULL, nodeid, DLM_MSG_LOOKUP_REPLY, &ms, &mh,
365462306a36Sopenharmony_ci			       GFP_NOFS);
365562306a36Sopenharmony_ci	if (error)
365662306a36Sopenharmony_ci		goto out;
365762306a36Sopenharmony_ci
365862306a36Sopenharmony_ci	ms->m_lkid = ms_in->m_lkid;
365962306a36Sopenharmony_ci	ms->m_result = cpu_to_le32(to_dlm_errno(rv));
366062306a36Sopenharmony_ci	ms->m_nodeid = cpu_to_le32(ret_nodeid);
366162306a36Sopenharmony_ci
366262306a36Sopenharmony_ci	error = send_message(mh, ms, ms_in->m_extra, receive_extralen(ms_in));
366362306a36Sopenharmony_ci out:
366462306a36Sopenharmony_ci	return error;
366562306a36Sopenharmony_ci}
366662306a36Sopenharmony_ci
366762306a36Sopenharmony_ci/* which args we save from a received message depends heavily on the type
366862306a36Sopenharmony_ci   of message, unlike the send side where we can safely send everything about
366962306a36Sopenharmony_ci   the lkb for any type of message */
367062306a36Sopenharmony_ci
367162306a36Sopenharmony_cistatic void receive_flags(struct dlm_lkb *lkb, const struct dlm_message *ms)
367262306a36Sopenharmony_ci{
367362306a36Sopenharmony_ci	lkb->lkb_exflags = le32_to_cpu(ms->m_exflags);
367462306a36Sopenharmony_ci	dlm_set_sbflags_val(lkb, le32_to_cpu(ms->m_sbflags));
367562306a36Sopenharmony_ci	dlm_set_dflags_val(lkb, le32_to_cpu(ms->m_flags));
367662306a36Sopenharmony_ci}
367762306a36Sopenharmony_ci
367862306a36Sopenharmony_cistatic void receive_flags_reply(struct dlm_lkb *lkb,
367962306a36Sopenharmony_ci				const struct dlm_message *ms,
368062306a36Sopenharmony_ci				bool local)
368162306a36Sopenharmony_ci{
368262306a36Sopenharmony_ci	if (local)
368362306a36Sopenharmony_ci		return;
368462306a36Sopenharmony_ci
368562306a36Sopenharmony_ci	dlm_set_sbflags_val(lkb, le32_to_cpu(ms->m_sbflags));
368662306a36Sopenharmony_ci	dlm_set_dflags_val(lkb, le32_to_cpu(ms->m_flags));
368762306a36Sopenharmony_ci}
368862306a36Sopenharmony_ci
368962306a36Sopenharmony_cistatic int receive_extralen(const struct dlm_message *ms)
369062306a36Sopenharmony_ci{
369162306a36Sopenharmony_ci	return (le16_to_cpu(ms->m_header.h_length) -
369262306a36Sopenharmony_ci		sizeof(struct dlm_message));
369362306a36Sopenharmony_ci}
369462306a36Sopenharmony_ci
369562306a36Sopenharmony_cistatic int receive_lvb(struct dlm_ls *ls, struct dlm_lkb *lkb,
369662306a36Sopenharmony_ci		       const struct dlm_message *ms)
369762306a36Sopenharmony_ci{
369862306a36Sopenharmony_ci	int len;
369962306a36Sopenharmony_ci
370062306a36Sopenharmony_ci	if (lkb->lkb_exflags & DLM_LKF_VALBLK) {
370162306a36Sopenharmony_ci		if (!lkb->lkb_lvbptr)
370262306a36Sopenharmony_ci			lkb->lkb_lvbptr = dlm_allocate_lvb(ls);
370362306a36Sopenharmony_ci		if (!lkb->lkb_lvbptr)
370462306a36Sopenharmony_ci			return -ENOMEM;
370562306a36Sopenharmony_ci		len = receive_extralen(ms);
370662306a36Sopenharmony_ci		if (len > ls->ls_lvblen)
370762306a36Sopenharmony_ci			len = ls->ls_lvblen;
370862306a36Sopenharmony_ci		memcpy(lkb->lkb_lvbptr, ms->m_extra, len);
370962306a36Sopenharmony_ci	}
371062306a36Sopenharmony_ci	return 0;
371162306a36Sopenharmony_ci}
371262306a36Sopenharmony_ci
371362306a36Sopenharmony_cistatic void fake_bastfn(void *astparam, int mode)
371462306a36Sopenharmony_ci{
371562306a36Sopenharmony_ci	log_print("fake_bastfn should not be called");
371662306a36Sopenharmony_ci}
371762306a36Sopenharmony_ci
371862306a36Sopenharmony_cistatic void fake_astfn(void *astparam)
371962306a36Sopenharmony_ci{
372062306a36Sopenharmony_ci	log_print("fake_astfn should not be called");
372162306a36Sopenharmony_ci}
372262306a36Sopenharmony_ci
372362306a36Sopenharmony_cistatic int receive_request_args(struct dlm_ls *ls, struct dlm_lkb *lkb,
372462306a36Sopenharmony_ci				const struct dlm_message *ms)
372562306a36Sopenharmony_ci{
372662306a36Sopenharmony_ci	lkb->lkb_nodeid = le32_to_cpu(ms->m_header.h_nodeid);
372762306a36Sopenharmony_ci	lkb->lkb_ownpid = le32_to_cpu(ms->m_pid);
372862306a36Sopenharmony_ci	lkb->lkb_remid = le32_to_cpu(ms->m_lkid);
372962306a36Sopenharmony_ci	lkb->lkb_grmode = DLM_LOCK_IV;
373062306a36Sopenharmony_ci	lkb->lkb_rqmode = le32_to_cpu(ms->m_rqmode);
373162306a36Sopenharmony_ci
373262306a36Sopenharmony_ci	lkb->lkb_bastfn = (ms->m_asts & cpu_to_le32(DLM_CB_BAST)) ? &fake_bastfn : NULL;
373362306a36Sopenharmony_ci	lkb->lkb_astfn = (ms->m_asts & cpu_to_le32(DLM_CB_CAST)) ? &fake_astfn : NULL;
373462306a36Sopenharmony_ci
373562306a36Sopenharmony_ci	if (lkb->lkb_exflags & DLM_LKF_VALBLK) {
373662306a36Sopenharmony_ci		/* lkb was just created so there won't be an lvb yet */
373762306a36Sopenharmony_ci		lkb->lkb_lvbptr = dlm_allocate_lvb(ls);
373862306a36Sopenharmony_ci		if (!lkb->lkb_lvbptr)
373962306a36Sopenharmony_ci			return -ENOMEM;
374062306a36Sopenharmony_ci	}
374162306a36Sopenharmony_ci
374262306a36Sopenharmony_ci	return 0;
374362306a36Sopenharmony_ci}
374462306a36Sopenharmony_ci
374562306a36Sopenharmony_cistatic int receive_convert_args(struct dlm_ls *ls, struct dlm_lkb *lkb,
374662306a36Sopenharmony_ci				const struct dlm_message *ms)
374762306a36Sopenharmony_ci{
374862306a36Sopenharmony_ci	if (lkb->lkb_status != DLM_LKSTS_GRANTED)
374962306a36Sopenharmony_ci		return -EBUSY;
375062306a36Sopenharmony_ci
375162306a36Sopenharmony_ci	if (receive_lvb(ls, lkb, ms))
375262306a36Sopenharmony_ci		return -ENOMEM;
375362306a36Sopenharmony_ci
375462306a36Sopenharmony_ci	lkb->lkb_rqmode = le32_to_cpu(ms->m_rqmode);
375562306a36Sopenharmony_ci	lkb->lkb_lvbseq = le32_to_cpu(ms->m_lvbseq);
375662306a36Sopenharmony_ci
375762306a36Sopenharmony_ci	return 0;
375862306a36Sopenharmony_ci}
375962306a36Sopenharmony_ci
376062306a36Sopenharmony_cistatic int receive_unlock_args(struct dlm_ls *ls, struct dlm_lkb *lkb,
376162306a36Sopenharmony_ci			       const struct dlm_message *ms)
376262306a36Sopenharmony_ci{
376362306a36Sopenharmony_ci	if (receive_lvb(ls, lkb, ms))
376462306a36Sopenharmony_ci		return -ENOMEM;
376562306a36Sopenharmony_ci	return 0;
376662306a36Sopenharmony_ci}
376762306a36Sopenharmony_ci
376862306a36Sopenharmony_ci/* We fill in the local-lkb fields with the info that send_xxxx_reply()
376962306a36Sopenharmony_ci   uses to send a reply and that the remote end uses to process the reply. */
377062306a36Sopenharmony_ci
377162306a36Sopenharmony_cistatic void setup_local_lkb(struct dlm_ls *ls, const struct dlm_message *ms)
377262306a36Sopenharmony_ci{
377362306a36Sopenharmony_ci	struct dlm_lkb *lkb = &ls->ls_local_lkb;
377462306a36Sopenharmony_ci	lkb->lkb_nodeid = le32_to_cpu(ms->m_header.h_nodeid);
377562306a36Sopenharmony_ci	lkb->lkb_remid = le32_to_cpu(ms->m_lkid);
377662306a36Sopenharmony_ci}
377762306a36Sopenharmony_ci
377862306a36Sopenharmony_ci/* This is called after the rsb is locked so that we can safely inspect
377962306a36Sopenharmony_ci   fields in the lkb. */
378062306a36Sopenharmony_ci
378162306a36Sopenharmony_cistatic int validate_message(struct dlm_lkb *lkb, const struct dlm_message *ms)
378262306a36Sopenharmony_ci{
378362306a36Sopenharmony_ci	int from = le32_to_cpu(ms->m_header.h_nodeid);
378462306a36Sopenharmony_ci	int error = 0;
378562306a36Sopenharmony_ci
378662306a36Sopenharmony_ci	/* currently mixing of user/kernel locks are not supported */
378762306a36Sopenharmony_ci	if (ms->m_flags & cpu_to_le32(BIT(DLM_DFL_USER_BIT)) &&
378862306a36Sopenharmony_ci	    !test_bit(DLM_DFL_USER_BIT, &lkb->lkb_dflags)) {
378962306a36Sopenharmony_ci		log_error(lkb->lkb_resource->res_ls,
379062306a36Sopenharmony_ci			  "got user dlm message for a kernel lock");
379162306a36Sopenharmony_ci		error = -EINVAL;
379262306a36Sopenharmony_ci		goto out;
379362306a36Sopenharmony_ci	}
379462306a36Sopenharmony_ci
379562306a36Sopenharmony_ci	switch (ms->m_type) {
379662306a36Sopenharmony_ci	case cpu_to_le32(DLM_MSG_CONVERT):
379762306a36Sopenharmony_ci	case cpu_to_le32(DLM_MSG_UNLOCK):
379862306a36Sopenharmony_ci	case cpu_to_le32(DLM_MSG_CANCEL):
379962306a36Sopenharmony_ci		if (!is_master_copy(lkb) || lkb->lkb_nodeid != from)
380062306a36Sopenharmony_ci			error = -EINVAL;
380162306a36Sopenharmony_ci		break;
380262306a36Sopenharmony_ci
380362306a36Sopenharmony_ci	case cpu_to_le32(DLM_MSG_CONVERT_REPLY):
380462306a36Sopenharmony_ci	case cpu_to_le32(DLM_MSG_UNLOCK_REPLY):
380562306a36Sopenharmony_ci	case cpu_to_le32(DLM_MSG_CANCEL_REPLY):
380662306a36Sopenharmony_ci	case cpu_to_le32(DLM_MSG_GRANT):
380762306a36Sopenharmony_ci	case cpu_to_le32(DLM_MSG_BAST):
380862306a36Sopenharmony_ci		if (!is_process_copy(lkb) || lkb->lkb_nodeid != from)
380962306a36Sopenharmony_ci			error = -EINVAL;
381062306a36Sopenharmony_ci		break;
381162306a36Sopenharmony_ci
381262306a36Sopenharmony_ci	case cpu_to_le32(DLM_MSG_REQUEST_REPLY):
381362306a36Sopenharmony_ci		if (!is_process_copy(lkb))
381462306a36Sopenharmony_ci			error = -EINVAL;
381562306a36Sopenharmony_ci		else if (lkb->lkb_nodeid != -1 && lkb->lkb_nodeid != from)
381662306a36Sopenharmony_ci			error = -EINVAL;
381762306a36Sopenharmony_ci		break;
381862306a36Sopenharmony_ci
381962306a36Sopenharmony_ci	default:
382062306a36Sopenharmony_ci		error = -EINVAL;
382162306a36Sopenharmony_ci	}
382262306a36Sopenharmony_ci
382362306a36Sopenharmony_ciout:
382462306a36Sopenharmony_ci	if (error)
382562306a36Sopenharmony_ci		log_error(lkb->lkb_resource->res_ls,
382662306a36Sopenharmony_ci			  "ignore invalid message %d from %d %x %x %x %d",
382762306a36Sopenharmony_ci			  le32_to_cpu(ms->m_type), from, lkb->lkb_id,
382862306a36Sopenharmony_ci			  lkb->lkb_remid, dlm_iflags_val(lkb),
382962306a36Sopenharmony_ci			  lkb->lkb_nodeid);
383062306a36Sopenharmony_ci	return error;
383162306a36Sopenharmony_ci}
383262306a36Sopenharmony_ci
383362306a36Sopenharmony_cistatic int receive_request(struct dlm_ls *ls, const struct dlm_message *ms)
383462306a36Sopenharmony_ci{
383562306a36Sopenharmony_ci	struct dlm_lkb *lkb;
383662306a36Sopenharmony_ci	struct dlm_rsb *r;
383762306a36Sopenharmony_ci	int from_nodeid;
383862306a36Sopenharmony_ci	int error, namelen = 0;
383962306a36Sopenharmony_ci
384062306a36Sopenharmony_ci	from_nodeid = le32_to_cpu(ms->m_header.h_nodeid);
384162306a36Sopenharmony_ci
384262306a36Sopenharmony_ci	error = create_lkb(ls, &lkb);
384362306a36Sopenharmony_ci	if (error)
384462306a36Sopenharmony_ci		goto fail;
384562306a36Sopenharmony_ci
384662306a36Sopenharmony_ci	receive_flags(lkb, ms);
384762306a36Sopenharmony_ci	set_bit(DLM_IFL_MSTCPY_BIT, &lkb->lkb_iflags);
384862306a36Sopenharmony_ci	error = receive_request_args(ls, lkb, ms);
384962306a36Sopenharmony_ci	if (error) {
385062306a36Sopenharmony_ci		__put_lkb(ls, lkb);
385162306a36Sopenharmony_ci		goto fail;
385262306a36Sopenharmony_ci	}
385362306a36Sopenharmony_ci
385462306a36Sopenharmony_ci	/* The dir node is the authority on whether we are the master
385562306a36Sopenharmony_ci	   for this rsb or not, so if the master sends us a request, we should
385662306a36Sopenharmony_ci	   recreate the rsb if we've destroyed it.   This race happens when we
385762306a36Sopenharmony_ci	   send a remove message to the dir node at the same time that the dir
385862306a36Sopenharmony_ci	   node sends us a request for the rsb. */
385962306a36Sopenharmony_ci
386062306a36Sopenharmony_ci	namelen = receive_extralen(ms);
386162306a36Sopenharmony_ci
386262306a36Sopenharmony_ci	error = find_rsb(ls, ms->m_extra, namelen, from_nodeid,
386362306a36Sopenharmony_ci			 R_RECEIVE_REQUEST, &r);
386462306a36Sopenharmony_ci	if (error) {
386562306a36Sopenharmony_ci		__put_lkb(ls, lkb);
386662306a36Sopenharmony_ci		goto fail;
386762306a36Sopenharmony_ci	}
386862306a36Sopenharmony_ci
386962306a36Sopenharmony_ci	lock_rsb(r);
387062306a36Sopenharmony_ci
387162306a36Sopenharmony_ci	if (r->res_master_nodeid != dlm_our_nodeid()) {
387262306a36Sopenharmony_ci		error = validate_master_nodeid(ls, r, from_nodeid);
387362306a36Sopenharmony_ci		if (error) {
387462306a36Sopenharmony_ci			unlock_rsb(r);
387562306a36Sopenharmony_ci			put_rsb(r);
387662306a36Sopenharmony_ci			__put_lkb(ls, lkb);
387762306a36Sopenharmony_ci			goto fail;
387862306a36Sopenharmony_ci		}
387962306a36Sopenharmony_ci	}
388062306a36Sopenharmony_ci
388162306a36Sopenharmony_ci	attach_lkb(r, lkb);
388262306a36Sopenharmony_ci	error = do_request(r, lkb);
388362306a36Sopenharmony_ci	send_request_reply(r, lkb, error);
388462306a36Sopenharmony_ci	do_request_effects(r, lkb, error);
388562306a36Sopenharmony_ci
388662306a36Sopenharmony_ci	unlock_rsb(r);
388762306a36Sopenharmony_ci	put_rsb(r);
388862306a36Sopenharmony_ci
388962306a36Sopenharmony_ci	if (error == -EINPROGRESS)
389062306a36Sopenharmony_ci		error = 0;
389162306a36Sopenharmony_ci	if (error)
389262306a36Sopenharmony_ci		dlm_put_lkb(lkb);
389362306a36Sopenharmony_ci	return 0;
389462306a36Sopenharmony_ci
389562306a36Sopenharmony_ci fail:
389662306a36Sopenharmony_ci	/* TODO: instead of returning ENOTBLK, add the lkb to res_lookup
389762306a36Sopenharmony_ci	   and do this receive_request again from process_lookup_list once
389862306a36Sopenharmony_ci	   we get the lookup reply.  This would avoid a many repeated
389962306a36Sopenharmony_ci	   ENOTBLK request failures when the lookup reply designating us
390062306a36Sopenharmony_ci	   as master is delayed. */
390162306a36Sopenharmony_ci
390262306a36Sopenharmony_ci	if (error != -ENOTBLK) {
390362306a36Sopenharmony_ci		log_limit(ls, "receive_request %x from %d %d",
390462306a36Sopenharmony_ci			  le32_to_cpu(ms->m_lkid), from_nodeid, error);
390562306a36Sopenharmony_ci	}
390662306a36Sopenharmony_ci
390762306a36Sopenharmony_ci	setup_local_lkb(ls, ms);
390862306a36Sopenharmony_ci	send_request_reply(&ls->ls_local_rsb, &ls->ls_local_lkb, error);
390962306a36Sopenharmony_ci	return error;
391062306a36Sopenharmony_ci}
391162306a36Sopenharmony_ci
391262306a36Sopenharmony_cistatic int receive_convert(struct dlm_ls *ls, const struct dlm_message *ms)
391362306a36Sopenharmony_ci{
391462306a36Sopenharmony_ci	struct dlm_lkb *lkb;
391562306a36Sopenharmony_ci	struct dlm_rsb *r;
391662306a36Sopenharmony_ci	int error, reply = 1;
391762306a36Sopenharmony_ci
391862306a36Sopenharmony_ci	error = find_lkb(ls, le32_to_cpu(ms->m_remid), &lkb);
391962306a36Sopenharmony_ci	if (error)
392062306a36Sopenharmony_ci		goto fail;
392162306a36Sopenharmony_ci
392262306a36Sopenharmony_ci	if (lkb->lkb_remid != le32_to_cpu(ms->m_lkid)) {
392362306a36Sopenharmony_ci		log_error(ls, "receive_convert %x remid %x recover_seq %llu "
392462306a36Sopenharmony_ci			  "remote %d %x", lkb->lkb_id, lkb->lkb_remid,
392562306a36Sopenharmony_ci			  (unsigned long long)lkb->lkb_recover_seq,
392662306a36Sopenharmony_ci			  le32_to_cpu(ms->m_header.h_nodeid),
392762306a36Sopenharmony_ci			  le32_to_cpu(ms->m_lkid));
392862306a36Sopenharmony_ci		error = -ENOENT;
392962306a36Sopenharmony_ci		dlm_put_lkb(lkb);
393062306a36Sopenharmony_ci		goto fail;
393162306a36Sopenharmony_ci	}
393262306a36Sopenharmony_ci
393362306a36Sopenharmony_ci	r = lkb->lkb_resource;
393462306a36Sopenharmony_ci
393562306a36Sopenharmony_ci	hold_rsb(r);
393662306a36Sopenharmony_ci	lock_rsb(r);
393762306a36Sopenharmony_ci
393862306a36Sopenharmony_ci	error = validate_message(lkb, ms);
393962306a36Sopenharmony_ci	if (error)
394062306a36Sopenharmony_ci		goto out;
394162306a36Sopenharmony_ci
394262306a36Sopenharmony_ci	receive_flags(lkb, ms);
394362306a36Sopenharmony_ci
394462306a36Sopenharmony_ci	error = receive_convert_args(ls, lkb, ms);
394562306a36Sopenharmony_ci	if (error) {
394662306a36Sopenharmony_ci		send_convert_reply(r, lkb, error);
394762306a36Sopenharmony_ci		goto out;
394862306a36Sopenharmony_ci	}
394962306a36Sopenharmony_ci
395062306a36Sopenharmony_ci	reply = !down_conversion(lkb);
395162306a36Sopenharmony_ci
395262306a36Sopenharmony_ci	error = do_convert(r, lkb);
395362306a36Sopenharmony_ci	if (reply)
395462306a36Sopenharmony_ci		send_convert_reply(r, lkb, error);
395562306a36Sopenharmony_ci	do_convert_effects(r, lkb, error);
395662306a36Sopenharmony_ci out:
395762306a36Sopenharmony_ci	unlock_rsb(r);
395862306a36Sopenharmony_ci	put_rsb(r);
395962306a36Sopenharmony_ci	dlm_put_lkb(lkb);
396062306a36Sopenharmony_ci	return 0;
396162306a36Sopenharmony_ci
396262306a36Sopenharmony_ci fail:
396362306a36Sopenharmony_ci	setup_local_lkb(ls, ms);
396462306a36Sopenharmony_ci	send_convert_reply(&ls->ls_local_rsb, &ls->ls_local_lkb, error);
396562306a36Sopenharmony_ci	return error;
396662306a36Sopenharmony_ci}
396762306a36Sopenharmony_ci
396862306a36Sopenharmony_cistatic int receive_unlock(struct dlm_ls *ls, const struct dlm_message *ms)
396962306a36Sopenharmony_ci{
397062306a36Sopenharmony_ci	struct dlm_lkb *lkb;
397162306a36Sopenharmony_ci	struct dlm_rsb *r;
397262306a36Sopenharmony_ci	int error;
397362306a36Sopenharmony_ci
397462306a36Sopenharmony_ci	error = find_lkb(ls, le32_to_cpu(ms->m_remid), &lkb);
397562306a36Sopenharmony_ci	if (error)
397662306a36Sopenharmony_ci		goto fail;
397762306a36Sopenharmony_ci
397862306a36Sopenharmony_ci	if (lkb->lkb_remid != le32_to_cpu(ms->m_lkid)) {
397962306a36Sopenharmony_ci		log_error(ls, "receive_unlock %x remid %x remote %d %x",
398062306a36Sopenharmony_ci			  lkb->lkb_id, lkb->lkb_remid,
398162306a36Sopenharmony_ci			  le32_to_cpu(ms->m_header.h_nodeid),
398262306a36Sopenharmony_ci			  le32_to_cpu(ms->m_lkid));
398362306a36Sopenharmony_ci		error = -ENOENT;
398462306a36Sopenharmony_ci		dlm_put_lkb(lkb);
398562306a36Sopenharmony_ci		goto fail;
398662306a36Sopenharmony_ci	}
398762306a36Sopenharmony_ci
398862306a36Sopenharmony_ci	r = lkb->lkb_resource;
398962306a36Sopenharmony_ci
399062306a36Sopenharmony_ci	hold_rsb(r);
399162306a36Sopenharmony_ci	lock_rsb(r);
399262306a36Sopenharmony_ci
399362306a36Sopenharmony_ci	error = validate_message(lkb, ms);
399462306a36Sopenharmony_ci	if (error)
399562306a36Sopenharmony_ci		goto out;
399662306a36Sopenharmony_ci
399762306a36Sopenharmony_ci	receive_flags(lkb, ms);
399862306a36Sopenharmony_ci
399962306a36Sopenharmony_ci	error = receive_unlock_args(ls, lkb, ms);
400062306a36Sopenharmony_ci	if (error) {
400162306a36Sopenharmony_ci		send_unlock_reply(r, lkb, error);
400262306a36Sopenharmony_ci		goto out;
400362306a36Sopenharmony_ci	}
400462306a36Sopenharmony_ci
400562306a36Sopenharmony_ci	error = do_unlock(r, lkb);
400662306a36Sopenharmony_ci	send_unlock_reply(r, lkb, error);
400762306a36Sopenharmony_ci	do_unlock_effects(r, lkb, error);
400862306a36Sopenharmony_ci out:
400962306a36Sopenharmony_ci	unlock_rsb(r);
401062306a36Sopenharmony_ci	put_rsb(r);
401162306a36Sopenharmony_ci	dlm_put_lkb(lkb);
401262306a36Sopenharmony_ci	return 0;
401362306a36Sopenharmony_ci
401462306a36Sopenharmony_ci fail:
401562306a36Sopenharmony_ci	setup_local_lkb(ls, ms);
401662306a36Sopenharmony_ci	send_unlock_reply(&ls->ls_local_rsb, &ls->ls_local_lkb, error);
401762306a36Sopenharmony_ci	return error;
401862306a36Sopenharmony_ci}
401962306a36Sopenharmony_ci
402062306a36Sopenharmony_cistatic int receive_cancel(struct dlm_ls *ls, const struct dlm_message *ms)
402162306a36Sopenharmony_ci{
402262306a36Sopenharmony_ci	struct dlm_lkb *lkb;
402362306a36Sopenharmony_ci	struct dlm_rsb *r;
402462306a36Sopenharmony_ci	int error;
402562306a36Sopenharmony_ci
402662306a36Sopenharmony_ci	error = find_lkb(ls, le32_to_cpu(ms->m_remid), &lkb);
402762306a36Sopenharmony_ci	if (error)
402862306a36Sopenharmony_ci		goto fail;
402962306a36Sopenharmony_ci
403062306a36Sopenharmony_ci	receive_flags(lkb, ms);
403162306a36Sopenharmony_ci
403262306a36Sopenharmony_ci	r = lkb->lkb_resource;
403362306a36Sopenharmony_ci
403462306a36Sopenharmony_ci	hold_rsb(r);
403562306a36Sopenharmony_ci	lock_rsb(r);
403662306a36Sopenharmony_ci
403762306a36Sopenharmony_ci	error = validate_message(lkb, ms);
403862306a36Sopenharmony_ci	if (error)
403962306a36Sopenharmony_ci		goto out;
404062306a36Sopenharmony_ci
404162306a36Sopenharmony_ci	error = do_cancel(r, lkb);
404262306a36Sopenharmony_ci	send_cancel_reply(r, lkb, error);
404362306a36Sopenharmony_ci	do_cancel_effects(r, lkb, error);
404462306a36Sopenharmony_ci out:
404562306a36Sopenharmony_ci	unlock_rsb(r);
404662306a36Sopenharmony_ci	put_rsb(r);
404762306a36Sopenharmony_ci	dlm_put_lkb(lkb);
404862306a36Sopenharmony_ci	return 0;
404962306a36Sopenharmony_ci
405062306a36Sopenharmony_ci fail:
405162306a36Sopenharmony_ci	setup_local_lkb(ls, ms);
405262306a36Sopenharmony_ci	send_cancel_reply(&ls->ls_local_rsb, &ls->ls_local_lkb, error);
405362306a36Sopenharmony_ci	return error;
405462306a36Sopenharmony_ci}
405562306a36Sopenharmony_ci
405662306a36Sopenharmony_cistatic int receive_grant(struct dlm_ls *ls, const struct dlm_message *ms)
405762306a36Sopenharmony_ci{
405862306a36Sopenharmony_ci	struct dlm_lkb *lkb;
405962306a36Sopenharmony_ci	struct dlm_rsb *r;
406062306a36Sopenharmony_ci	int error;
406162306a36Sopenharmony_ci
406262306a36Sopenharmony_ci	error = find_lkb(ls, le32_to_cpu(ms->m_remid), &lkb);
406362306a36Sopenharmony_ci	if (error)
406462306a36Sopenharmony_ci		return error;
406562306a36Sopenharmony_ci
406662306a36Sopenharmony_ci	r = lkb->lkb_resource;
406762306a36Sopenharmony_ci
406862306a36Sopenharmony_ci	hold_rsb(r);
406962306a36Sopenharmony_ci	lock_rsb(r);
407062306a36Sopenharmony_ci
407162306a36Sopenharmony_ci	error = validate_message(lkb, ms);
407262306a36Sopenharmony_ci	if (error)
407362306a36Sopenharmony_ci		goto out;
407462306a36Sopenharmony_ci
407562306a36Sopenharmony_ci	receive_flags_reply(lkb, ms, false);
407662306a36Sopenharmony_ci	if (is_altmode(lkb))
407762306a36Sopenharmony_ci		munge_altmode(lkb, ms);
407862306a36Sopenharmony_ci	grant_lock_pc(r, lkb, ms);
407962306a36Sopenharmony_ci	queue_cast(r, lkb, 0);
408062306a36Sopenharmony_ci out:
408162306a36Sopenharmony_ci	unlock_rsb(r);
408262306a36Sopenharmony_ci	put_rsb(r);
408362306a36Sopenharmony_ci	dlm_put_lkb(lkb);
408462306a36Sopenharmony_ci	return 0;
408562306a36Sopenharmony_ci}
408662306a36Sopenharmony_ci
408762306a36Sopenharmony_cistatic int receive_bast(struct dlm_ls *ls, const struct dlm_message *ms)
408862306a36Sopenharmony_ci{
408962306a36Sopenharmony_ci	struct dlm_lkb *lkb;
409062306a36Sopenharmony_ci	struct dlm_rsb *r;
409162306a36Sopenharmony_ci	int error;
409262306a36Sopenharmony_ci
409362306a36Sopenharmony_ci	error = find_lkb(ls, le32_to_cpu(ms->m_remid), &lkb);
409462306a36Sopenharmony_ci	if (error)
409562306a36Sopenharmony_ci		return error;
409662306a36Sopenharmony_ci
409762306a36Sopenharmony_ci	r = lkb->lkb_resource;
409862306a36Sopenharmony_ci
409962306a36Sopenharmony_ci	hold_rsb(r);
410062306a36Sopenharmony_ci	lock_rsb(r);
410162306a36Sopenharmony_ci
410262306a36Sopenharmony_ci	error = validate_message(lkb, ms);
410362306a36Sopenharmony_ci	if (error)
410462306a36Sopenharmony_ci		goto out;
410562306a36Sopenharmony_ci
410662306a36Sopenharmony_ci	queue_bast(r, lkb, le32_to_cpu(ms->m_bastmode));
410762306a36Sopenharmony_ci	lkb->lkb_highbast = le32_to_cpu(ms->m_bastmode);
410862306a36Sopenharmony_ci out:
410962306a36Sopenharmony_ci	unlock_rsb(r);
411062306a36Sopenharmony_ci	put_rsb(r);
411162306a36Sopenharmony_ci	dlm_put_lkb(lkb);
411262306a36Sopenharmony_ci	return 0;
411362306a36Sopenharmony_ci}
411462306a36Sopenharmony_ci
411562306a36Sopenharmony_cistatic void receive_lookup(struct dlm_ls *ls, const struct dlm_message *ms)
411662306a36Sopenharmony_ci{
411762306a36Sopenharmony_ci	int len, error, ret_nodeid, from_nodeid, our_nodeid;
411862306a36Sopenharmony_ci
411962306a36Sopenharmony_ci	from_nodeid = le32_to_cpu(ms->m_header.h_nodeid);
412062306a36Sopenharmony_ci	our_nodeid = dlm_our_nodeid();
412162306a36Sopenharmony_ci
412262306a36Sopenharmony_ci	len = receive_extralen(ms);
412362306a36Sopenharmony_ci
412462306a36Sopenharmony_ci	error = dlm_master_lookup(ls, from_nodeid, ms->m_extra, len, 0,
412562306a36Sopenharmony_ci				  &ret_nodeid, NULL);
412662306a36Sopenharmony_ci
412762306a36Sopenharmony_ci	/* Optimization: we're master so treat lookup as a request */
412862306a36Sopenharmony_ci	if (!error && ret_nodeid == our_nodeid) {
412962306a36Sopenharmony_ci		receive_request(ls, ms);
413062306a36Sopenharmony_ci		return;
413162306a36Sopenharmony_ci	}
413262306a36Sopenharmony_ci	send_lookup_reply(ls, ms, ret_nodeid, error);
413362306a36Sopenharmony_ci}
413462306a36Sopenharmony_ci
413562306a36Sopenharmony_cistatic void receive_remove(struct dlm_ls *ls, const struct dlm_message *ms)
413662306a36Sopenharmony_ci{
413762306a36Sopenharmony_ci	char name[DLM_RESNAME_MAXLEN+1];
413862306a36Sopenharmony_ci	struct dlm_rsb *r;
413962306a36Sopenharmony_ci	uint32_t hash, b;
414062306a36Sopenharmony_ci	int rv, len, dir_nodeid, from_nodeid;
414162306a36Sopenharmony_ci
414262306a36Sopenharmony_ci	from_nodeid = le32_to_cpu(ms->m_header.h_nodeid);
414362306a36Sopenharmony_ci
414462306a36Sopenharmony_ci	len = receive_extralen(ms);
414562306a36Sopenharmony_ci
414662306a36Sopenharmony_ci	if (len > DLM_RESNAME_MAXLEN) {
414762306a36Sopenharmony_ci		log_error(ls, "receive_remove from %d bad len %d",
414862306a36Sopenharmony_ci			  from_nodeid, len);
414962306a36Sopenharmony_ci		return;
415062306a36Sopenharmony_ci	}
415162306a36Sopenharmony_ci
415262306a36Sopenharmony_ci	dir_nodeid = dlm_hash2nodeid(ls, le32_to_cpu(ms->m_hash));
415362306a36Sopenharmony_ci	if (dir_nodeid != dlm_our_nodeid()) {
415462306a36Sopenharmony_ci		log_error(ls, "receive_remove from %d bad nodeid %d",
415562306a36Sopenharmony_ci			  from_nodeid, dir_nodeid);
415662306a36Sopenharmony_ci		return;
415762306a36Sopenharmony_ci	}
415862306a36Sopenharmony_ci
415962306a36Sopenharmony_ci	/* Look for name on rsbtbl.toss, if it's there, kill it.
416062306a36Sopenharmony_ci	   If it's on rsbtbl.keep, it's being used, and we should ignore this
416162306a36Sopenharmony_ci	   message.  This is an expected race between the dir node sending a
416262306a36Sopenharmony_ci	   request to the master node at the same time as the master node sends
416362306a36Sopenharmony_ci	   a remove to the dir node.  The resolution to that race is for the
416462306a36Sopenharmony_ci	   dir node to ignore the remove message, and the master node to
416562306a36Sopenharmony_ci	   recreate the master rsb when it gets a request from the dir node for
416662306a36Sopenharmony_ci	   an rsb it doesn't have. */
416762306a36Sopenharmony_ci
416862306a36Sopenharmony_ci	memset(name, 0, sizeof(name));
416962306a36Sopenharmony_ci	memcpy(name, ms->m_extra, len);
417062306a36Sopenharmony_ci
417162306a36Sopenharmony_ci	hash = jhash(name, len, 0);
417262306a36Sopenharmony_ci	b = hash & (ls->ls_rsbtbl_size - 1);
417362306a36Sopenharmony_ci
417462306a36Sopenharmony_ci	spin_lock(&ls->ls_rsbtbl[b].lock);
417562306a36Sopenharmony_ci
417662306a36Sopenharmony_ci	rv = dlm_search_rsb_tree(&ls->ls_rsbtbl[b].toss, name, len, &r);
417762306a36Sopenharmony_ci	if (rv) {
417862306a36Sopenharmony_ci		/* verify the rsb is on keep list per comment above */
417962306a36Sopenharmony_ci		rv = dlm_search_rsb_tree(&ls->ls_rsbtbl[b].keep, name, len, &r);
418062306a36Sopenharmony_ci		if (rv) {
418162306a36Sopenharmony_ci			/* should not happen */
418262306a36Sopenharmony_ci			log_error(ls, "receive_remove from %d not found %s",
418362306a36Sopenharmony_ci				  from_nodeid, name);
418462306a36Sopenharmony_ci			spin_unlock(&ls->ls_rsbtbl[b].lock);
418562306a36Sopenharmony_ci			return;
418662306a36Sopenharmony_ci		}
418762306a36Sopenharmony_ci		if (r->res_master_nodeid != from_nodeid) {
418862306a36Sopenharmony_ci			/* should not happen */
418962306a36Sopenharmony_ci			log_error(ls, "receive_remove keep from %d master %d",
419062306a36Sopenharmony_ci				  from_nodeid, r->res_master_nodeid);
419162306a36Sopenharmony_ci			dlm_print_rsb(r);
419262306a36Sopenharmony_ci			spin_unlock(&ls->ls_rsbtbl[b].lock);
419362306a36Sopenharmony_ci			return;
419462306a36Sopenharmony_ci		}
419562306a36Sopenharmony_ci
419662306a36Sopenharmony_ci		log_debug(ls, "receive_remove from %d master %d first %x %s",
419762306a36Sopenharmony_ci			  from_nodeid, r->res_master_nodeid, r->res_first_lkid,
419862306a36Sopenharmony_ci			  name);
419962306a36Sopenharmony_ci		spin_unlock(&ls->ls_rsbtbl[b].lock);
420062306a36Sopenharmony_ci		return;
420162306a36Sopenharmony_ci	}
420262306a36Sopenharmony_ci
420362306a36Sopenharmony_ci	if (r->res_master_nodeid != from_nodeid) {
420462306a36Sopenharmony_ci		log_error(ls, "receive_remove toss from %d master %d",
420562306a36Sopenharmony_ci			  from_nodeid, r->res_master_nodeid);
420662306a36Sopenharmony_ci		dlm_print_rsb(r);
420762306a36Sopenharmony_ci		spin_unlock(&ls->ls_rsbtbl[b].lock);
420862306a36Sopenharmony_ci		return;
420962306a36Sopenharmony_ci	}
421062306a36Sopenharmony_ci
421162306a36Sopenharmony_ci	if (kref_put(&r->res_ref, kill_rsb)) {
421262306a36Sopenharmony_ci		rb_erase(&r->res_hashnode, &ls->ls_rsbtbl[b].toss);
421362306a36Sopenharmony_ci		spin_unlock(&ls->ls_rsbtbl[b].lock);
421462306a36Sopenharmony_ci		dlm_free_rsb(r);
421562306a36Sopenharmony_ci	} else {
421662306a36Sopenharmony_ci		log_error(ls, "receive_remove from %d rsb ref error",
421762306a36Sopenharmony_ci			  from_nodeid);
421862306a36Sopenharmony_ci		dlm_print_rsb(r);
421962306a36Sopenharmony_ci		spin_unlock(&ls->ls_rsbtbl[b].lock);
422062306a36Sopenharmony_ci	}
422162306a36Sopenharmony_ci}
422262306a36Sopenharmony_ci
422362306a36Sopenharmony_cistatic void receive_purge(struct dlm_ls *ls, const struct dlm_message *ms)
422462306a36Sopenharmony_ci{
422562306a36Sopenharmony_ci	do_purge(ls, le32_to_cpu(ms->m_nodeid), le32_to_cpu(ms->m_pid));
422662306a36Sopenharmony_ci}
422762306a36Sopenharmony_ci
422862306a36Sopenharmony_cistatic int receive_request_reply(struct dlm_ls *ls,
422962306a36Sopenharmony_ci				 const struct dlm_message *ms)
423062306a36Sopenharmony_ci{
423162306a36Sopenharmony_ci	struct dlm_lkb *lkb;
423262306a36Sopenharmony_ci	struct dlm_rsb *r;
423362306a36Sopenharmony_ci	int error, mstype, result;
423462306a36Sopenharmony_ci	int from_nodeid = le32_to_cpu(ms->m_header.h_nodeid);
423562306a36Sopenharmony_ci
423662306a36Sopenharmony_ci	error = find_lkb(ls, le32_to_cpu(ms->m_remid), &lkb);
423762306a36Sopenharmony_ci	if (error)
423862306a36Sopenharmony_ci		return error;
423962306a36Sopenharmony_ci
424062306a36Sopenharmony_ci	r = lkb->lkb_resource;
424162306a36Sopenharmony_ci	hold_rsb(r);
424262306a36Sopenharmony_ci	lock_rsb(r);
424362306a36Sopenharmony_ci
424462306a36Sopenharmony_ci	error = validate_message(lkb, ms);
424562306a36Sopenharmony_ci	if (error)
424662306a36Sopenharmony_ci		goto out;
424762306a36Sopenharmony_ci
424862306a36Sopenharmony_ci	mstype = lkb->lkb_wait_type;
424962306a36Sopenharmony_ci	error = remove_from_waiters(lkb, DLM_MSG_REQUEST_REPLY);
425062306a36Sopenharmony_ci	if (error) {
425162306a36Sopenharmony_ci		log_error(ls, "receive_request_reply %x remote %d %x result %d",
425262306a36Sopenharmony_ci			  lkb->lkb_id, from_nodeid, le32_to_cpu(ms->m_lkid),
425362306a36Sopenharmony_ci			  from_dlm_errno(le32_to_cpu(ms->m_result)));
425462306a36Sopenharmony_ci		dlm_dump_rsb(r);
425562306a36Sopenharmony_ci		goto out;
425662306a36Sopenharmony_ci	}
425762306a36Sopenharmony_ci
425862306a36Sopenharmony_ci	/* Optimization: the dir node was also the master, so it took our
425962306a36Sopenharmony_ci	   lookup as a request and sent request reply instead of lookup reply */
426062306a36Sopenharmony_ci	if (mstype == DLM_MSG_LOOKUP) {
426162306a36Sopenharmony_ci		r->res_master_nodeid = from_nodeid;
426262306a36Sopenharmony_ci		r->res_nodeid = from_nodeid;
426362306a36Sopenharmony_ci		lkb->lkb_nodeid = from_nodeid;
426462306a36Sopenharmony_ci	}
426562306a36Sopenharmony_ci
426662306a36Sopenharmony_ci	/* this is the value returned from do_request() on the master */
426762306a36Sopenharmony_ci	result = from_dlm_errno(le32_to_cpu(ms->m_result));
426862306a36Sopenharmony_ci
426962306a36Sopenharmony_ci	switch (result) {
427062306a36Sopenharmony_ci	case -EAGAIN:
427162306a36Sopenharmony_ci		/* request would block (be queued) on remote master */
427262306a36Sopenharmony_ci		queue_cast(r, lkb, -EAGAIN);
427362306a36Sopenharmony_ci		confirm_master(r, -EAGAIN);
427462306a36Sopenharmony_ci		unhold_lkb(lkb); /* undoes create_lkb() */
427562306a36Sopenharmony_ci		break;
427662306a36Sopenharmony_ci
427762306a36Sopenharmony_ci	case -EINPROGRESS:
427862306a36Sopenharmony_ci	case 0:
427962306a36Sopenharmony_ci		/* request was queued or granted on remote master */
428062306a36Sopenharmony_ci		receive_flags_reply(lkb, ms, false);
428162306a36Sopenharmony_ci		lkb->lkb_remid = le32_to_cpu(ms->m_lkid);
428262306a36Sopenharmony_ci		if (is_altmode(lkb))
428362306a36Sopenharmony_ci			munge_altmode(lkb, ms);
428462306a36Sopenharmony_ci		if (result) {
428562306a36Sopenharmony_ci			add_lkb(r, lkb, DLM_LKSTS_WAITING);
428662306a36Sopenharmony_ci		} else {
428762306a36Sopenharmony_ci			grant_lock_pc(r, lkb, ms);
428862306a36Sopenharmony_ci			queue_cast(r, lkb, 0);
428962306a36Sopenharmony_ci		}
429062306a36Sopenharmony_ci		confirm_master(r, result);
429162306a36Sopenharmony_ci		break;
429262306a36Sopenharmony_ci
429362306a36Sopenharmony_ci	case -EBADR:
429462306a36Sopenharmony_ci	case -ENOTBLK:
429562306a36Sopenharmony_ci		/* find_rsb failed to find rsb or rsb wasn't master */
429662306a36Sopenharmony_ci		log_limit(ls, "receive_request_reply %x from %d %d "
429762306a36Sopenharmony_ci			  "master %d dir %d first %x %s", lkb->lkb_id,
429862306a36Sopenharmony_ci			  from_nodeid, result, r->res_master_nodeid,
429962306a36Sopenharmony_ci			  r->res_dir_nodeid, r->res_first_lkid, r->res_name);
430062306a36Sopenharmony_ci
430162306a36Sopenharmony_ci		if (r->res_dir_nodeid != dlm_our_nodeid() &&
430262306a36Sopenharmony_ci		    r->res_master_nodeid != dlm_our_nodeid()) {
430362306a36Sopenharmony_ci			/* cause _request_lock->set_master->send_lookup */
430462306a36Sopenharmony_ci			r->res_master_nodeid = 0;
430562306a36Sopenharmony_ci			r->res_nodeid = -1;
430662306a36Sopenharmony_ci			lkb->lkb_nodeid = -1;
430762306a36Sopenharmony_ci		}
430862306a36Sopenharmony_ci
430962306a36Sopenharmony_ci		if (is_overlap(lkb)) {
431062306a36Sopenharmony_ci			/* we'll ignore error in cancel/unlock reply */
431162306a36Sopenharmony_ci			queue_cast_overlap(r, lkb);
431262306a36Sopenharmony_ci			confirm_master(r, result);
431362306a36Sopenharmony_ci			unhold_lkb(lkb); /* undoes create_lkb() */
431462306a36Sopenharmony_ci		} else {
431562306a36Sopenharmony_ci			_request_lock(r, lkb);
431662306a36Sopenharmony_ci
431762306a36Sopenharmony_ci			if (r->res_master_nodeid == dlm_our_nodeid())
431862306a36Sopenharmony_ci				confirm_master(r, 0);
431962306a36Sopenharmony_ci		}
432062306a36Sopenharmony_ci		break;
432162306a36Sopenharmony_ci
432262306a36Sopenharmony_ci	default:
432362306a36Sopenharmony_ci		log_error(ls, "receive_request_reply %x error %d",
432462306a36Sopenharmony_ci			  lkb->lkb_id, result);
432562306a36Sopenharmony_ci	}
432662306a36Sopenharmony_ci
432762306a36Sopenharmony_ci	if ((result == 0 || result == -EINPROGRESS) &&
432862306a36Sopenharmony_ci	    test_and_clear_bit(DLM_IFL_OVERLAP_UNLOCK_BIT, &lkb->lkb_iflags)) {
432962306a36Sopenharmony_ci		log_debug(ls, "receive_request_reply %x result %d unlock",
433062306a36Sopenharmony_ci			  lkb->lkb_id, result);
433162306a36Sopenharmony_ci		clear_bit(DLM_IFL_OVERLAP_CANCEL_BIT, &lkb->lkb_iflags);
433262306a36Sopenharmony_ci		send_unlock(r, lkb);
433362306a36Sopenharmony_ci	} else if ((result == -EINPROGRESS) &&
433462306a36Sopenharmony_ci		   test_and_clear_bit(DLM_IFL_OVERLAP_CANCEL_BIT,
433562306a36Sopenharmony_ci				      &lkb->lkb_iflags)) {
433662306a36Sopenharmony_ci		log_debug(ls, "receive_request_reply %x cancel", lkb->lkb_id);
433762306a36Sopenharmony_ci		clear_bit(DLM_IFL_OVERLAP_UNLOCK_BIT, &lkb->lkb_iflags);
433862306a36Sopenharmony_ci		send_cancel(r, lkb);
433962306a36Sopenharmony_ci	} else {
434062306a36Sopenharmony_ci		clear_bit(DLM_IFL_OVERLAP_CANCEL_BIT, &lkb->lkb_iflags);
434162306a36Sopenharmony_ci		clear_bit(DLM_IFL_OVERLAP_UNLOCK_BIT, &lkb->lkb_iflags);
434262306a36Sopenharmony_ci	}
434362306a36Sopenharmony_ci out:
434462306a36Sopenharmony_ci	unlock_rsb(r);
434562306a36Sopenharmony_ci	put_rsb(r);
434662306a36Sopenharmony_ci	dlm_put_lkb(lkb);
434762306a36Sopenharmony_ci	return 0;
434862306a36Sopenharmony_ci}
434962306a36Sopenharmony_ci
435062306a36Sopenharmony_cistatic void __receive_convert_reply(struct dlm_rsb *r, struct dlm_lkb *lkb,
435162306a36Sopenharmony_ci				    const struct dlm_message *ms, bool local)
435262306a36Sopenharmony_ci{
435362306a36Sopenharmony_ci	/* this is the value returned from do_convert() on the master */
435462306a36Sopenharmony_ci	switch (from_dlm_errno(le32_to_cpu(ms->m_result))) {
435562306a36Sopenharmony_ci	case -EAGAIN:
435662306a36Sopenharmony_ci		/* convert would block (be queued) on remote master */
435762306a36Sopenharmony_ci		queue_cast(r, lkb, -EAGAIN);
435862306a36Sopenharmony_ci		break;
435962306a36Sopenharmony_ci
436062306a36Sopenharmony_ci	case -EDEADLK:
436162306a36Sopenharmony_ci		receive_flags_reply(lkb, ms, local);
436262306a36Sopenharmony_ci		revert_lock_pc(r, lkb);
436362306a36Sopenharmony_ci		queue_cast(r, lkb, -EDEADLK);
436462306a36Sopenharmony_ci		break;
436562306a36Sopenharmony_ci
436662306a36Sopenharmony_ci	case -EINPROGRESS:
436762306a36Sopenharmony_ci		/* convert was queued on remote master */
436862306a36Sopenharmony_ci		receive_flags_reply(lkb, ms, local);
436962306a36Sopenharmony_ci		if (is_demoted(lkb))
437062306a36Sopenharmony_ci			munge_demoted(lkb);
437162306a36Sopenharmony_ci		del_lkb(r, lkb);
437262306a36Sopenharmony_ci		add_lkb(r, lkb, DLM_LKSTS_CONVERT);
437362306a36Sopenharmony_ci		break;
437462306a36Sopenharmony_ci
437562306a36Sopenharmony_ci	case 0:
437662306a36Sopenharmony_ci		/* convert was granted on remote master */
437762306a36Sopenharmony_ci		receive_flags_reply(lkb, ms, local);
437862306a36Sopenharmony_ci		if (is_demoted(lkb))
437962306a36Sopenharmony_ci			munge_demoted(lkb);
438062306a36Sopenharmony_ci		grant_lock_pc(r, lkb, ms);
438162306a36Sopenharmony_ci		queue_cast(r, lkb, 0);
438262306a36Sopenharmony_ci		break;
438362306a36Sopenharmony_ci
438462306a36Sopenharmony_ci	default:
438562306a36Sopenharmony_ci		log_error(r->res_ls, "receive_convert_reply %x remote %d %x %d",
438662306a36Sopenharmony_ci			  lkb->lkb_id, le32_to_cpu(ms->m_header.h_nodeid),
438762306a36Sopenharmony_ci			  le32_to_cpu(ms->m_lkid),
438862306a36Sopenharmony_ci			  from_dlm_errno(le32_to_cpu(ms->m_result)));
438962306a36Sopenharmony_ci		dlm_print_rsb(r);
439062306a36Sopenharmony_ci		dlm_print_lkb(lkb);
439162306a36Sopenharmony_ci	}
439262306a36Sopenharmony_ci}
439362306a36Sopenharmony_ci
439462306a36Sopenharmony_cistatic void _receive_convert_reply(struct dlm_lkb *lkb,
439562306a36Sopenharmony_ci				   const struct dlm_message *ms, bool local)
439662306a36Sopenharmony_ci{
439762306a36Sopenharmony_ci	struct dlm_rsb *r = lkb->lkb_resource;
439862306a36Sopenharmony_ci	int error;
439962306a36Sopenharmony_ci
440062306a36Sopenharmony_ci	hold_rsb(r);
440162306a36Sopenharmony_ci	lock_rsb(r);
440262306a36Sopenharmony_ci
440362306a36Sopenharmony_ci	error = validate_message(lkb, ms);
440462306a36Sopenharmony_ci	if (error)
440562306a36Sopenharmony_ci		goto out;
440662306a36Sopenharmony_ci
440762306a36Sopenharmony_ci	/* local reply can happen with waiters_mutex held */
440862306a36Sopenharmony_ci	error = remove_from_waiters_ms(lkb, ms, local);
440962306a36Sopenharmony_ci	if (error)
441062306a36Sopenharmony_ci		goto out;
441162306a36Sopenharmony_ci
441262306a36Sopenharmony_ci	__receive_convert_reply(r, lkb, ms, local);
441362306a36Sopenharmony_ci out:
441462306a36Sopenharmony_ci	unlock_rsb(r);
441562306a36Sopenharmony_ci	put_rsb(r);
441662306a36Sopenharmony_ci}
441762306a36Sopenharmony_ci
441862306a36Sopenharmony_cistatic int receive_convert_reply(struct dlm_ls *ls,
441962306a36Sopenharmony_ci				 const struct dlm_message *ms)
442062306a36Sopenharmony_ci{
442162306a36Sopenharmony_ci	struct dlm_lkb *lkb;
442262306a36Sopenharmony_ci	int error;
442362306a36Sopenharmony_ci
442462306a36Sopenharmony_ci	error = find_lkb(ls, le32_to_cpu(ms->m_remid), &lkb);
442562306a36Sopenharmony_ci	if (error)
442662306a36Sopenharmony_ci		return error;
442762306a36Sopenharmony_ci
442862306a36Sopenharmony_ci	_receive_convert_reply(lkb, ms, false);
442962306a36Sopenharmony_ci	dlm_put_lkb(lkb);
443062306a36Sopenharmony_ci	return 0;
443162306a36Sopenharmony_ci}
443262306a36Sopenharmony_ci
443362306a36Sopenharmony_cistatic void _receive_unlock_reply(struct dlm_lkb *lkb,
443462306a36Sopenharmony_ci				  const struct dlm_message *ms, bool local)
443562306a36Sopenharmony_ci{
443662306a36Sopenharmony_ci	struct dlm_rsb *r = lkb->lkb_resource;
443762306a36Sopenharmony_ci	int error;
443862306a36Sopenharmony_ci
443962306a36Sopenharmony_ci	hold_rsb(r);
444062306a36Sopenharmony_ci	lock_rsb(r);
444162306a36Sopenharmony_ci
444262306a36Sopenharmony_ci	error = validate_message(lkb, ms);
444362306a36Sopenharmony_ci	if (error)
444462306a36Sopenharmony_ci		goto out;
444562306a36Sopenharmony_ci
444662306a36Sopenharmony_ci	/* local reply can happen with waiters_mutex held */
444762306a36Sopenharmony_ci	error = remove_from_waiters_ms(lkb, ms, local);
444862306a36Sopenharmony_ci	if (error)
444962306a36Sopenharmony_ci		goto out;
445062306a36Sopenharmony_ci
445162306a36Sopenharmony_ci	/* this is the value returned from do_unlock() on the master */
445262306a36Sopenharmony_ci
445362306a36Sopenharmony_ci	switch (from_dlm_errno(le32_to_cpu(ms->m_result))) {
445462306a36Sopenharmony_ci	case -DLM_EUNLOCK:
445562306a36Sopenharmony_ci		receive_flags_reply(lkb, ms, local);
445662306a36Sopenharmony_ci		remove_lock_pc(r, lkb);
445762306a36Sopenharmony_ci		queue_cast(r, lkb, -DLM_EUNLOCK);
445862306a36Sopenharmony_ci		break;
445962306a36Sopenharmony_ci	case -ENOENT:
446062306a36Sopenharmony_ci		break;
446162306a36Sopenharmony_ci	default:
446262306a36Sopenharmony_ci		log_error(r->res_ls, "receive_unlock_reply %x error %d",
446362306a36Sopenharmony_ci			  lkb->lkb_id, from_dlm_errno(le32_to_cpu(ms->m_result)));
446462306a36Sopenharmony_ci	}
446562306a36Sopenharmony_ci out:
446662306a36Sopenharmony_ci	unlock_rsb(r);
446762306a36Sopenharmony_ci	put_rsb(r);
446862306a36Sopenharmony_ci}
446962306a36Sopenharmony_ci
447062306a36Sopenharmony_cistatic int receive_unlock_reply(struct dlm_ls *ls,
447162306a36Sopenharmony_ci				const struct dlm_message *ms)
447262306a36Sopenharmony_ci{
447362306a36Sopenharmony_ci	struct dlm_lkb *lkb;
447462306a36Sopenharmony_ci	int error;
447562306a36Sopenharmony_ci
447662306a36Sopenharmony_ci	error = find_lkb(ls, le32_to_cpu(ms->m_remid), &lkb);
447762306a36Sopenharmony_ci	if (error)
447862306a36Sopenharmony_ci		return error;
447962306a36Sopenharmony_ci
448062306a36Sopenharmony_ci	_receive_unlock_reply(lkb, ms, false);
448162306a36Sopenharmony_ci	dlm_put_lkb(lkb);
448262306a36Sopenharmony_ci	return 0;
448362306a36Sopenharmony_ci}
448462306a36Sopenharmony_ci
448562306a36Sopenharmony_cistatic void _receive_cancel_reply(struct dlm_lkb *lkb,
448662306a36Sopenharmony_ci				  const struct dlm_message *ms, bool local)
448762306a36Sopenharmony_ci{
448862306a36Sopenharmony_ci	struct dlm_rsb *r = lkb->lkb_resource;
448962306a36Sopenharmony_ci	int error;
449062306a36Sopenharmony_ci
449162306a36Sopenharmony_ci	hold_rsb(r);
449262306a36Sopenharmony_ci	lock_rsb(r);
449362306a36Sopenharmony_ci
449462306a36Sopenharmony_ci	error = validate_message(lkb, ms);
449562306a36Sopenharmony_ci	if (error)
449662306a36Sopenharmony_ci		goto out;
449762306a36Sopenharmony_ci
449862306a36Sopenharmony_ci	/* local reply can happen with waiters_mutex held */
449962306a36Sopenharmony_ci	error = remove_from_waiters_ms(lkb, ms, local);
450062306a36Sopenharmony_ci	if (error)
450162306a36Sopenharmony_ci		goto out;
450262306a36Sopenharmony_ci
450362306a36Sopenharmony_ci	/* this is the value returned from do_cancel() on the master */
450462306a36Sopenharmony_ci
450562306a36Sopenharmony_ci	switch (from_dlm_errno(le32_to_cpu(ms->m_result))) {
450662306a36Sopenharmony_ci	case -DLM_ECANCEL:
450762306a36Sopenharmony_ci		receive_flags_reply(lkb, ms, local);
450862306a36Sopenharmony_ci		revert_lock_pc(r, lkb);
450962306a36Sopenharmony_ci		queue_cast(r, lkb, -DLM_ECANCEL);
451062306a36Sopenharmony_ci		break;
451162306a36Sopenharmony_ci	case 0:
451262306a36Sopenharmony_ci		break;
451362306a36Sopenharmony_ci	default:
451462306a36Sopenharmony_ci		log_error(r->res_ls, "receive_cancel_reply %x error %d",
451562306a36Sopenharmony_ci			  lkb->lkb_id,
451662306a36Sopenharmony_ci			  from_dlm_errno(le32_to_cpu(ms->m_result)));
451762306a36Sopenharmony_ci	}
451862306a36Sopenharmony_ci out:
451962306a36Sopenharmony_ci	unlock_rsb(r);
452062306a36Sopenharmony_ci	put_rsb(r);
452162306a36Sopenharmony_ci}
452262306a36Sopenharmony_ci
452362306a36Sopenharmony_cistatic int receive_cancel_reply(struct dlm_ls *ls,
452462306a36Sopenharmony_ci				const struct dlm_message *ms)
452562306a36Sopenharmony_ci{
452662306a36Sopenharmony_ci	struct dlm_lkb *lkb;
452762306a36Sopenharmony_ci	int error;
452862306a36Sopenharmony_ci
452962306a36Sopenharmony_ci	error = find_lkb(ls, le32_to_cpu(ms->m_remid), &lkb);
453062306a36Sopenharmony_ci	if (error)
453162306a36Sopenharmony_ci		return error;
453262306a36Sopenharmony_ci
453362306a36Sopenharmony_ci	_receive_cancel_reply(lkb, ms, false);
453462306a36Sopenharmony_ci	dlm_put_lkb(lkb);
453562306a36Sopenharmony_ci	return 0;
453662306a36Sopenharmony_ci}
453762306a36Sopenharmony_ci
453862306a36Sopenharmony_cistatic void receive_lookup_reply(struct dlm_ls *ls,
453962306a36Sopenharmony_ci				 const struct dlm_message *ms)
454062306a36Sopenharmony_ci{
454162306a36Sopenharmony_ci	struct dlm_lkb *lkb;
454262306a36Sopenharmony_ci	struct dlm_rsb *r;
454362306a36Sopenharmony_ci	int error, ret_nodeid;
454462306a36Sopenharmony_ci	int do_lookup_list = 0;
454562306a36Sopenharmony_ci
454662306a36Sopenharmony_ci	error = find_lkb(ls, le32_to_cpu(ms->m_lkid), &lkb);
454762306a36Sopenharmony_ci	if (error) {
454862306a36Sopenharmony_ci		log_error(ls, "%s no lkid %x", __func__,
454962306a36Sopenharmony_ci			  le32_to_cpu(ms->m_lkid));
455062306a36Sopenharmony_ci		return;
455162306a36Sopenharmony_ci	}
455262306a36Sopenharmony_ci
455362306a36Sopenharmony_ci	/* ms->m_result is the value returned by dlm_master_lookup on dir node
455462306a36Sopenharmony_ci	   FIXME: will a non-zero error ever be returned? */
455562306a36Sopenharmony_ci
455662306a36Sopenharmony_ci	r = lkb->lkb_resource;
455762306a36Sopenharmony_ci	hold_rsb(r);
455862306a36Sopenharmony_ci	lock_rsb(r);
455962306a36Sopenharmony_ci
456062306a36Sopenharmony_ci	error = remove_from_waiters(lkb, DLM_MSG_LOOKUP_REPLY);
456162306a36Sopenharmony_ci	if (error)
456262306a36Sopenharmony_ci		goto out;
456362306a36Sopenharmony_ci
456462306a36Sopenharmony_ci	ret_nodeid = le32_to_cpu(ms->m_nodeid);
456562306a36Sopenharmony_ci
456662306a36Sopenharmony_ci	/* We sometimes receive a request from the dir node for this
456762306a36Sopenharmony_ci	   rsb before we've received the dir node's loookup_reply for it.
456862306a36Sopenharmony_ci	   The request from the dir node implies we're the master, so we set
456962306a36Sopenharmony_ci	   ourself as master in receive_request_reply, and verify here that
457062306a36Sopenharmony_ci	   we are indeed the master. */
457162306a36Sopenharmony_ci
457262306a36Sopenharmony_ci	if (r->res_master_nodeid && (r->res_master_nodeid != ret_nodeid)) {
457362306a36Sopenharmony_ci		/* This should never happen */
457462306a36Sopenharmony_ci		log_error(ls, "receive_lookup_reply %x from %d ret %d "
457562306a36Sopenharmony_ci			  "master %d dir %d our %d first %x %s",
457662306a36Sopenharmony_ci			  lkb->lkb_id, le32_to_cpu(ms->m_header.h_nodeid),
457762306a36Sopenharmony_ci			  ret_nodeid, r->res_master_nodeid, r->res_dir_nodeid,
457862306a36Sopenharmony_ci			  dlm_our_nodeid(), r->res_first_lkid, r->res_name);
457962306a36Sopenharmony_ci	}
458062306a36Sopenharmony_ci
458162306a36Sopenharmony_ci	if (ret_nodeid == dlm_our_nodeid()) {
458262306a36Sopenharmony_ci		r->res_master_nodeid = ret_nodeid;
458362306a36Sopenharmony_ci		r->res_nodeid = 0;
458462306a36Sopenharmony_ci		do_lookup_list = 1;
458562306a36Sopenharmony_ci		r->res_first_lkid = 0;
458662306a36Sopenharmony_ci	} else if (ret_nodeid == -1) {
458762306a36Sopenharmony_ci		/* the remote node doesn't believe it's the dir node */
458862306a36Sopenharmony_ci		log_error(ls, "receive_lookup_reply %x from %d bad ret_nodeid",
458962306a36Sopenharmony_ci			  lkb->lkb_id, le32_to_cpu(ms->m_header.h_nodeid));
459062306a36Sopenharmony_ci		r->res_master_nodeid = 0;
459162306a36Sopenharmony_ci		r->res_nodeid = -1;
459262306a36Sopenharmony_ci		lkb->lkb_nodeid = -1;
459362306a36Sopenharmony_ci	} else {
459462306a36Sopenharmony_ci		/* set_master() will set lkb_nodeid from r */
459562306a36Sopenharmony_ci		r->res_master_nodeid = ret_nodeid;
459662306a36Sopenharmony_ci		r->res_nodeid = ret_nodeid;
459762306a36Sopenharmony_ci	}
459862306a36Sopenharmony_ci
459962306a36Sopenharmony_ci	if (is_overlap(lkb)) {
460062306a36Sopenharmony_ci		log_debug(ls, "receive_lookup_reply %x unlock %x",
460162306a36Sopenharmony_ci			  lkb->lkb_id, dlm_iflags_val(lkb));
460262306a36Sopenharmony_ci		queue_cast_overlap(r, lkb);
460362306a36Sopenharmony_ci		unhold_lkb(lkb); /* undoes create_lkb() */
460462306a36Sopenharmony_ci		goto out_list;
460562306a36Sopenharmony_ci	}
460662306a36Sopenharmony_ci
460762306a36Sopenharmony_ci	_request_lock(r, lkb);
460862306a36Sopenharmony_ci
460962306a36Sopenharmony_ci out_list:
461062306a36Sopenharmony_ci	if (do_lookup_list)
461162306a36Sopenharmony_ci		process_lookup_list(r);
461262306a36Sopenharmony_ci out:
461362306a36Sopenharmony_ci	unlock_rsb(r);
461462306a36Sopenharmony_ci	put_rsb(r);
461562306a36Sopenharmony_ci	dlm_put_lkb(lkb);
461662306a36Sopenharmony_ci}
461762306a36Sopenharmony_ci
461862306a36Sopenharmony_cistatic void _receive_message(struct dlm_ls *ls, const struct dlm_message *ms,
461962306a36Sopenharmony_ci			     uint32_t saved_seq)
462062306a36Sopenharmony_ci{
462162306a36Sopenharmony_ci	int error = 0, noent = 0;
462262306a36Sopenharmony_ci
462362306a36Sopenharmony_ci	if (WARN_ON_ONCE(!dlm_is_member(ls, le32_to_cpu(ms->m_header.h_nodeid)))) {
462462306a36Sopenharmony_ci		log_limit(ls, "receive %d from non-member %d %x %x %d",
462562306a36Sopenharmony_ci			  le32_to_cpu(ms->m_type),
462662306a36Sopenharmony_ci			  le32_to_cpu(ms->m_header.h_nodeid),
462762306a36Sopenharmony_ci			  le32_to_cpu(ms->m_lkid), le32_to_cpu(ms->m_remid),
462862306a36Sopenharmony_ci			  from_dlm_errno(le32_to_cpu(ms->m_result)));
462962306a36Sopenharmony_ci		return;
463062306a36Sopenharmony_ci	}
463162306a36Sopenharmony_ci
463262306a36Sopenharmony_ci	switch (ms->m_type) {
463362306a36Sopenharmony_ci
463462306a36Sopenharmony_ci	/* messages sent to a master node */
463562306a36Sopenharmony_ci
463662306a36Sopenharmony_ci	case cpu_to_le32(DLM_MSG_REQUEST):
463762306a36Sopenharmony_ci		error = receive_request(ls, ms);
463862306a36Sopenharmony_ci		break;
463962306a36Sopenharmony_ci
464062306a36Sopenharmony_ci	case cpu_to_le32(DLM_MSG_CONVERT):
464162306a36Sopenharmony_ci		error = receive_convert(ls, ms);
464262306a36Sopenharmony_ci		break;
464362306a36Sopenharmony_ci
464462306a36Sopenharmony_ci	case cpu_to_le32(DLM_MSG_UNLOCK):
464562306a36Sopenharmony_ci		error = receive_unlock(ls, ms);
464662306a36Sopenharmony_ci		break;
464762306a36Sopenharmony_ci
464862306a36Sopenharmony_ci	case cpu_to_le32(DLM_MSG_CANCEL):
464962306a36Sopenharmony_ci		noent = 1;
465062306a36Sopenharmony_ci		error = receive_cancel(ls, ms);
465162306a36Sopenharmony_ci		break;
465262306a36Sopenharmony_ci
465362306a36Sopenharmony_ci	/* messages sent from a master node (replies to above) */
465462306a36Sopenharmony_ci
465562306a36Sopenharmony_ci	case cpu_to_le32(DLM_MSG_REQUEST_REPLY):
465662306a36Sopenharmony_ci		error = receive_request_reply(ls, ms);
465762306a36Sopenharmony_ci		break;
465862306a36Sopenharmony_ci
465962306a36Sopenharmony_ci	case cpu_to_le32(DLM_MSG_CONVERT_REPLY):
466062306a36Sopenharmony_ci		error = receive_convert_reply(ls, ms);
466162306a36Sopenharmony_ci		break;
466262306a36Sopenharmony_ci
466362306a36Sopenharmony_ci	case cpu_to_le32(DLM_MSG_UNLOCK_REPLY):
466462306a36Sopenharmony_ci		error = receive_unlock_reply(ls, ms);
466562306a36Sopenharmony_ci		break;
466662306a36Sopenharmony_ci
466762306a36Sopenharmony_ci	case cpu_to_le32(DLM_MSG_CANCEL_REPLY):
466862306a36Sopenharmony_ci		error = receive_cancel_reply(ls, ms);
466962306a36Sopenharmony_ci		break;
467062306a36Sopenharmony_ci
467162306a36Sopenharmony_ci	/* messages sent from a master node (only two types of async msg) */
467262306a36Sopenharmony_ci
467362306a36Sopenharmony_ci	case cpu_to_le32(DLM_MSG_GRANT):
467462306a36Sopenharmony_ci		noent = 1;
467562306a36Sopenharmony_ci		error = receive_grant(ls, ms);
467662306a36Sopenharmony_ci		break;
467762306a36Sopenharmony_ci
467862306a36Sopenharmony_ci	case cpu_to_le32(DLM_MSG_BAST):
467962306a36Sopenharmony_ci		noent = 1;
468062306a36Sopenharmony_ci		error = receive_bast(ls, ms);
468162306a36Sopenharmony_ci		break;
468262306a36Sopenharmony_ci
468362306a36Sopenharmony_ci	/* messages sent to a dir node */
468462306a36Sopenharmony_ci
468562306a36Sopenharmony_ci	case cpu_to_le32(DLM_MSG_LOOKUP):
468662306a36Sopenharmony_ci		receive_lookup(ls, ms);
468762306a36Sopenharmony_ci		break;
468862306a36Sopenharmony_ci
468962306a36Sopenharmony_ci	case cpu_to_le32(DLM_MSG_REMOVE):
469062306a36Sopenharmony_ci		receive_remove(ls, ms);
469162306a36Sopenharmony_ci		break;
469262306a36Sopenharmony_ci
469362306a36Sopenharmony_ci	/* messages sent from a dir node (remove has no reply) */
469462306a36Sopenharmony_ci
469562306a36Sopenharmony_ci	case cpu_to_le32(DLM_MSG_LOOKUP_REPLY):
469662306a36Sopenharmony_ci		receive_lookup_reply(ls, ms);
469762306a36Sopenharmony_ci		break;
469862306a36Sopenharmony_ci
469962306a36Sopenharmony_ci	/* other messages */
470062306a36Sopenharmony_ci
470162306a36Sopenharmony_ci	case cpu_to_le32(DLM_MSG_PURGE):
470262306a36Sopenharmony_ci		receive_purge(ls, ms);
470362306a36Sopenharmony_ci		break;
470462306a36Sopenharmony_ci
470562306a36Sopenharmony_ci	default:
470662306a36Sopenharmony_ci		log_error(ls, "unknown message type %d",
470762306a36Sopenharmony_ci			  le32_to_cpu(ms->m_type));
470862306a36Sopenharmony_ci	}
470962306a36Sopenharmony_ci
471062306a36Sopenharmony_ci	/*
471162306a36Sopenharmony_ci	 * When checking for ENOENT, we're checking the result of
471262306a36Sopenharmony_ci	 * find_lkb(m_remid):
471362306a36Sopenharmony_ci	 *
471462306a36Sopenharmony_ci	 * The lock id referenced in the message wasn't found.  This may
471562306a36Sopenharmony_ci	 * happen in normal usage for the async messages and cancel, so
471662306a36Sopenharmony_ci	 * only use log_debug for them.
471762306a36Sopenharmony_ci	 *
471862306a36Sopenharmony_ci	 * Some errors are expected and normal.
471962306a36Sopenharmony_ci	 */
472062306a36Sopenharmony_ci
472162306a36Sopenharmony_ci	if (error == -ENOENT && noent) {
472262306a36Sopenharmony_ci		log_debug(ls, "receive %d no %x remote %d %x saved_seq %u",
472362306a36Sopenharmony_ci			  le32_to_cpu(ms->m_type), le32_to_cpu(ms->m_remid),
472462306a36Sopenharmony_ci			  le32_to_cpu(ms->m_header.h_nodeid),
472562306a36Sopenharmony_ci			  le32_to_cpu(ms->m_lkid), saved_seq);
472662306a36Sopenharmony_ci	} else if (error == -ENOENT) {
472762306a36Sopenharmony_ci		log_error(ls, "receive %d no %x remote %d %x saved_seq %u",
472862306a36Sopenharmony_ci			  le32_to_cpu(ms->m_type), le32_to_cpu(ms->m_remid),
472962306a36Sopenharmony_ci			  le32_to_cpu(ms->m_header.h_nodeid),
473062306a36Sopenharmony_ci			  le32_to_cpu(ms->m_lkid), saved_seq);
473162306a36Sopenharmony_ci
473262306a36Sopenharmony_ci		if (ms->m_type == cpu_to_le32(DLM_MSG_CONVERT))
473362306a36Sopenharmony_ci			dlm_dump_rsb_hash(ls, le32_to_cpu(ms->m_hash));
473462306a36Sopenharmony_ci	}
473562306a36Sopenharmony_ci
473662306a36Sopenharmony_ci	if (error == -EINVAL) {
473762306a36Sopenharmony_ci		log_error(ls, "receive %d inval from %d lkid %x remid %x "
473862306a36Sopenharmony_ci			  "saved_seq %u",
473962306a36Sopenharmony_ci			  le32_to_cpu(ms->m_type),
474062306a36Sopenharmony_ci			  le32_to_cpu(ms->m_header.h_nodeid),
474162306a36Sopenharmony_ci			  le32_to_cpu(ms->m_lkid), le32_to_cpu(ms->m_remid),
474262306a36Sopenharmony_ci			  saved_seq);
474362306a36Sopenharmony_ci	}
474462306a36Sopenharmony_ci}
474562306a36Sopenharmony_ci
474662306a36Sopenharmony_ci/* If the lockspace is in recovery mode (locking stopped), then normal
474762306a36Sopenharmony_ci   messages are saved on the requestqueue for processing after recovery is
474862306a36Sopenharmony_ci   done.  When not in recovery mode, we wait for dlm_recoverd to drain saved
474962306a36Sopenharmony_ci   messages off the requestqueue before we process new ones. This occurs right
475062306a36Sopenharmony_ci   after recovery completes when we transition from saving all messages on
475162306a36Sopenharmony_ci   requestqueue, to processing all the saved messages, to processing new
475262306a36Sopenharmony_ci   messages as they arrive. */
475362306a36Sopenharmony_ci
475462306a36Sopenharmony_cistatic void dlm_receive_message(struct dlm_ls *ls, const struct dlm_message *ms,
475562306a36Sopenharmony_ci				int nodeid)
475662306a36Sopenharmony_ci{
475762306a36Sopenharmony_ci	if (dlm_locking_stopped(ls)) {
475862306a36Sopenharmony_ci		/* If we were a member of this lockspace, left, and rejoined,
475962306a36Sopenharmony_ci		   other nodes may still be sending us messages from the
476062306a36Sopenharmony_ci		   lockspace generation before we left. */
476162306a36Sopenharmony_ci		if (WARN_ON_ONCE(!ls->ls_generation)) {
476262306a36Sopenharmony_ci			log_limit(ls, "receive %d from %d ignore old gen",
476362306a36Sopenharmony_ci				  le32_to_cpu(ms->m_type), nodeid);
476462306a36Sopenharmony_ci			return;
476562306a36Sopenharmony_ci		}
476662306a36Sopenharmony_ci
476762306a36Sopenharmony_ci		dlm_add_requestqueue(ls, nodeid, ms);
476862306a36Sopenharmony_ci	} else {
476962306a36Sopenharmony_ci		dlm_wait_requestqueue(ls);
477062306a36Sopenharmony_ci		_receive_message(ls, ms, 0);
477162306a36Sopenharmony_ci	}
477262306a36Sopenharmony_ci}
477362306a36Sopenharmony_ci
477462306a36Sopenharmony_ci/* This is called by dlm_recoverd to process messages that were saved on
477562306a36Sopenharmony_ci   the requestqueue. */
477662306a36Sopenharmony_ci
477762306a36Sopenharmony_civoid dlm_receive_message_saved(struct dlm_ls *ls, const struct dlm_message *ms,
477862306a36Sopenharmony_ci			       uint32_t saved_seq)
477962306a36Sopenharmony_ci{
478062306a36Sopenharmony_ci	_receive_message(ls, ms, saved_seq);
478162306a36Sopenharmony_ci}
478262306a36Sopenharmony_ci
478362306a36Sopenharmony_ci/* This is called by the midcomms layer when something is received for
478462306a36Sopenharmony_ci   the lockspace.  It could be either a MSG (normal message sent as part of
478562306a36Sopenharmony_ci   standard locking activity) or an RCOM (recovery message sent as part of
478662306a36Sopenharmony_ci   lockspace recovery). */
478762306a36Sopenharmony_ci
478862306a36Sopenharmony_civoid dlm_receive_buffer(const union dlm_packet *p, int nodeid)
478962306a36Sopenharmony_ci{
479062306a36Sopenharmony_ci	const struct dlm_header *hd = &p->header;
479162306a36Sopenharmony_ci	struct dlm_ls *ls;
479262306a36Sopenharmony_ci	int type = 0;
479362306a36Sopenharmony_ci
479462306a36Sopenharmony_ci	switch (hd->h_cmd) {
479562306a36Sopenharmony_ci	case DLM_MSG:
479662306a36Sopenharmony_ci		type = le32_to_cpu(p->message.m_type);
479762306a36Sopenharmony_ci		break;
479862306a36Sopenharmony_ci	case DLM_RCOM:
479962306a36Sopenharmony_ci		type = le32_to_cpu(p->rcom.rc_type);
480062306a36Sopenharmony_ci		break;
480162306a36Sopenharmony_ci	default:
480262306a36Sopenharmony_ci		log_print("invalid h_cmd %d from %u", hd->h_cmd, nodeid);
480362306a36Sopenharmony_ci		return;
480462306a36Sopenharmony_ci	}
480562306a36Sopenharmony_ci
480662306a36Sopenharmony_ci	if (le32_to_cpu(hd->h_nodeid) != nodeid) {
480762306a36Sopenharmony_ci		log_print("invalid h_nodeid %d from %d lockspace %x",
480862306a36Sopenharmony_ci			  le32_to_cpu(hd->h_nodeid), nodeid,
480962306a36Sopenharmony_ci			  le32_to_cpu(hd->u.h_lockspace));
481062306a36Sopenharmony_ci		return;
481162306a36Sopenharmony_ci	}
481262306a36Sopenharmony_ci
481362306a36Sopenharmony_ci	ls = dlm_find_lockspace_global(le32_to_cpu(hd->u.h_lockspace));
481462306a36Sopenharmony_ci	if (!ls) {
481562306a36Sopenharmony_ci		if (dlm_config.ci_log_debug) {
481662306a36Sopenharmony_ci			printk_ratelimited(KERN_DEBUG "dlm: invalid lockspace "
481762306a36Sopenharmony_ci				"%u from %d cmd %d type %d\n",
481862306a36Sopenharmony_ci				le32_to_cpu(hd->u.h_lockspace), nodeid,
481962306a36Sopenharmony_ci				hd->h_cmd, type);
482062306a36Sopenharmony_ci		}
482162306a36Sopenharmony_ci
482262306a36Sopenharmony_ci		if (hd->h_cmd == DLM_RCOM && type == DLM_RCOM_STATUS)
482362306a36Sopenharmony_ci			dlm_send_ls_not_ready(nodeid, &p->rcom);
482462306a36Sopenharmony_ci		return;
482562306a36Sopenharmony_ci	}
482662306a36Sopenharmony_ci
482762306a36Sopenharmony_ci	/* this rwsem allows dlm_ls_stop() to wait for all dlm_recv threads to
482862306a36Sopenharmony_ci	   be inactive (in this ls) before transitioning to recovery mode */
482962306a36Sopenharmony_ci
483062306a36Sopenharmony_ci	down_read(&ls->ls_recv_active);
483162306a36Sopenharmony_ci	if (hd->h_cmd == DLM_MSG)
483262306a36Sopenharmony_ci		dlm_receive_message(ls, &p->message, nodeid);
483362306a36Sopenharmony_ci	else if (hd->h_cmd == DLM_RCOM)
483462306a36Sopenharmony_ci		dlm_receive_rcom(ls, &p->rcom, nodeid);
483562306a36Sopenharmony_ci	else
483662306a36Sopenharmony_ci		log_error(ls, "invalid h_cmd %d from %d lockspace %x",
483762306a36Sopenharmony_ci			  hd->h_cmd, nodeid, le32_to_cpu(hd->u.h_lockspace));
483862306a36Sopenharmony_ci	up_read(&ls->ls_recv_active);
483962306a36Sopenharmony_ci
484062306a36Sopenharmony_ci	dlm_put_lockspace(ls);
484162306a36Sopenharmony_ci}
484262306a36Sopenharmony_ci
484362306a36Sopenharmony_cistatic void recover_convert_waiter(struct dlm_ls *ls, struct dlm_lkb *lkb,
484462306a36Sopenharmony_ci				   struct dlm_message *ms_local)
484562306a36Sopenharmony_ci{
484662306a36Sopenharmony_ci	if (middle_conversion(lkb)) {
484762306a36Sopenharmony_ci		hold_lkb(lkb);
484862306a36Sopenharmony_ci		memset(ms_local, 0, sizeof(struct dlm_message));
484962306a36Sopenharmony_ci		ms_local->m_type = cpu_to_le32(DLM_MSG_CONVERT_REPLY);
485062306a36Sopenharmony_ci		ms_local->m_result = cpu_to_le32(to_dlm_errno(-EINPROGRESS));
485162306a36Sopenharmony_ci		ms_local->m_header.h_nodeid = cpu_to_le32(lkb->lkb_nodeid);
485262306a36Sopenharmony_ci		_receive_convert_reply(lkb, ms_local, true);
485362306a36Sopenharmony_ci
485462306a36Sopenharmony_ci		/* Same special case as in receive_rcom_lock_args() */
485562306a36Sopenharmony_ci		lkb->lkb_grmode = DLM_LOCK_IV;
485662306a36Sopenharmony_ci		rsb_set_flag(lkb->lkb_resource, RSB_RECOVER_CONVERT);
485762306a36Sopenharmony_ci		unhold_lkb(lkb);
485862306a36Sopenharmony_ci
485962306a36Sopenharmony_ci	} else if (lkb->lkb_rqmode >= lkb->lkb_grmode) {
486062306a36Sopenharmony_ci		set_bit(DLM_IFL_RESEND_BIT, &lkb->lkb_iflags);
486162306a36Sopenharmony_ci	}
486262306a36Sopenharmony_ci
486362306a36Sopenharmony_ci	/* lkb->lkb_rqmode < lkb->lkb_grmode shouldn't happen since down
486462306a36Sopenharmony_ci	   conversions are async; there's no reply from the remote master */
486562306a36Sopenharmony_ci}
486662306a36Sopenharmony_ci
486762306a36Sopenharmony_ci/* A waiting lkb needs recovery if the master node has failed, or
486862306a36Sopenharmony_ci   the master node is changing (only when no directory is used) */
486962306a36Sopenharmony_ci
487062306a36Sopenharmony_cistatic int waiter_needs_recovery(struct dlm_ls *ls, struct dlm_lkb *lkb,
487162306a36Sopenharmony_ci				 int dir_nodeid)
487262306a36Sopenharmony_ci{
487362306a36Sopenharmony_ci	if (dlm_no_directory(ls))
487462306a36Sopenharmony_ci		return 1;
487562306a36Sopenharmony_ci
487662306a36Sopenharmony_ci	if (dlm_is_removed(ls, lkb->lkb_wait_nodeid))
487762306a36Sopenharmony_ci		return 1;
487862306a36Sopenharmony_ci
487962306a36Sopenharmony_ci	return 0;
488062306a36Sopenharmony_ci}
488162306a36Sopenharmony_ci
488262306a36Sopenharmony_ci/* Recovery for locks that are waiting for replies from nodes that are now
488362306a36Sopenharmony_ci   gone.  We can just complete unlocks and cancels by faking a reply from the
488462306a36Sopenharmony_ci   dead node.  Requests and up-conversions we flag to be resent after
488562306a36Sopenharmony_ci   recovery.  Down-conversions can just be completed with a fake reply like
488662306a36Sopenharmony_ci   unlocks.  Conversions between PR and CW need special attention. */
488762306a36Sopenharmony_ci
488862306a36Sopenharmony_civoid dlm_recover_waiters_pre(struct dlm_ls *ls)
488962306a36Sopenharmony_ci{
489062306a36Sopenharmony_ci	struct dlm_lkb *lkb, *safe;
489162306a36Sopenharmony_ci	struct dlm_message *ms_local;
489262306a36Sopenharmony_ci	int wait_type, local_unlock_result, local_cancel_result;
489362306a36Sopenharmony_ci	int dir_nodeid;
489462306a36Sopenharmony_ci
489562306a36Sopenharmony_ci	ms_local = kmalloc(sizeof(*ms_local), GFP_KERNEL);
489662306a36Sopenharmony_ci	if (!ms_local)
489762306a36Sopenharmony_ci		return;
489862306a36Sopenharmony_ci
489962306a36Sopenharmony_ci	mutex_lock(&ls->ls_waiters_mutex);
490062306a36Sopenharmony_ci
490162306a36Sopenharmony_ci	list_for_each_entry_safe(lkb, safe, &ls->ls_waiters, lkb_wait_reply) {
490262306a36Sopenharmony_ci
490362306a36Sopenharmony_ci		dir_nodeid = dlm_dir_nodeid(lkb->lkb_resource);
490462306a36Sopenharmony_ci
490562306a36Sopenharmony_ci		/* exclude debug messages about unlocks because there can be so
490662306a36Sopenharmony_ci		   many and they aren't very interesting */
490762306a36Sopenharmony_ci
490862306a36Sopenharmony_ci		if (lkb->lkb_wait_type != DLM_MSG_UNLOCK) {
490962306a36Sopenharmony_ci			log_debug(ls, "waiter %x remote %x msg %d r_nodeid %d "
491062306a36Sopenharmony_ci				  "lkb_nodeid %d wait_nodeid %d dir_nodeid %d",
491162306a36Sopenharmony_ci				  lkb->lkb_id,
491262306a36Sopenharmony_ci				  lkb->lkb_remid,
491362306a36Sopenharmony_ci				  lkb->lkb_wait_type,
491462306a36Sopenharmony_ci				  lkb->lkb_resource->res_nodeid,
491562306a36Sopenharmony_ci				  lkb->lkb_nodeid,
491662306a36Sopenharmony_ci				  lkb->lkb_wait_nodeid,
491762306a36Sopenharmony_ci				  dir_nodeid);
491862306a36Sopenharmony_ci		}
491962306a36Sopenharmony_ci
492062306a36Sopenharmony_ci		/* all outstanding lookups, regardless of destination  will be
492162306a36Sopenharmony_ci		   resent after recovery is done */
492262306a36Sopenharmony_ci
492362306a36Sopenharmony_ci		if (lkb->lkb_wait_type == DLM_MSG_LOOKUP) {
492462306a36Sopenharmony_ci			set_bit(DLM_IFL_RESEND_BIT, &lkb->lkb_iflags);
492562306a36Sopenharmony_ci			continue;
492662306a36Sopenharmony_ci		}
492762306a36Sopenharmony_ci
492862306a36Sopenharmony_ci		if (!waiter_needs_recovery(ls, lkb, dir_nodeid))
492962306a36Sopenharmony_ci			continue;
493062306a36Sopenharmony_ci
493162306a36Sopenharmony_ci		wait_type = lkb->lkb_wait_type;
493262306a36Sopenharmony_ci		local_unlock_result = -DLM_EUNLOCK;
493362306a36Sopenharmony_ci		local_cancel_result = -DLM_ECANCEL;
493462306a36Sopenharmony_ci
493562306a36Sopenharmony_ci		/* Main reply may have been received leaving a zero wait_type,
493662306a36Sopenharmony_ci		   but a reply for the overlapping op may not have been
493762306a36Sopenharmony_ci		   received.  In that case we need to fake the appropriate
493862306a36Sopenharmony_ci		   reply for the overlap op. */
493962306a36Sopenharmony_ci
494062306a36Sopenharmony_ci		if (!wait_type) {
494162306a36Sopenharmony_ci			if (is_overlap_cancel(lkb)) {
494262306a36Sopenharmony_ci				wait_type = DLM_MSG_CANCEL;
494362306a36Sopenharmony_ci				if (lkb->lkb_grmode == DLM_LOCK_IV)
494462306a36Sopenharmony_ci					local_cancel_result = 0;
494562306a36Sopenharmony_ci			}
494662306a36Sopenharmony_ci			if (is_overlap_unlock(lkb)) {
494762306a36Sopenharmony_ci				wait_type = DLM_MSG_UNLOCK;
494862306a36Sopenharmony_ci				if (lkb->lkb_grmode == DLM_LOCK_IV)
494962306a36Sopenharmony_ci					local_unlock_result = -ENOENT;
495062306a36Sopenharmony_ci			}
495162306a36Sopenharmony_ci
495262306a36Sopenharmony_ci			log_debug(ls, "rwpre overlap %x %x %d %d %d",
495362306a36Sopenharmony_ci				  lkb->lkb_id, dlm_iflags_val(lkb), wait_type,
495462306a36Sopenharmony_ci				  local_cancel_result, local_unlock_result);
495562306a36Sopenharmony_ci		}
495662306a36Sopenharmony_ci
495762306a36Sopenharmony_ci		switch (wait_type) {
495862306a36Sopenharmony_ci
495962306a36Sopenharmony_ci		case DLM_MSG_REQUEST:
496062306a36Sopenharmony_ci			set_bit(DLM_IFL_RESEND_BIT, &lkb->lkb_iflags);
496162306a36Sopenharmony_ci			break;
496262306a36Sopenharmony_ci
496362306a36Sopenharmony_ci		case DLM_MSG_CONVERT:
496462306a36Sopenharmony_ci			recover_convert_waiter(ls, lkb, ms_local);
496562306a36Sopenharmony_ci			break;
496662306a36Sopenharmony_ci
496762306a36Sopenharmony_ci		case DLM_MSG_UNLOCK:
496862306a36Sopenharmony_ci			hold_lkb(lkb);
496962306a36Sopenharmony_ci			memset(ms_local, 0, sizeof(struct dlm_message));
497062306a36Sopenharmony_ci			ms_local->m_type = cpu_to_le32(DLM_MSG_UNLOCK_REPLY);
497162306a36Sopenharmony_ci			ms_local->m_result = cpu_to_le32(to_dlm_errno(local_unlock_result));
497262306a36Sopenharmony_ci			ms_local->m_header.h_nodeid = cpu_to_le32(lkb->lkb_nodeid);
497362306a36Sopenharmony_ci			_receive_unlock_reply(lkb, ms_local, true);
497462306a36Sopenharmony_ci			dlm_put_lkb(lkb);
497562306a36Sopenharmony_ci			break;
497662306a36Sopenharmony_ci
497762306a36Sopenharmony_ci		case DLM_MSG_CANCEL:
497862306a36Sopenharmony_ci			hold_lkb(lkb);
497962306a36Sopenharmony_ci			memset(ms_local, 0, sizeof(struct dlm_message));
498062306a36Sopenharmony_ci			ms_local->m_type = cpu_to_le32(DLM_MSG_CANCEL_REPLY);
498162306a36Sopenharmony_ci			ms_local->m_result = cpu_to_le32(to_dlm_errno(local_cancel_result));
498262306a36Sopenharmony_ci			ms_local->m_header.h_nodeid = cpu_to_le32(lkb->lkb_nodeid);
498362306a36Sopenharmony_ci			_receive_cancel_reply(lkb, ms_local, true);
498462306a36Sopenharmony_ci			dlm_put_lkb(lkb);
498562306a36Sopenharmony_ci			break;
498662306a36Sopenharmony_ci
498762306a36Sopenharmony_ci		default:
498862306a36Sopenharmony_ci			log_error(ls, "invalid lkb wait_type %d %d",
498962306a36Sopenharmony_ci				  lkb->lkb_wait_type, wait_type);
499062306a36Sopenharmony_ci		}
499162306a36Sopenharmony_ci		schedule();
499262306a36Sopenharmony_ci	}
499362306a36Sopenharmony_ci	mutex_unlock(&ls->ls_waiters_mutex);
499462306a36Sopenharmony_ci	kfree(ms_local);
499562306a36Sopenharmony_ci}
499662306a36Sopenharmony_ci
499762306a36Sopenharmony_cistatic struct dlm_lkb *find_resend_waiter(struct dlm_ls *ls)
499862306a36Sopenharmony_ci{
499962306a36Sopenharmony_ci	struct dlm_lkb *lkb = NULL, *iter;
500062306a36Sopenharmony_ci
500162306a36Sopenharmony_ci	mutex_lock(&ls->ls_waiters_mutex);
500262306a36Sopenharmony_ci	list_for_each_entry(iter, &ls->ls_waiters, lkb_wait_reply) {
500362306a36Sopenharmony_ci		if (test_bit(DLM_IFL_RESEND_BIT, &iter->lkb_iflags)) {
500462306a36Sopenharmony_ci			hold_lkb(iter);
500562306a36Sopenharmony_ci			lkb = iter;
500662306a36Sopenharmony_ci			break;
500762306a36Sopenharmony_ci		}
500862306a36Sopenharmony_ci	}
500962306a36Sopenharmony_ci	mutex_unlock(&ls->ls_waiters_mutex);
501062306a36Sopenharmony_ci
501162306a36Sopenharmony_ci	return lkb;
501262306a36Sopenharmony_ci}
501362306a36Sopenharmony_ci
501462306a36Sopenharmony_ci/* Deal with lookups and lkb's marked RESEND from _pre.  We may now be the
501562306a36Sopenharmony_ci   master or dir-node for r.  Processing the lkb may result in it being placed
501662306a36Sopenharmony_ci   back on waiters. */
501762306a36Sopenharmony_ci
501862306a36Sopenharmony_ci/* We do this after normal locking has been enabled and any saved messages
501962306a36Sopenharmony_ci   (in requestqueue) have been processed.  We should be confident that at
502062306a36Sopenharmony_ci   this point we won't get or process a reply to any of these waiting
502162306a36Sopenharmony_ci   operations.  But, new ops may be coming in on the rsbs/locks here from
502262306a36Sopenharmony_ci   userspace or remotely. */
502362306a36Sopenharmony_ci
502462306a36Sopenharmony_ci/* there may have been an overlap unlock/cancel prior to recovery or after
502562306a36Sopenharmony_ci   recovery.  if before, the lkb may still have a pos wait_count; if after, the
502662306a36Sopenharmony_ci   overlap flag would just have been set and nothing new sent.  we can be
502762306a36Sopenharmony_ci   confident here than any replies to either the initial op or overlap ops
502862306a36Sopenharmony_ci   prior to recovery have been received. */
502962306a36Sopenharmony_ci
503062306a36Sopenharmony_ciint dlm_recover_waiters_post(struct dlm_ls *ls)
503162306a36Sopenharmony_ci{
503262306a36Sopenharmony_ci	struct dlm_lkb *lkb;
503362306a36Sopenharmony_ci	struct dlm_rsb *r;
503462306a36Sopenharmony_ci	int error = 0, mstype, err, oc, ou;
503562306a36Sopenharmony_ci
503662306a36Sopenharmony_ci	while (1) {
503762306a36Sopenharmony_ci		if (dlm_locking_stopped(ls)) {
503862306a36Sopenharmony_ci			log_debug(ls, "recover_waiters_post aborted");
503962306a36Sopenharmony_ci			error = -EINTR;
504062306a36Sopenharmony_ci			break;
504162306a36Sopenharmony_ci		}
504262306a36Sopenharmony_ci
504362306a36Sopenharmony_ci		lkb = find_resend_waiter(ls);
504462306a36Sopenharmony_ci		if (!lkb)
504562306a36Sopenharmony_ci			break;
504662306a36Sopenharmony_ci
504762306a36Sopenharmony_ci		r = lkb->lkb_resource;
504862306a36Sopenharmony_ci		hold_rsb(r);
504962306a36Sopenharmony_ci		lock_rsb(r);
505062306a36Sopenharmony_ci
505162306a36Sopenharmony_ci		mstype = lkb->lkb_wait_type;
505262306a36Sopenharmony_ci		oc = test_and_clear_bit(DLM_IFL_OVERLAP_CANCEL_BIT,
505362306a36Sopenharmony_ci					&lkb->lkb_iflags);
505462306a36Sopenharmony_ci		ou = test_and_clear_bit(DLM_IFL_OVERLAP_UNLOCK_BIT,
505562306a36Sopenharmony_ci					&lkb->lkb_iflags);
505662306a36Sopenharmony_ci		err = 0;
505762306a36Sopenharmony_ci
505862306a36Sopenharmony_ci		log_debug(ls, "waiter %x remote %x msg %d r_nodeid %d "
505962306a36Sopenharmony_ci			  "lkb_nodeid %d wait_nodeid %d dir_nodeid %d "
506062306a36Sopenharmony_ci			  "overlap %d %d", lkb->lkb_id, lkb->lkb_remid, mstype,
506162306a36Sopenharmony_ci			  r->res_nodeid, lkb->lkb_nodeid, lkb->lkb_wait_nodeid,
506262306a36Sopenharmony_ci			  dlm_dir_nodeid(r), oc, ou);
506362306a36Sopenharmony_ci
506462306a36Sopenharmony_ci		/* At this point we assume that we won't get a reply to any
506562306a36Sopenharmony_ci		   previous op or overlap op on this lock.  First, do a big
506662306a36Sopenharmony_ci		   remove_from_waiters() for all previous ops. */
506762306a36Sopenharmony_ci
506862306a36Sopenharmony_ci		clear_bit(DLM_IFL_RESEND_BIT, &lkb->lkb_iflags);
506962306a36Sopenharmony_ci		lkb->lkb_wait_type = 0;
507062306a36Sopenharmony_ci		/* drop all wait_count references we still
507162306a36Sopenharmony_ci		 * hold a reference for this iteration.
507262306a36Sopenharmony_ci		 */
507362306a36Sopenharmony_ci		while (!atomic_dec_and_test(&lkb->lkb_wait_count))
507462306a36Sopenharmony_ci			unhold_lkb(lkb);
507562306a36Sopenharmony_ci
507662306a36Sopenharmony_ci		mutex_lock(&ls->ls_waiters_mutex);
507762306a36Sopenharmony_ci		list_del_init(&lkb->lkb_wait_reply);
507862306a36Sopenharmony_ci		mutex_unlock(&ls->ls_waiters_mutex);
507962306a36Sopenharmony_ci
508062306a36Sopenharmony_ci		if (oc || ou) {
508162306a36Sopenharmony_ci			/* do an unlock or cancel instead of resending */
508262306a36Sopenharmony_ci			switch (mstype) {
508362306a36Sopenharmony_ci			case DLM_MSG_LOOKUP:
508462306a36Sopenharmony_ci			case DLM_MSG_REQUEST:
508562306a36Sopenharmony_ci				queue_cast(r, lkb, ou ? -DLM_EUNLOCK :
508662306a36Sopenharmony_ci							-DLM_ECANCEL);
508762306a36Sopenharmony_ci				unhold_lkb(lkb); /* undoes create_lkb() */
508862306a36Sopenharmony_ci				break;
508962306a36Sopenharmony_ci			case DLM_MSG_CONVERT:
509062306a36Sopenharmony_ci				if (oc) {
509162306a36Sopenharmony_ci					queue_cast(r, lkb, -DLM_ECANCEL);
509262306a36Sopenharmony_ci				} else {
509362306a36Sopenharmony_ci					lkb->lkb_exflags |= DLM_LKF_FORCEUNLOCK;
509462306a36Sopenharmony_ci					_unlock_lock(r, lkb);
509562306a36Sopenharmony_ci				}
509662306a36Sopenharmony_ci				break;
509762306a36Sopenharmony_ci			default:
509862306a36Sopenharmony_ci				err = 1;
509962306a36Sopenharmony_ci			}
510062306a36Sopenharmony_ci		} else {
510162306a36Sopenharmony_ci			switch (mstype) {
510262306a36Sopenharmony_ci			case DLM_MSG_LOOKUP:
510362306a36Sopenharmony_ci			case DLM_MSG_REQUEST:
510462306a36Sopenharmony_ci				_request_lock(r, lkb);
510562306a36Sopenharmony_ci				if (is_master(r))
510662306a36Sopenharmony_ci					confirm_master(r, 0);
510762306a36Sopenharmony_ci				break;
510862306a36Sopenharmony_ci			case DLM_MSG_CONVERT:
510962306a36Sopenharmony_ci				_convert_lock(r, lkb);
511062306a36Sopenharmony_ci				break;
511162306a36Sopenharmony_ci			default:
511262306a36Sopenharmony_ci				err = 1;
511362306a36Sopenharmony_ci			}
511462306a36Sopenharmony_ci		}
511562306a36Sopenharmony_ci
511662306a36Sopenharmony_ci		if (err) {
511762306a36Sopenharmony_ci			log_error(ls, "waiter %x msg %d r_nodeid %d "
511862306a36Sopenharmony_ci				  "dir_nodeid %d overlap %d %d",
511962306a36Sopenharmony_ci				  lkb->lkb_id, mstype, r->res_nodeid,
512062306a36Sopenharmony_ci				  dlm_dir_nodeid(r), oc, ou);
512162306a36Sopenharmony_ci		}
512262306a36Sopenharmony_ci		unlock_rsb(r);
512362306a36Sopenharmony_ci		put_rsb(r);
512462306a36Sopenharmony_ci		dlm_put_lkb(lkb);
512562306a36Sopenharmony_ci	}
512662306a36Sopenharmony_ci
512762306a36Sopenharmony_ci	return error;
512862306a36Sopenharmony_ci}
512962306a36Sopenharmony_ci
513062306a36Sopenharmony_cistatic void purge_mstcpy_list(struct dlm_ls *ls, struct dlm_rsb *r,
513162306a36Sopenharmony_ci			      struct list_head *list)
513262306a36Sopenharmony_ci{
513362306a36Sopenharmony_ci	struct dlm_lkb *lkb, *safe;
513462306a36Sopenharmony_ci
513562306a36Sopenharmony_ci	list_for_each_entry_safe(lkb, safe, list, lkb_statequeue) {
513662306a36Sopenharmony_ci		if (!is_master_copy(lkb))
513762306a36Sopenharmony_ci			continue;
513862306a36Sopenharmony_ci
513962306a36Sopenharmony_ci		/* don't purge lkbs we've added in recover_master_copy for
514062306a36Sopenharmony_ci		   the current recovery seq */
514162306a36Sopenharmony_ci
514262306a36Sopenharmony_ci		if (lkb->lkb_recover_seq == ls->ls_recover_seq)
514362306a36Sopenharmony_ci			continue;
514462306a36Sopenharmony_ci
514562306a36Sopenharmony_ci		del_lkb(r, lkb);
514662306a36Sopenharmony_ci
514762306a36Sopenharmony_ci		/* this put should free the lkb */
514862306a36Sopenharmony_ci		if (!dlm_put_lkb(lkb))
514962306a36Sopenharmony_ci			log_error(ls, "purged mstcpy lkb not released");
515062306a36Sopenharmony_ci	}
515162306a36Sopenharmony_ci}
515262306a36Sopenharmony_ci
515362306a36Sopenharmony_civoid dlm_purge_mstcpy_locks(struct dlm_rsb *r)
515462306a36Sopenharmony_ci{
515562306a36Sopenharmony_ci	struct dlm_ls *ls = r->res_ls;
515662306a36Sopenharmony_ci
515762306a36Sopenharmony_ci	purge_mstcpy_list(ls, r, &r->res_grantqueue);
515862306a36Sopenharmony_ci	purge_mstcpy_list(ls, r, &r->res_convertqueue);
515962306a36Sopenharmony_ci	purge_mstcpy_list(ls, r, &r->res_waitqueue);
516062306a36Sopenharmony_ci}
516162306a36Sopenharmony_ci
516262306a36Sopenharmony_cistatic void purge_dead_list(struct dlm_ls *ls, struct dlm_rsb *r,
516362306a36Sopenharmony_ci			    struct list_head *list,
516462306a36Sopenharmony_ci			    int nodeid_gone, unsigned int *count)
516562306a36Sopenharmony_ci{
516662306a36Sopenharmony_ci	struct dlm_lkb *lkb, *safe;
516762306a36Sopenharmony_ci
516862306a36Sopenharmony_ci	list_for_each_entry_safe(lkb, safe, list, lkb_statequeue) {
516962306a36Sopenharmony_ci		if (!is_master_copy(lkb))
517062306a36Sopenharmony_ci			continue;
517162306a36Sopenharmony_ci
517262306a36Sopenharmony_ci		if ((lkb->lkb_nodeid == nodeid_gone) ||
517362306a36Sopenharmony_ci		    dlm_is_removed(ls, lkb->lkb_nodeid)) {
517462306a36Sopenharmony_ci
517562306a36Sopenharmony_ci			/* tell recover_lvb to invalidate the lvb
517662306a36Sopenharmony_ci			   because a node holding EX/PW failed */
517762306a36Sopenharmony_ci			if ((lkb->lkb_exflags & DLM_LKF_VALBLK) &&
517862306a36Sopenharmony_ci			    (lkb->lkb_grmode >= DLM_LOCK_PW)) {
517962306a36Sopenharmony_ci				rsb_set_flag(r, RSB_RECOVER_LVB_INVAL);
518062306a36Sopenharmony_ci			}
518162306a36Sopenharmony_ci
518262306a36Sopenharmony_ci			del_lkb(r, lkb);
518362306a36Sopenharmony_ci
518462306a36Sopenharmony_ci			/* this put should free the lkb */
518562306a36Sopenharmony_ci			if (!dlm_put_lkb(lkb))
518662306a36Sopenharmony_ci				log_error(ls, "purged dead lkb not released");
518762306a36Sopenharmony_ci
518862306a36Sopenharmony_ci			rsb_set_flag(r, RSB_RECOVER_GRANT);
518962306a36Sopenharmony_ci
519062306a36Sopenharmony_ci			(*count)++;
519162306a36Sopenharmony_ci		}
519262306a36Sopenharmony_ci	}
519362306a36Sopenharmony_ci}
519462306a36Sopenharmony_ci
519562306a36Sopenharmony_ci/* Get rid of locks held by nodes that are gone. */
519662306a36Sopenharmony_ci
519762306a36Sopenharmony_civoid dlm_recover_purge(struct dlm_ls *ls)
519862306a36Sopenharmony_ci{
519962306a36Sopenharmony_ci	struct dlm_rsb *r;
520062306a36Sopenharmony_ci	struct dlm_member *memb;
520162306a36Sopenharmony_ci	int nodes_count = 0;
520262306a36Sopenharmony_ci	int nodeid_gone = 0;
520362306a36Sopenharmony_ci	unsigned int lkb_count = 0;
520462306a36Sopenharmony_ci
520562306a36Sopenharmony_ci	/* cache one removed nodeid to optimize the common
520662306a36Sopenharmony_ci	   case of a single node removed */
520762306a36Sopenharmony_ci
520862306a36Sopenharmony_ci	list_for_each_entry(memb, &ls->ls_nodes_gone, list) {
520962306a36Sopenharmony_ci		nodes_count++;
521062306a36Sopenharmony_ci		nodeid_gone = memb->nodeid;
521162306a36Sopenharmony_ci	}
521262306a36Sopenharmony_ci
521362306a36Sopenharmony_ci	if (!nodes_count)
521462306a36Sopenharmony_ci		return;
521562306a36Sopenharmony_ci
521662306a36Sopenharmony_ci	down_write(&ls->ls_root_sem);
521762306a36Sopenharmony_ci	list_for_each_entry(r, &ls->ls_root_list, res_root_list) {
521862306a36Sopenharmony_ci		hold_rsb(r);
521962306a36Sopenharmony_ci		lock_rsb(r);
522062306a36Sopenharmony_ci		if (is_master(r)) {
522162306a36Sopenharmony_ci			purge_dead_list(ls, r, &r->res_grantqueue,
522262306a36Sopenharmony_ci					nodeid_gone, &lkb_count);
522362306a36Sopenharmony_ci			purge_dead_list(ls, r, &r->res_convertqueue,
522462306a36Sopenharmony_ci					nodeid_gone, &lkb_count);
522562306a36Sopenharmony_ci			purge_dead_list(ls, r, &r->res_waitqueue,
522662306a36Sopenharmony_ci					nodeid_gone, &lkb_count);
522762306a36Sopenharmony_ci		}
522862306a36Sopenharmony_ci		unlock_rsb(r);
522962306a36Sopenharmony_ci		unhold_rsb(r);
523062306a36Sopenharmony_ci		cond_resched();
523162306a36Sopenharmony_ci	}
523262306a36Sopenharmony_ci	up_write(&ls->ls_root_sem);
523362306a36Sopenharmony_ci
523462306a36Sopenharmony_ci	if (lkb_count)
523562306a36Sopenharmony_ci		log_rinfo(ls, "dlm_recover_purge %u locks for %u nodes",
523662306a36Sopenharmony_ci			  lkb_count, nodes_count);
523762306a36Sopenharmony_ci}
523862306a36Sopenharmony_ci
523962306a36Sopenharmony_cistatic struct dlm_rsb *find_grant_rsb(struct dlm_ls *ls, int bucket)
524062306a36Sopenharmony_ci{
524162306a36Sopenharmony_ci	struct rb_node *n;
524262306a36Sopenharmony_ci	struct dlm_rsb *r;
524362306a36Sopenharmony_ci
524462306a36Sopenharmony_ci	spin_lock(&ls->ls_rsbtbl[bucket].lock);
524562306a36Sopenharmony_ci	for (n = rb_first(&ls->ls_rsbtbl[bucket].keep); n; n = rb_next(n)) {
524662306a36Sopenharmony_ci		r = rb_entry(n, struct dlm_rsb, res_hashnode);
524762306a36Sopenharmony_ci
524862306a36Sopenharmony_ci		if (!rsb_flag(r, RSB_RECOVER_GRANT))
524962306a36Sopenharmony_ci			continue;
525062306a36Sopenharmony_ci		if (!is_master(r)) {
525162306a36Sopenharmony_ci			rsb_clear_flag(r, RSB_RECOVER_GRANT);
525262306a36Sopenharmony_ci			continue;
525362306a36Sopenharmony_ci		}
525462306a36Sopenharmony_ci		hold_rsb(r);
525562306a36Sopenharmony_ci		spin_unlock(&ls->ls_rsbtbl[bucket].lock);
525662306a36Sopenharmony_ci		return r;
525762306a36Sopenharmony_ci	}
525862306a36Sopenharmony_ci	spin_unlock(&ls->ls_rsbtbl[bucket].lock);
525962306a36Sopenharmony_ci	return NULL;
526062306a36Sopenharmony_ci}
526162306a36Sopenharmony_ci
526262306a36Sopenharmony_ci/*
526362306a36Sopenharmony_ci * Attempt to grant locks on resources that we are the master of.
526462306a36Sopenharmony_ci * Locks may have become grantable during recovery because locks
526562306a36Sopenharmony_ci * from departed nodes have been purged (or not rebuilt), allowing
526662306a36Sopenharmony_ci * previously blocked locks to now be granted.  The subset of rsb's
526762306a36Sopenharmony_ci * we are interested in are those with lkb's on either the convert or
526862306a36Sopenharmony_ci * waiting queues.
526962306a36Sopenharmony_ci *
527062306a36Sopenharmony_ci * Simplest would be to go through each master rsb and check for non-empty
527162306a36Sopenharmony_ci * convert or waiting queues, and attempt to grant on those rsbs.
527262306a36Sopenharmony_ci * Checking the queues requires lock_rsb, though, for which we'd need
527362306a36Sopenharmony_ci * to release the rsbtbl lock.  This would make iterating through all
527462306a36Sopenharmony_ci * rsb's very inefficient.  So, we rely on earlier recovery routines
527562306a36Sopenharmony_ci * to set RECOVER_GRANT on any rsb's that we should attempt to grant
527662306a36Sopenharmony_ci * locks for.
527762306a36Sopenharmony_ci */
527862306a36Sopenharmony_ci
527962306a36Sopenharmony_civoid dlm_recover_grant(struct dlm_ls *ls)
528062306a36Sopenharmony_ci{
528162306a36Sopenharmony_ci	struct dlm_rsb *r;
528262306a36Sopenharmony_ci	int bucket = 0;
528362306a36Sopenharmony_ci	unsigned int count = 0;
528462306a36Sopenharmony_ci	unsigned int rsb_count = 0;
528562306a36Sopenharmony_ci	unsigned int lkb_count = 0;
528662306a36Sopenharmony_ci
528762306a36Sopenharmony_ci	while (1) {
528862306a36Sopenharmony_ci		r = find_grant_rsb(ls, bucket);
528962306a36Sopenharmony_ci		if (!r) {
529062306a36Sopenharmony_ci			if (bucket == ls->ls_rsbtbl_size - 1)
529162306a36Sopenharmony_ci				break;
529262306a36Sopenharmony_ci			bucket++;
529362306a36Sopenharmony_ci			continue;
529462306a36Sopenharmony_ci		}
529562306a36Sopenharmony_ci		rsb_count++;
529662306a36Sopenharmony_ci		count = 0;
529762306a36Sopenharmony_ci		lock_rsb(r);
529862306a36Sopenharmony_ci		/* the RECOVER_GRANT flag is checked in the grant path */
529962306a36Sopenharmony_ci		grant_pending_locks(r, &count);
530062306a36Sopenharmony_ci		rsb_clear_flag(r, RSB_RECOVER_GRANT);
530162306a36Sopenharmony_ci		lkb_count += count;
530262306a36Sopenharmony_ci		confirm_master(r, 0);
530362306a36Sopenharmony_ci		unlock_rsb(r);
530462306a36Sopenharmony_ci		put_rsb(r);
530562306a36Sopenharmony_ci		cond_resched();
530662306a36Sopenharmony_ci	}
530762306a36Sopenharmony_ci
530862306a36Sopenharmony_ci	if (lkb_count)
530962306a36Sopenharmony_ci		log_rinfo(ls, "dlm_recover_grant %u locks on %u resources",
531062306a36Sopenharmony_ci			  lkb_count, rsb_count);
531162306a36Sopenharmony_ci}
531262306a36Sopenharmony_ci
531362306a36Sopenharmony_cistatic struct dlm_lkb *search_remid_list(struct list_head *head, int nodeid,
531462306a36Sopenharmony_ci					 uint32_t remid)
531562306a36Sopenharmony_ci{
531662306a36Sopenharmony_ci	struct dlm_lkb *lkb;
531762306a36Sopenharmony_ci
531862306a36Sopenharmony_ci	list_for_each_entry(lkb, head, lkb_statequeue) {
531962306a36Sopenharmony_ci		if (lkb->lkb_nodeid == nodeid && lkb->lkb_remid == remid)
532062306a36Sopenharmony_ci			return lkb;
532162306a36Sopenharmony_ci	}
532262306a36Sopenharmony_ci	return NULL;
532362306a36Sopenharmony_ci}
532462306a36Sopenharmony_ci
532562306a36Sopenharmony_cistatic struct dlm_lkb *search_remid(struct dlm_rsb *r, int nodeid,
532662306a36Sopenharmony_ci				    uint32_t remid)
532762306a36Sopenharmony_ci{
532862306a36Sopenharmony_ci	struct dlm_lkb *lkb;
532962306a36Sopenharmony_ci
533062306a36Sopenharmony_ci	lkb = search_remid_list(&r->res_grantqueue, nodeid, remid);
533162306a36Sopenharmony_ci	if (lkb)
533262306a36Sopenharmony_ci		return lkb;
533362306a36Sopenharmony_ci	lkb = search_remid_list(&r->res_convertqueue, nodeid, remid);
533462306a36Sopenharmony_ci	if (lkb)
533562306a36Sopenharmony_ci		return lkb;
533662306a36Sopenharmony_ci	lkb = search_remid_list(&r->res_waitqueue, nodeid, remid);
533762306a36Sopenharmony_ci	if (lkb)
533862306a36Sopenharmony_ci		return lkb;
533962306a36Sopenharmony_ci	return NULL;
534062306a36Sopenharmony_ci}
534162306a36Sopenharmony_ci
534262306a36Sopenharmony_ci/* needs at least dlm_rcom + rcom_lock */
534362306a36Sopenharmony_cistatic int receive_rcom_lock_args(struct dlm_ls *ls, struct dlm_lkb *lkb,
534462306a36Sopenharmony_ci				  struct dlm_rsb *r, const struct dlm_rcom *rc)
534562306a36Sopenharmony_ci{
534662306a36Sopenharmony_ci	struct rcom_lock *rl = (struct rcom_lock *) rc->rc_buf;
534762306a36Sopenharmony_ci
534862306a36Sopenharmony_ci	lkb->lkb_nodeid = le32_to_cpu(rc->rc_header.h_nodeid);
534962306a36Sopenharmony_ci	lkb->lkb_ownpid = le32_to_cpu(rl->rl_ownpid);
535062306a36Sopenharmony_ci	lkb->lkb_remid = le32_to_cpu(rl->rl_lkid);
535162306a36Sopenharmony_ci	lkb->lkb_exflags = le32_to_cpu(rl->rl_exflags);
535262306a36Sopenharmony_ci	dlm_set_dflags_val(lkb, le32_to_cpu(rl->rl_flags));
535362306a36Sopenharmony_ci	set_bit(DLM_IFL_MSTCPY_BIT, &lkb->lkb_iflags);
535462306a36Sopenharmony_ci	lkb->lkb_lvbseq = le32_to_cpu(rl->rl_lvbseq);
535562306a36Sopenharmony_ci	lkb->lkb_rqmode = rl->rl_rqmode;
535662306a36Sopenharmony_ci	lkb->lkb_grmode = rl->rl_grmode;
535762306a36Sopenharmony_ci	/* don't set lkb_status because add_lkb wants to itself */
535862306a36Sopenharmony_ci
535962306a36Sopenharmony_ci	lkb->lkb_bastfn = (rl->rl_asts & DLM_CB_BAST) ? &fake_bastfn : NULL;
536062306a36Sopenharmony_ci	lkb->lkb_astfn = (rl->rl_asts & DLM_CB_CAST) ? &fake_astfn : NULL;
536162306a36Sopenharmony_ci
536262306a36Sopenharmony_ci	if (lkb->lkb_exflags & DLM_LKF_VALBLK) {
536362306a36Sopenharmony_ci		int lvblen = le16_to_cpu(rc->rc_header.h_length) -
536462306a36Sopenharmony_ci			sizeof(struct dlm_rcom) - sizeof(struct rcom_lock);
536562306a36Sopenharmony_ci		if (lvblen > ls->ls_lvblen)
536662306a36Sopenharmony_ci			return -EINVAL;
536762306a36Sopenharmony_ci		lkb->lkb_lvbptr = dlm_allocate_lvb(ls);
536862306a36Sopenharmony_ci		if (!lkb->lkb_lvbptr)
536962306a36Sopenharmony_ci			return -ENOMEM;
537062306a36Sopenharmony_ci		memcpy(lkb->lkb_lvbptr, rl->rl_lvb, lvblen);
537162306a36Sopenharmony_ci	}
537262306a36Sopenharmony_ci
537362306a36Sopenharmony_ci	/* Conversions between PR and CW (middle modes) need special handling.
537462306a36Sopenharmony_ci	   The real granted mode of these converting locks cannot be determined
537562306a36Sopenharmony_ci	   until all locks have been rebuilt on the rsb (recover_conversion) */
537662306a36Sopenharmony_ci
537762306a36Sopenharmony_ci	if (rl->rl_wait_type == cpu_to_le16(DLM_MSG_CONVERT) &&
537862306a36Sopenharmony_ci	    middle_conversion(lkb)) {
537962306a36Sopenharmony_ci		rl->rl_status = DLM_LKSTS_CONVERT;
538062306a36Sopenharmony_ci		lkb->lkb_grmode = DLM_LOCK_IV;
538162306a36Sopenharmony_ci		rsb_set_flag(r, RSB_RECOVER_CONVERT);
538262306a36Sopenharmony_ci	}
538362306a36Sopenharmony_ci
538462306a36Sopenharmony_ci	return 0;
538562306a36Sopenharmony_ci}
538662306a36Sopenharmony_ci
538762306a36Sopenharmony_ci/* This lkb may have been recovered in a previous aborted recovery so we need
538862306a36Sopenharmony_ci   to check if the rsb already has an lkb with the given remote nodeid/lkid.
538962306a36Sopenharmony_ci   If so we just send back a standard reply.  If not, we create a new lkb with
539062306a36Sopenharmony_ci   the given values and send back our lkid.  We send back our lkid by sending
539162306a36Sopenharmony_ci   back the rcom_lock struct we got but with the remid field filled in. */
539262306a36Sopenharmony_ci
539362306a36Sopenharmony_ci/* needs at least dlm_rcom + rcom_lock */
539462306a36Sopenharmony_ciint dlm_recover_master_copy(struct dlm_ls *ls, const struct dlm_rcom *rc,
539562306a36Sopenharmony_ci			    __le32 *rl_remid, __le32 *rl_result)
539662306a36Sopenharmony_ci{
539762306a36Sopenharmony_ci	struct rcom_lock *rl = (struct rcom_lock *) rc->rc_buf;
539862306a36Sopenharmony_ci	struct dlm_rsb *r;
539962306a36Sopenharmony_ci	struct dlm_lkb *lkb;
540062306a36Sopenharmony_ci	uint32_t remid = 0;
540162306a36Sopenharmony_ci	int from_nodeid = le32_to_cpu(rc->rc_header.h_nodeid);
540262306a36Sopenharmony_ci	int error;
540362306a36Sopenharmony_ci
540462306a36Sopenharmony_ci	/* init rl_remid with rcom lock rl_remid */
540562306a36Sopenharmony_ci	*rl_remid = rl->rl_remid;
540662306a36Sopenharmony_ci
540762306a36Sopenharmony_ci	if (rl->rl_parent_lkid) {
540862306a36Sopenharmony_ci		error = -EOPNOTSUPP;
540962306a36Sopenharmony_ci		goto out;
541062306a36Sopenharmony_ci	}
541162306a36Sopenharmony_ci
541262306a36Sopenharmony_ci	remid = le32_to_cpu(rl->rl_lkid);
541362306a36Sopenharmony_ci
541462306a36Sopenharmony_ci	/* In general we expect the rsb returned to be R_MASTER, but we don't
541562306a36Sopenharmony_ci	   have to require it.  Recovery of masters on one node can overlap
541662306a36Sopenharmony_ci	   recovery of locks on another node, so one node can send us MSTCPY
541762306a36Sopenharmony_ci	   locks before we've made ourselves master of this rsb.  We can still
541862306a36Sopenharmony_ci	   add new MSTCPY locks that we receive here without any harm; when
541962306a36Sopenharmony_ci	   we make ourselves master, dlm_recover_masters() won't touch the
542062306a36Sopenharmony_ci	   MSTCPY locks we've received early. */
542162306a36Sopenharmony_ci
542262306a36Sopenharmony_ci	error = find_rsb(ls, rl->rl_name, le16_to_cpu(rl->rl_namelen),
542362306a36Sopenharmony_ci			 from_nodeid, R_RECEIVE_RECOVER, &r);
542462306a36Sopenharmony_ci	if (error)
542562306a36Sopenharmony_ci		goto out;
542662306a36Sopenharmony_ci
542762306a36Sopenharmony_ci	lock_rsb(r);
542862306a36Sopenharmony_ci
542962306a36Sopenharmony_ci	if (dlm_no_directory(ls) && (dlm_dir_nodeid(r) != dlm_our_nodeid())) {
543062306a36Sopenharmony_ci		log_error(ls, "dlm_recover_master_copy remote %d %x not dir",
543162306a36Sopenharmony_ci			  from_nodeid, remid);
543262306a36Sopenharmony_ci		error = -EBADR;
543362306a36Sopenharmony_ci		goto out_unlock;
543462306a36Sopenharmony_ci	}
543562306a36Sopenharmony_ci
543662306a36Sopenharmony_ci	lkb = search_remid(r, from_nodeid, remid);
543762306a36Sopenharmony_ci	if (lkb) {
543862306a36Sopenharmony_ci		error = -EEXIST;
543962306a36Sopenharmony_ci		goto out_remid;
544062306a36Sopenharmony_ci	}
544162306a36Sopenharmony_ci
544262306a36Sopenharmony_ci	error = create_lkb(ls, &lkb);
544362306a36Sopenharmony_ci	if (error)
544462306a36Sopenharmony_ci		goto out_unlock;
544562306a36Sopenharmony_ci
544662306a36Sopenharmony_ci	error = receive_rcom_lock_args(ls, lkb, r, rc);
544762306a36Sopenharmony_ci	if (error) {
544862306a36Sopenharmony_ci		__put_lkb(ls, lkb);
544962306a36Sopenharmony_ci		goto out_unlock;
545062306a36Sopenharmony_ci	}
545162306a36Sopenharmony_ci
545262306a36Sopenharmony_ci	attach_lkb(r, lkb);
545362306a36Sopenharmony_ci	add_lkb(r, lkb, rl->rl_status);
545462306a36Sopenharmony_ci	ls->ls_recover_locks_in++;
545562306a36Sopenharmony_ci
545662306a36Sopenharmony_ci	if (!list_empty(&r->res_waitqueue) || !list_empty(&r->res_convertqueue))
545762306a36Sopenharmony_ci		rsb_set_flag(r, RSB_RECOVER_GRANT);
545862306a36Sopenharmony_ci
545962306a36Sopenharmony_ci out_remid:
546062306a36Sopenharmony_ci	/* this is the new value returned to the lock holder for
546162306a36Sopenharmony_ci	   saving in its process-copy lkb */
546262306a36Sopenharmony_ci	*rl_remid = cpu_to_le32(lkb->lkb_id);
546362306a36Sopenharmony_ci
546462306a36Sopenharmony_ci	lkb->lkb_recover_seq = ls->ls_recover_seq;
546562306a36Sopenharmony_ci
546662306a36Sopenharmony_ci out_unlock:
546762306a36Sopenharmony_ci	unlock_rsb(r);
546862306a36Sopenharmony_ci	put_rsb(r);
546962306a36Sopenharmony_ci out:
547062306a36Sopenharmony_ci	if (error && error != -EEXIST)
547162306a36Sopenharmony_ci		log_rinfo(ls, "dlm_recover_master_copy remote %d %x error %d",
547262306a36Sopenharmony_ci			  from_nodeid, remid, error);
547362306a36Sopenharmony_ci	*rl_result = cpu_to_le32(error);
547462306a36Sopenharmony_ci	return error;
547562306a36Sopenharmony_ci}
547662306a36Sopenharmony_ci
547762306a36Sopenharmony_ci/* needs at least dlm_rcom + rcom_lock */
547862306a36Sopenharmony_ciint dlm_recover_process_copy(struct dlm_ls *ls, const struct dlm_rcom *rc,
547962306a36Sopenharmony_ci			     uint64_t seq)
548062306a36Sopenharmony_ci{
548162306a36Sopenharmony_ci	struct rcom_lock *rl = (struct rcom_lock *) rc->rc_buf;
548262306a36Sopenharmony_ci	struct dlm_rsb *r;
548362306a36Sopenharmony_ci	struct dlm_lkb *lkb;
548462306a36Sopenharmony_ci	uint32_t lkid, remid;
548562306a36Sopenharmony_ci	int error, result;
548662306a36Sopenharmony_ci
548762306a36Sopenharmony_ci	lkid = le32_to_cpu(rl->rl_lkid);
548862306a36Sopenharmony_ci	remid = le32_to_cpu(rl->rl_remid);
548962306a36Sopenharmony_ci	result = le32_to_cpu(rl->rl_result);
549062306a36Sopenharmony_ci
549162306a36Sopenharmony_ci	error = find_lkb(ls, lkid, &lkb);
549262306a36Sopenharmony_ci	if (error) {
549362306a36Sopenharmony_ci		log_error(ls, "dlm_recover_process_copy no %x remote %d %x %d",
549462306a36Sopenharmony_ci			  lkid, le32_to_cpu(rc->rc_header.h_nodeid), remid,
549562306a36Sopenharmony_ci			  result);
549662306a36Sopenharmony_ci		return error;
549762306a36Sopenharmony_ci	}
549862306a36Sopenharmony_ci
549962306a36Sopenharmony_ci	r = lkb->lkb_resource;
550062306a36Sopenharmony_ci	hold_rsb(r);
550162306a36Sopenharmony_ci	lock_rsb(r);
550262306a36Sopenharmony_ci
550362306a36Sopenharmony_ci	if (!is_process_copy(lkb)) {
550462306a36Sopenharmony_ci		log_error(ls, "dlm_recover_process_copy bad %x remote %d %x %d",
550562306a36Sopenharmony_ci			  lkid, le32_to_cpu(rc->rc_header.h_nodeid), remid,
550662306a36Sopenharmony_ci			  result);
550762306a36Sopenharmony_ci		dlm_dump_rsb(r);
550862306a36Sopenharmony_ci		unlock_rsb(r);
550962306a36Sopenharmony_ci		put_rsb(r);
551062306a36Sopenharmony_ci		dlm_put_lkb(lkb);
551162306a36Sopenharmony_ci		return -EINVAL;
551262306a36Sopenharmony_ci	}
551362306a36Sopenharmony_ci
551462306a36Sopenharmony_ci	switch (result) {
551562306a36Sopenharmony_ci	case -EBADR:
551662306a36Sopenharmony_ci		/* There's a chance the new master received our lock before
551762306a36Sopenharmony_ci		   dlm_recover_master_reply(), this wouldn't happen if we did
551862306a36Sopenharmony_ci		   a barrier between recover_masters and recover_locks. */
551962306a36Sopenharmony_ci
552062306a36Sopenharmony_ci		log_debug(ls, "dlm_recover_process_copy %x remote %d %x %d",
552162306a36Sopenharmony_ci			  lkid, le32_to_cpu(rc->rc_header.h_nodeid), remid,
552262306a36Sopenharmony_ci			  result);
552362306a36Sopenharmony_ci
552462306a36Sopenharmony_ci		dlm_send_rcom_lock(r, lkb, seq);
552562306a36Sopenharmony_ci		goto out;
552662306a36Sopenharmony_ci	case -EEXIST:
552762306a36Sopenharmony_ci	case 0:
552862306a36Sopenharmony_ci		lkb->lkb_remid = remid;
552962306a36Sopenharmony_ci		break;
553062306a36Sopenharmony_ci	default:
553162306a36Sopenharmony_ci		log_error(ls, "dlm_recover_process_copy %x remote %d %x %d unk",
553262306a36Sopenharmony_ci			  lkid, le32_to_cpu(rc->rc_header.h_nodeid), remid,
553362306a36Sopenharmony_ci			  result);
553462306a36Sopenharmony_ci	}
553562306a36Sopenharmony_ci
553662306a36Sopenharmony_ci	/* an ack for dlm_recover_locks() which waits for replies from
553762306a36Sopenharmony_ci	   all the locks it sends to new masters */
553862306a36Sopenharmony_ci	dlm_recovered_lock(r);
553962306a36Sopenharmony_ci out:
554062306a36Sopenharmony_ci	unlock_rsb(r);
554162306a36Sopenharmony_ci	put_rsb(r);
554262306a36Sopenharmony_ci	dlm_put_lkb(lkb);
554362306a36Sopenharmony_ci
554462306a36Sopenharmony_ci	return 0;
554562306a36Sopenharmony_ci}
554662306a36Sopenharmony_ci
554762306a36Sopenharmony_ciint dlm_user_request(struct dlm_ls *ls, struct dlm_user_args *ua,
554862306a36Sopenharmony_ci		     int mode, uint32_t flags, void *name, unsigned int namelen)
554962306a36Sopenharmony_ci{
555062306a36Sopenharmony_ci	struct dlm_lkb *lkb;
555162306a36Sopenharmony_ci	struct dlm_args args;
555262306a36Sopenharmony_ci	bool do_put = true;
555362306a36Sopenharmony_ci	int error;
555462306a36Sopenharmony_ci
555562306a36Sopenharmony_ci	dlm_lock_recovery(ls);
555662306a36Sopenharmony_ci
555762306a36Sopenharmony_ci	error = create_lkb(ls, &lkb);
555862306a36Sopenharmony_ci	if (error) {
555962306a36Sopenharmony_ci		kfree(ua);
556062306a36Sopenharmony_ci		goto out;
556162306a36Sopenharmony_ci	}
556262306a36Sopenharmony_ci
556362306a36Sopenharmony_ci	trace_dlm_lock_start(ls, lkb, name, namelen, mode, flags);
556462306a36Sopenharmony_ci
556562306a36Sopenharmony_ci	if (flags & DLM_LKF_VALBLK) {
556662306a36Sopenharmony_ci		ua->lksb.sb_lvbptr = kzalloc(DLM_USER_LVB_LEN, GFP_NOFS);
556762306a36Sopenharmony_ci		if (!ua->lksb.sb_lvbptr) {
556862306a36Sopenharmony_ci			kfree(ua);
556962306a36Sopenharmony_ci			error = -ENOMEM;
557062306a36Sopenharmony_ci			goto out_put;
557162306a36Sopenharmony_ci		}
557262306a36Sopenharmony_ci	}
557362306a36Sopenharmony_ci	error = set_lock_args(mode, &ua->lksb, flags, namelen, fake_astfn, ua,
557462306a36Sopenharmony_ci			      fake_bastfn, &args);
557562306a36Sopenharmony_ci	if (error) {
557662306a36Sopenharmony_ci		kfree(ua->lksb.sb_lvbptr);
557762306a36Sopenharmony_ci		ua->lksb.sb_lvbptr = NULL;
557862306a36Sopenharmony_ci		kfree(ua);
557962306a36Sopenharmony_ci		goto out_put;
558062306a36Sopenharmony_ci	}
558162306a36Sopenharmony_ci
558262306a36Sopenharmony_ci	/* After ua is attached to lkb it will be freed by dlm_free_lkb().
558362306a36Sopenharmony_ci	   When DLM_DFL_USER_BIT is set, the dlm knows that this is a userspace
558462306a36Sopenharmony_ci	   lock and that lkb_astparam is the dlm_user_args structure. */
558562306a36Sopenharmony_ci	set_bit(DLM_DFL_USER_BIT, &lkb->lkb_dflags);
558662306a36Sopenharmony_ci	error = request_lock(ls, lkb, name, namelen, &args);
558762306a36Sopenharmony_ci
558862306a36Sopenharmony_ci	switch (error) {
558962306a36Sopenharmony_ci	case 0:
559062306a36Sopenharmony_ci		break;
559162306a36Sopenharmony_ci	case -EINPROGRESS:
559262306a36Sopenharmony_ci		error = 0;
559362306a36Sopenharmony_ci		break;
559462306a36Sopenharmony_ci	case -EAGAIN:
559562306a36Sopenharmony_ci		error = 0;
559662306a36Sopenharmony_ci		fallthrough;
559762306a36Sopenharmony_ci	default:
559862306a36Sopenharmony_ci		goto out_put;
559962306a36Sopenharmony_ci	}
560062306a36Sopenharmony_ci
560162306a36Sopenharmony_ci	/* add this new lkb to the per-process list of locks */
560262306a36Sopenharmony_ci	spin_lock(&ua->proc->locks_spin);
560362306a36Sopenharmony_ci	hold_lkb(lkb);
560462306a36Sopenharmony_ci	list_add_tail(&lkb->lkb_ownqueue, &ua->proc->locks);
560562306a36Sopenharmony_ci	spin_unlock(&ua->proc->locks_spin);
560662306a36Sopenharmony_ci	do_put = false;
560762306a36Sopenharmony_ci out_put:
560862306a36Sopenharmony_ci	trace_dlm_lock_end(ls, lkb, name, namelen, mode, flags, error, false);
560962306a36Sopenharmony_ci	if (do_put)
561062306a36Sopenharmony_ci		__put_lkb(ls, lkb);
561162306a36Sopenharmony_ci out:
561262306a36Sopenharmony_ci	dlm_unlock_recovery(ls);
561362306a36Sopenharmony_ci	return error;
561462306a36Sopenharmony_ci}
561562306a36Sopenharmony_ci
561662306a36Sopenharmony_ciint dlm_user_convert(struct dlm_ls *ls, struct dlm_user_args *ua_tmp,
561762306a36Sopenharmony_ci		     int mode, uint32_t flags, uint32_t lkid, char *lvb_in)
561862306a36Sopenharmony_ci{
561962306a36Sopenharmony_ci	struct dlm_lkb *lkb;
562062306a36Sopenharmony_ci	struct dlm_args args;
562162306a36Sopenharmony_ci	struct dlm_user_args *ua;
562262306a36Sopenharmony_ci	int error;
562362306a36Sopenharmony_ci
562462306a36Sopenharmony_ci	dlm_lock_recovery(ls);
562562306a36Sopenharmony_ci
562662306a36Sopenharmony_ci	error = find_lkb(ls, lkid, &lkb);
562762306a36Sopenharmony_ci	if (error)
562862306a36Sopenharmony_ci		goto out;
562962306a36Sopenharmony_ci
563062306a36Sopenharmony_ci	trace_dlm_lock_start(ls, lkb, NULL, 0, mode, flags);
563162306a36Sopenharmony_ci
563262306a36Sopenharmony_ci	/* user can change the params on its lock when it converts it, or
563362306a36Sopenharmony_ci	   add an lvb that didn't exist before */
563462306a36Sopenharmony_ci
563562306a36Sopenharmony_ci	ua = lkb->lkb_ua;
563662306a36Sopenharmony_ci
563762306a36Sopenharmony_ci	if (flags & DLM_LKF_VALBLK && !ua->lksb.sb_lvbptr) {
563862306a36Sopenharmony_ci		ua->lksb.sb_lvbptr = kzalloc(DLM_USER_LVB_LEN, GFP_NOFS);
563962306a36Sopenharmony_ci		if (!ua->lksb.sb_lvbptr) {
564062306a36Sopenharmony_ci			error = -ENOMEM;
564162306a36Sopenharmony_ci			goto out_put;
564262306a36Sopenharmony_ci		}
564362306a36Sopenharmony_ci	}
564462306a36Sopenharmony_ci	if (lvb_in && ua->lksb.sb_lvbptr)
564562306a36Sopenharmony_ci		memcpy(ua->lksb.sb_lvbptr, lvb_in, DLM_USER_LVB_LEN);
564662306a36Sopenharmony_ci
564762306a36Sopenharmony_ci	ua->xid = ua_tmp->xid;
564862306a36Sopenharmony_ci	ua->castparam = ua_tmp->castparam;
564962306a36Sopenharmony_ci	ua->castaddr = ua_tmp->castaddr;
565062306a36Sopenharmony_ci	ua->bastparam = ua_tmp->bastparam;
565162306a36Sopenharmony_ci	ua->bastaddr = ua_tmp->bastaddr;
565262306a36Sopenharmony_ci	ua->user_lksb = ua_tmp->user_lksb;
565362306a36Sopenharmony_ci
565462306a36Sopenharmony_ci	error = set_lock_args(mode, &ua->lksb, flags, 0, fake_astfn, ua,
565562306a36Sopenharmony_ci			      fake_bastfn, &args);
565662306a36Sopenharmony_ci	if (error)
565762306a36Sopenharmony_ci		goto out_put;
565862306a36Sopenharmony_ci
565962306a36Sopenharmony_ci	error = convert_lock(ls, lkb, &args);
566062306a36Sopenharmony_ci
566162306a36Sopenharmony_ci	if (error == -EINPROGRESS || error == -EAGAIN || error == -EDEADLK)
566262306a36Sopenharmony_ci		error = 0;
566362306a36Sopenharmony_ci out_put:
566462306a36Sopenharmony_ci	trace_dlm_lock_end(ls, lkb, NULL, 0, mode, flags, error, false);
566562306a36Sopenharmony_ci	dlm_put_lkb(lkb);
566662306a36Sopenharmony_ci out:
566762306a36Sopenharmony_ci	dlm_unlock_recovery(ls);
566862306a36Sopenharmony_ci	kfree(ua_tmp);
566962306a36Sopenharmony_ci	return error;
567062306a36Sopenharmony_ci}
567162306a36Sopenharmony_ci
567262306a36Sopenharmony_ci/*
567362306a36Sopenharmony_ci * The caller asks for an orphan lock on a given resource with a given mode.
567462306a36Sopenharmony_ci * If a matching lock exists, it's moved to the owner's list of locks and
567562306a36Sopenharmony_ci * the lkid is returned.
567662306a36Sopenharmony_ci */
567762306a36Sopenharmony_ci
567862306a36Sopenharmony_ciint dlm_user_adopt_orphan(struct dlm_ls *ls, struct dlm_user_args *ua_tmp,
567962306a36Sopenharmony_ci		     int mode, uint32_t flags, void *name, unsigned int namelen,
568062306a36Sopenharmony_ci		     uint32_t *lkid)
568162306a36Sopenharmony_ci{
568262306a36Sopenharmony_ci	struct dlm_lkb *lkb = NULL, *iter;
568362306a36Sopenharmony_ci	struct dlm_user_args *ua;
568462306a36Sopenharmony_ci	int found_other_mode = 0;
568562306a36Sopenharmony_ci	int rv = 0;
568662306a36Sopenharmony_ci
568762306a36Sopenharmony_ci	mutex_lock(&ls->ls_orphans_mutex);
568862306a36Sopenharmony_ci	list_for_each_entry(iter, &ls->ls_orphans, lkb_ownqueue) {
568962306a36Sopenharmony_ci		if (iter->lkb_resource->res_length != namelen)
569062306a36Sopenharmony_ci			continue;
569162306a36Sopenharmony_ci		if (memcmp(iter->lkb_resource->res_name, name, namelen))
569262306a36Sopenharmony_ci			continue;
569362306a36Sopenharmony_ci		if (iter->lkb_grmode != mode) {
569462306a36Sopenharmony_ci			found_other_mode = 1;
569562306a36Sopenharmony_ci			continue;
569662306a36Sopenharmony_ci		}
569762306a36Sopenharmony_ci
569862306a36Sopenharmony_ci		lkb = iter;
569962306a36Sopenharmony_ci		list_del_init(&iter->lkb_ownqueue);
570062306a36Sopenharmony_ci		clear_bit(DLM_DFL_ORPHAN_BIT, &iter->lkb_dflags);
570162306a36Sopenharmony_ci		*lkid = iter->lkb_id;
570262306a36Sopenharmony_ci		break;
570362306a36Sopenharmony_ci	}
570462306a36Sopenharmony_ci	mutex_unlock(&ls->ls_orphans_mutex);
570562306a36Sopenharmony_ci
570662306a36Sopenharmony_ci	if (!lkb && found_other_mode) {
570762306a36Sopenharmony_ci		rv = -EAGAIN;
570862306a36Sopenharmony_ci		goto out;
570962306a36Sopenharmony_ci	}
571062306a36Sopenharmony_ci
571162306a36Sopenharmony_ci	if (!lkb) {
571262306a36Sopenharmony_ci		rv = -ENOENT;
571362306a36Sopenharmony_ci		goto out;
571462306a36Sopenharmony_ci	}
571562306a36Sopenharmony_ci
571662306a36Sopenharmony_ci	lkb->lkb_exflags = flags;
571762306a36Sopenharmony_ci	lkb->lkb_ownpid = (int) current->pid;
571862306a36Sopenharmony_ci
571962306a36Sopenharmony_ci	ua = lkb->lkb_ua;
572062306a36Sopenharmony_ci
572162306a36Sopenharmony_ci	ua->proc = ua_tmp->proc;
572262306a36Sopenharmony_ci	ua->xid = ua_tmp->xid;
572362306a36Sopenharmony_ci	ua->castparam = ua_tmp->castparam;
572462306a36Sopenharmony_ci	ua->castaddr = ua_tmp->castaddr;
572562306a36Sopenharmony_ci	ua->bastparam = ua_tmp->bastparam;
572662306a36Sopenharmony_ci	ua->bastaddr = ua_tmp->bastaddr;
572762306a36Sopenharmony_ci	ua->user_lksb = ua_tmp->user_lksb;
572862306a36Sopenharmony_ci
572962306a36Sopenharmony_ci	/*
573062306a36Sopenharmony_ci	 * The lkb reference from the ls_orphans list was not
573162306a36Sopenharmony_ci	 * removed above, and is now considered the reference
573262306a36Sopenharmony_ci	 * for the proc locks list.
573362306a36Sopenharmony_ci	 */
573462306a36Sopenharmony_ci
573562306a36Sopenharmony_ci	spin_lock(&ua->proc->locks_spin);
573662306a36Sopenharmony_ci	list_add_tail(&lkb->lkb_ownqueue, &ua->proc->locks);
573762306a36Sopenharmony_ci	spin_unlock(&ua->proc->locks_spin);
573862306a36Sopenharmony_ci out:
573962306a36Sopenharmony_ci	kfree(ua_tmp);
574062306a36Sopenharmony_ci	return rv;
574162306a36Sopenharmony_ci}
574262306a36Sopenharmony_ci
574362306a36Sopenharmony_ciint dlm_user_unlock(struct dlm_ls *ls, struct dlm_user_args *ua_tmp,
574462306a36Sopenharmony_ci		    uint32_t flags, uint32_t lkid, char *lvb_in)
574562306a36Sopenharmony_ci{
574662306a36Sopenharmony_ci	struct dlm_lkb *lkb;
574762306a36Sopenharmony_ci	struct dlm_args args;
574862306a36Sopenharmony_ci	struct dlm_user_args *ua;
574962306a36Sopenharmony_ci	int error;
575062306a36Sopenharmony_ci
575162306a36Sopenharmony_ci	dlm_lock_recovery(ls);
575262306a36Sopenharmony_ci
575362306a36Sopenharmony_ci	error = find_lkb(ls, lkid, &lkb);
575462306a36Sopenharmony_ci	if (error)
575562306a36Sopenharmony_ci		goto out;
575662306a36Sopenharmony_ci
575762306a36Sopenharmony_ci	trace_dlm_unlock_start(ls, lkb, flags);
575862306a36Sopenharmony_ci
575962306a36Sopenharmony_ci	ua = lkb->lkb_ua;
576062306a36Sopenharmony_ci
576162306a36Sopenharmony_ci	if (lvb_in && ua->lksb.sb_lvbptr)
576262306a36Sopenharmony_ci		memcpy(ua->lksb.sb_lvbptr, lvb_in, DLM_USER_LVB_LEN);
576362306a36Sopenharmony_ci	if (ua_tmp->castparam)
576462306a36Sopenharmony_ci		ua->castparam = ua_tmp->castparam;
576562306a36Sopenharmony_ci	ua->user_lksb = ua_tmp->user_lksb;
576662306a36Sopenharmony_ci
576762306a36Sopenharmony_ci	error = set_unlock_args(flags, ua, &args);
576862306a36Sopenharmony_ci	if (error)
576962306a36Sopenharmony_ci		goto out_put;
577062306a36Sopenharmony_ci
577162306a36Sopenharmony_ci	error = unlock_lock(ls, lkb, &args);
577262306a36Sopenharmony_ci
577362306a36Sopenharmony_ci	if (error == -DLM_EUNLOCK)
577462306a36Sopenharmony_ci		error = 0;
577562306a36Sopenharmony_ci	/* from validate_unlock_args() */
577662306a36Sopenharmony_ci	if (error == -EBUSY && (flags & DLM_LKF_FORCEUNLOCK))
577762306a36Sopenharmony_ci		error = 0;
577862306a36Sopenharmony_ci	if (error)
577962306a36Sopenharmony_ci		goto out_put;
578062306a36Sopenharmony_ci
578162306a36Sopenharmony_ci	spin_lock(&ua->proc->locks_spin);
578262306a36Sopenharmony_ci	/* dlm_user_add_cb() may have already taken lkb off the proc list */
578362306a36Sopenharmony_ci	if (!list_empty(&lkb->lkb_ownqueue))
578462306a36Sopenharmony_ci		list_move(&lkb->lkb_ownqueue, &ua->proc->unlocking);
578562306a36Sopenharmony_ci	spin_unlock(&ua->proc->locks_spin);
578662306a36Sopenharmony_ci out_put:
578762306a36Sopenharmony_ci	trace_dlm_unlock_end(ls, lkb, flags, error);
578862306a36Sopenharmony_ci	dlm_put_lkb(lkb);
578962306a36Sopenharmony_ci out:
579062306a36Sopenharmony_ci	dlm_unlock_recovery(ls);
579162306a36Sopenharmony_ci	kfree(ua_tmp);
579262306a36Sopenharmony_ci	return error;
579362306a36Sopenharmony_ci}
579462306a36Sopenharmony_ci
579562306a36Sopenharmony_ciint dlm_user_cancel(struct dlm_ls *ls, struct dlm_user_args *ua_tmp,
579662306a36Sopenharmony_ci		    uint32_t flags, uint32_t lkid)
579762306a36Sopenharmony_ci{
579862306a36Sopenharmony_ci	struct dlm_lkb *lkb;
579962306a36Sopenharmony_ci	struct dlm_args args;
580062306a36Sopenharmony_ci	struct dlm_user_args *ua;
580162306a36Sopenharmony_ci	int error;
580262306a36Sopenharmony_ci
580362306a36Sopenharmony_ci	dlm_lock_recovery(ls);
580462306a36Sopenharmony_ci
580562306a36Sopenharmony_ci	error = find_lkb(ls, lkid, &lkb);
580662306a36Sopenharmony_ci	if (error)
580762306a36Sopenharmony_ci		goto out;
580862306a36Sopenharmony_ci
580962306a36Sopenharmony_ci	trace_dlm_unlock_start(ls, lkb, flags);
581062306a36Sopenharmony_ci
581162306a36Sopenharmony_ci	ua = lkb->lkb_ua;
581262306a36Sopenharmony_ci	if (ua_tmp->castparam)
581362306a36Sopenharmony_ci		ua->castparam = ua_tmp->castparam;
581462306a36Sopenharmony_ci	ua->user_lksb = ua_tmp->user_lksb;
581562306a36Sopenharmony_ci
581662306a36Sopenharmony_ci	error = set_unlock_args(flags, ua, &args);
581762306a36Sopenharmony_ci	if (error)
581862306a36Sopenharmony_ci		goto out_put;
581962306a36Sopenharmony_ci
582062306a36Sopenharmony_ci	error = cancel_lock(ls, lkb, &args);
582162306a36Sopenharmony_ci
582262306a36Sopenharmony_ci	if (error == -DLM_ECANCEL)
582362306a36Sopenharmony_ci		error = 0;
582462306a36Sopenharmony_ci	/* from validate_unlock_args() */
582562306a36Sopenharmony_ci	if (error == -EBUSY)
582662306a36Sopenharmony_ci		error = 0;
582762306a36Sopenharmony_ci out_put:
582862306a36Sopenharmony_ci	trace_dlm_unlock_end(ls, lkb, flags, error);
582962306a36Sopenharmony_ci	dlm_put_lkb(lkb);
583062306a36Sopenharmony_ci out:
583162306a36Sopenharmony_ci	dlm_unlock_recovery(ls);
583262306a36Sopenharmony_ci	kfree(ua_tmp);
583362306a36Sopenharmony_ci	return error;
583462306a36Sopenharmony_ci}
583562306a36Sopenharmony_ci
583662306a36Sopenharmony_ciint dlm_user_deadlock(struct dlm_ls *ls, uint32_t flags, uint32_t lkid)
583762306a36Sopenharmony_ci{
583862306a36Sopenharmony_ci	struct dlm_lkb *lkb;
583962306a36Sopenharmony_ci	struct dlm_args args;
584062306a36Sopenharmony_ci	struct dlm_user_args *ua;
584162306a36Sopenharmony_ci	struct dlm_rsb *r;
584262306a36Sopenharmony_ci	int error;
584362306a36Sopenharmony_ci
584462306a36Sopenharmony_ci	dlm_lock_recovery(ls);
584562306a36Sopenharmony_ci
584662306a36Sopenharmony_ci	error = find_lkb(ls, lkid, &lkb);
584762306a36Sopenharmony_ci	if (error)
584862306a36Sopenharmony_ci		goto out;
584962306a36Sopenharmony_ci
585062306a36Sopenharmony_ci	trace_dlm_unlock_start(ls, lkb, flags);
585162306a36Sopenharmony_ci
585262306a36Sopenharmony_ci	ua = lkb->lkb_ua;
585362306a36Sopenharmony_ci
585462306a36Sopenharmony_ci	error = set_unlock_args(flags, ua, &args);
585562306a36Sopenharmony_ci	if (error)
585662306a36Sopenharmony_ci		goto out_put;
585762306a36Sopenharmony_ci
585862306a36Sopenharmony_ci	/* same as cancel_lock(), but set DEADLOCK_CANCEL after lock_rsb */
585962306a36Sopenharmony_ci
586062306a36Sopenharmony_ci	r = lkb->lkb_resource;
586162306a36Sopenharmony_ci	hold_rsb(r);
586262306a36Sopenharmony_ci	lock_rsb(r);
586362306a36Sopenharmony_ci
586462306a36Sopenharmony_ci	error = validate_unlock_args(lkb, &args);
586562306a36Sopenharmony_ci	if (error)
586662306a36Sopenharmony_ci		goto out_r;
586762306a36Sopenharmony_ci	set_bit(DLM_IFL_DEADLOCK_CANCEL_BIT, &lkb->lkb_iflags);
586862306a36Sopenharmony_ci
586962306a36Sopenharmony_ci	error = _cancel_lock(r, lkb);
587062306a36Sopenharmony_ci out_r:
587162306a36Sopenharmony_ci	unlock_rsb(r);
587262306a36Sopenharmony_ci	put_rsb(r);
587362306a36Sopenharmony_ci
587462306a36Sopenharmony_ci	if (error == -DLM_ECANCEL)
587562306a36Sopenharmony_ci		error = 0;
587662306a36Sopenharmony_ci	/* from validate_unlock_args() */
587762306a36Sopenharmony_ci	if (error == -EBUSY)
587862306a36Sopenharmony_ci		error = 0;
587962306a36Sopenharmony_ci out_put:
588062306a36Sopenharmony_ci	trace_dlm_unlock_end(ls, lkb, flags, error);
588162306a36Sopenharmony_ci	dlm_put_lkb(lkb);
588262306a36Sopenharmony_ci out:
588362306a36Sopenharmony_ci	dlm_unlock_recovery(ls);
588462306a36Sopenharmony_ci	return error;
588562306a36Sopenharmony_ci}
588662306a36Sopenharmony_ci
588762306a36Sopenharmony_ci/* lkb's that are removed from the waiters list by revert are just left on the
588862306a36Sopenharmony_ci   orphans list with the granted orphan locks, to be freed by purge */
588962306a36Sopenharmony_ci
589062306a36Sopenharmony_cistatic int orphan_proc_lock(struct dlm_ls *ls, struct dlm_lkb *lkb)
589162306a36Sopenharmony_ci{
589262306a36Sopenharmony_ci	struct dlm_args args;
589362306a36Sopenharmony_ci	int error;
589462306a36Sopenharmony_ci
589562306a36Sopenharmony_ci	hold_lkb(lkb); /* reference for the ls_orphans list */
589662306a36Sopenharmony_ci	mutex_lock(&ls->ls_orphans_mutex);
589762306a36Sopenharmony_ci	list_add_tail(&lkb->lkb_ownqueue, &ls->ls_orphans);
589862306a36Sopenharmony_ci	mutex_unlock(&ls->ls_orphans_mutex);
589962306a36Sopenharmony_ci
590062306a36Sopenharmony_ci	set_unlock_args(0, lkb->lkb_ua, &args);
590162306a36Sopenharmony_ci
590262306a36Sopenharmony_ci	error = cancel_lock(ls, lkb, &args);
590362306a36Sopenharmony_ci	if (error == -DLM_ECANCEL)
590462306a36Sopenharmony_ci		error = 0;
590562306a36Sopenharmony_ci	return error;
590662306a36Sopenharmony_ci}
590762306a36Sopenharmony_ci
590862306a36Sopenharmony_ci/* The FORCEUNLOCK flag allows the unlock to go ahead even if the lkb isn't
590962306a36Sopenharmony_ci   granted.  Regardless of what rsb queue the lock is on, it's removed and
591062306a36Sopenharmony_ci   freed.  The IVVALBLK flag causes the lvb on the resource to be invalidated
591162306a36Sopenharmony_ci   if our lock is PW/EX (it's ignored if our granted mode is smaller.) */
591262306a36Sopenharmony_ci
591362306a36Sopenharmony_cistatic int unlock_proc_lock(struct dlm_ls *ls, struct dlm_lkb *lkb)
591462306a36Sopenharmony_ci{
591562306a36Sopenharmony_ci	struct dlm_args args;
591662306a36Sopenharmony_ci	int error;
591762306a36Sopenharmony_ci
591862306a36Sopenharmony_ci	set_unlock_args(DLM_LKF_FORCEUNLOCK | DLM_LKF_IVVALBLK,
591962306a36Sopenharmony_ci			lkb->lkb_ua, &args);
592062306a36Sopenharmony_ci
592162306a36Sopenharmony_ci	error = unlock_lock(ls, lkb, &args);
592262306a36Sopenharmony_ci	if (error == -DLM_EUNLOCK)
592362306a36Sopenharmony_ci		error = 0;
592462306a36Sopenharmony_ci	return error;
592562306a36Sopenharmony_ci}
592662306a36Sopenharmony_ci
592762306a36Sopenharmony_ci/* We have to release clear_proc_locks mutex before calling unlock_proc_lock()
592862306a36Sopenharmony_ci   (which does lock_rsb) due to deadlock with receiving a message that does
592962306a36Sopenharmony_ci   lock_rsb followed by dlm_user_add_cb() */
593062306a36Sopenharmony_ci
593162306a36Sopenharmony_cistatic struct dlm_lkb *del_proc_lock(struct dlm_ls *ls,
593262306a36Sopenharmony_ci				     struct dlm_user_proc *proc)
593362306a36Sopenharmony_ci{
593462306a36Sopenharmony_ci	struct dlm_lkb *lkb = NULL;
593562306a36Sopenharmony_ci
593662306a36Sopenharmony_ci	spin_lock(&ls->ls_clear_proc_locks);
593762306a36Sopenharmony_ci	if (list_empty(&proc->locks))
593862306a36Sopenharmony_ci		goto out;
593962306a36Sopenharmony_ci
594062306a36Sopenharmony_ci	lkb = list_entry(proc->locks.next, struct dlm_lkb, lkb_ownqueue);
594162306a36Sopenharmony_ci	list_del_init(&lkb->lkb_ownqueue);
594262306a36Sopenharmony_ci
594362306a36Sopenharmony_ci	if (lkb->lkb_exflags & DLM_LKF_PERSISTENT)
594462306a36Sopenharmony_ci		set_bit(DLM_DFL_ORPHAN_BIT, &lkb->lkb_dflags);
594562306a36Sopenharmony_ci	else
594662306a36Sopenharmony_ci		set_bit(DLM_IFL_DEAD_BIT, &lkb->lkb_iflags);
594762306a36Sopenharmony_ci out:
594862306a36Sopenharmony_ci	spin_unlock(&ls->ls_clear_proc_locks);
594962306a36Sopenharmony_ci	return lkb;
595062306a36Sopenharmony_ci}
595162306a36Sopenharmony_ci
595262306a36Sopenharmony_ci/* The ls_clear_proc_locks mutex protects against dlm_user_add_cb() which
595362306a36Sopenharmony_ci   1) references lkb->ua which we free here and 2) adds lkbs to proc->asts,
595462306a36Sopenharmony_ci   which we clear here. */
595562306a36Sopenharmony_ci
595662306a36Sopenharmony_ci/* proc CLOSING flag is set so no more device_reads should look at proc->asts
595762306a36Sopenharmony_ci   list, and no more device_writes should add lkb's to proc->locks list; so we
595862306a36Sopenharmony_ci   shouldn't need to take asts_spin or locks_spin here.  this assumes that
595962306a36Sopenharmony_ci   device reads/writes/closes are serialized -- FIXME: we may need to serialize
596062306a36Sopenharmony_ci   them ourself. */
596162306a36Sopenharmony_ci
596262306a36Sopenharmony_civoid dlm_clear_proc_locks(struct dlm_ls *ls, struct dlm_user_proc *proc)
596362306a36Sopenharmony_ci{
596462306a36Sopenharmony_ci	struct dlm_lkb *lkb, *safe;
596562306a36Sopenharmony_ci
596662306a36Sopenharmony_ci	dlm_lock_recovery(ls);
596762306a36Sopenharmony_ci
596862306a36Sopenharmony_ci	while (1) {
596962306a36Sopenharmony_ci		lkb = del_proc_lock(ls, proc);
597062306a36Sopenharmony_ci		if (!lkb)
597162306a36Sopenharmony_ci			break;
597262306a36Sopenharmony_ci		if (lkb->lkb_exflags & DLM_LKF_PERSISTENT)
597362306a36Sopenharmony_ci			orphan_proc_lock(ls, lkb);
597462306a36Sopenharmony_ci		else
597562306a36Sopenharmony_ci			unlock_proc_lock(ls, lkb);
597662306a36Sopenharmony_ci
597762306a36Sopenharmony_ci		/* this removes the reference for the proc->locks list
597862306a36Sopenharmony_ci		   added by dlm_user_request, it may result in the lkb
597962306a36Sopenharmony_ci		   being freed */
598062306a36Sopenharmony_ci
598162306a36Sopenharmony_ci		dlm_put_lkb(lkb);
598262306a36Sopenharmony_ci	}
598362306a36Sopenharmony_ci
598462306a36Sopenharmony_ci	spin_lock(&ls->ls_clear_proc_locks);
598562306a36Sopenharmony_ci
598662306a36Sopenharmony_ci	/* in-progress unlocks */
598762306a36Sopenharmony_ci	list_for_each_entry_safe(lkb, safe, &proc->unlocking, lkb_ownqueue) {
598862306a36Sopenharmony_ci		list_del_init(&lkb->lkb_ownqueue);
598962306a36Sopenharmony_ci		set_bit(DLM_IFL_DEAD_BIT, &lkb->lkb_iflags);
599062306a36Sopenharmony_ci		dlm_put_lkb(lkb);
599162306a36Sopenharmony_ci	}
599262306a36Sopenharmony_ci
599362306a36Sopenharmony_ci	list_for_each_entry_safe(lkb, safe, &proc->asts, lkb_cb_list) {
599462306a36Sopenharmony_ci		dlm_purge_lkb_callbacks(lkb);
599562306a36Sopenharmony_ci		list_del_init(&lkb->lkb_cb_list);
599662306a36Sopenharmony_ci		dlm_put_lkb(lkb);
599762306a36Sopenharmony_ci	}
599862306a36Sopenharmony_ci
599962306a36Sopenharmony_ci	spin_unlock(&ls->ls_clear_proc_locks);
600062306a36Sopenharmony_ci	dlm_unlock_recovery(ls);
600162306a36Sopenharmony_ci}
600262306a36Sopenharmony_ci
600362306a36Sopenharmony_cistatic void purge_proc_locks(struct dlm_ls *ls, struct dlm_user_proc *proc)
600462306a36Sopenharmony_ci{
600562306a36Sopenharmony_ci	struct dlm_lkb *lkb, *safe;
600662306a36Sopenharmony_ci
600762306a36Sopenharmony_ci	while (1) {
600862306a36Sopenharmony_ci		lkb = NULL;
600962306a36Sopenharmony_ci		spin_lock(&proc->locks_spin);
601062306a36Sopenharmony_ci		if (!list_empty(&proc->locks)) {
601162306a36Sopenharmony_ci			lkb = list_entry(proc->locks.next, struct dlm_lkb,
601262306a36Sopenharmony_ci					 lkb_ownqueue);
601362306a36Sopenharmony_ci			list_del_init(&lkb->lkb_ownqueue);
601462306a36Sopenharmony_ci		}
601562306a36Sopenharmony_ci		spin_unlock(&proc->locks_spin);
601662306a36Sopenharmony_ci
601762306a36Sopenharmony_ci		if (!lkb)
601862306a36Sopenharmony_ci			break;
601962306a36Sopenharmony_ci
602062306a36Sopenharmony_ci		set_bit(DLM_IFL_DEAD_BIT, &lkb->lkb_iflags);
602162306a36Sopenharmony_ci		unlock_proc_lock(ls, lkb);
602262306a36Sopenharmony_ci		dlm_put_lkb(lkb); /* ref from proc->locks list */
602362306a36Sopenharmony_ci	}
602462306a36Sopenharmony_ci
602562306a36Sopenharmony_ci	spin_lock(&proc->locks_spin);
602662306a36Sopenharmony_ci	list_for_each_entry_safe(lkb, safe, &proc->unlocking, lkb_ownqueue) {
602762306a36Sopenharmony_ci		list_del_init(&lkb->lkb_ownqueue);
602862306a36Sopenharmony_ci		set_bit(DLM_IFL_DEAD_BIT, &lkb->lkb_iflags);
602962306a36Sopenharmony_ci		dlm_put_lkb(lkb);
603062306a36Sopenharmony_ci	}
603162306a36Sopenharmony_ci	spin_unlock(&proc->locks_spin);
603262306a36Sopenharmony_ci
603362306a36Sopenharmony_ci	spin_lock(&proc->asts_spin);
603462306a36Sopenharmony_ci	list_for_each_entry_safe(lkb, safe, &proc->asts, lkb_cb_list) {
603562306a36Sopenharmony_ci		dlm_purge_lkb_callbacks(lkb);
603662306a36Sopenharmony_ci		list_del_init(&lkb->lkb_cb_list);
603762306a36Sopenharmony_ci		dlm_put_lkb(lkb);
603862306a36Sopenharmony_ci	}
603962306a36Sopenharmony_ci	spin_unlock(&proc->asts_spin);
604062306a36Sopenharmony_ci}
604162306a36Sopenharmony_ci
604262306a36Sopenharmony_ci/* pid of 0 means purge all orphans */
604362306a36Sopenharmony_ci
604462306a36Sopenharmony_cistatic void do_purge(struct dlm_ls *ls, int nodeid, int pid)
604562306a36Sopenharmony_ci{
604662306a36Sopenharmony_ci	struct dlm_lkb *lkb, *safe;
604762306a36Sopenharmony_ci
604862306a36Sopenharmony_ci	mutex_lock(&ls->ls_orphans_mutex);
604962306a36Sopenharmony_ci	list_for_each_entry_safe(lkb, safe, &ls->ls_orphans, lkb_ownqueue) {
605062306a36Sopenharmony_ci		if (pid && lkb->lkb_ownpid != pid)
605162306a36Sopenharmony_ci			continue;
605262306a36Sopenharmony_ci		unlock_proc_lock(ls, lkb);
605362306a36Sopenharmony_ci		list_del_init(&lkb->lkb_ownqueue);
605462306a36Sopenharmony_ci		dlm_put_lkb(lkb);
605562306a36Sopenharmony_ci	}
605662306a36Sopenharmony_ci	mutex_unlock(&ls->ls_orphans_mutex);
605762306a36Sopenharmony_ci}
605862306a36Sopenharmony_ci
605962306a36Sopenharmony_cistatic int send_purge(struct dlm_ls *ls, int nodeid, int pid)
606062306a36Sopenharmony_ci{
606162306a36Sopenharmony_ci	struct dlm_message *ms;
606262306a36Sopenharmony_ci	struct dlm_mhandle *mh;
606362306a36Sopenharmony_ci	int error;
606462306a36Sopenharmony_ci
606562306a36Sopenharmony_ci	error = _create_message(ls, sizeof(struct dlm_message), nodeid,
606662306a36Sopenharmony_ci				DLM_MSG_PURGE, &ms, &mh, GFP_NOFS);
606762306a36Sopenharmony_ci	if (error)
606862306a36Sopenharmony_ci		return error;
606962306a36Sopenharmony_ci	ms->m_nodeid = cpu_to_le32(nodeid);
607062306a36Sopenharmony_ci	ms->m_pid = cpu_to_le32(pid);
607162306a36Sopenharmony_ci
607262306a36Sopenharmony_ci	return send_message(mh, ms, NULL, 0);
607362306a36Sopenharmony_ci}
607462306a36Sopenharmony_ci
607562306a36Sopenharmony_ciint dlm_user_purge(struct dlm_ls *ls, struct dlm_user_proc *proc,
607662306a36Sopenharmony_ci		   int nodeid, int pid)
607762306a36Sopenharmony_ci{
607862306a36Sopenharmony_ci	int error = 0;
607962306a36Sopenharmony_ci
608062306a36Sopenharmony_ci	if (nodeid && (nodeid != dlm_our_nodeid())) {
608162306a36Sopenharmony_ci		error = send_purge(ls, nodeid, pid);
608262306a36Sopenharmony_ci	} else {
608362306a36Sopenharmony_ci		dlm_lock_recovery(ls);
608462306a36Sopenharmony_ci		if (pid == current->pid)
608562306a36Sopenharmony_ci			purge_proc_locks(ls, proc);
608662306a36Sopenharmony_ci		else
608762306a36Sopenharmony_ci			do_purge(ls, nodeid, pid);
608862306a36Sopenharmony_ci		dlm_unlock_recovery(ls);
608962306a36Sopenharmony_ci	}
609062306a36Sopenharmony_ci	return error;
609162306a36Sopenharmony_ci}
609262306a36Sopenharmony_ci
609362306a36Sopenharmony_ci/* debug functionality */
609462306a36Sopenharmony_ciint dlm_debug_add_lkb(struct dlm_ls *ls, uint32_t lkb_id, char *name, int len,
609562306a36Sopenharmony_ci		      int lkb_nodeid, unsigned int lkb_dflags, int lkb_status)
609662306a36Sopenharmony_ci{
609762306a36Sopenharmony_ci	struct dlm_lksb *lksb;
609862306a36Sopenharmony_ci	struct dlm_lkb *lkb;
609962306a36Sopenharmony_ci	struct dlm_rsb *r;
610062306a36Sopenharmony_ci	int error;
610162306a36Sopenharmony_ci
610262306a36Sopenharmony_ci	/* we currently can't set a valid user lock */
610362306a36Sopenharmony_ci	if (lkb_dflags & BIT(DLM_DFL_USER_BIT))
610462306a36Sopenharmony_ci		return -EOPNOTSUPP;
610562306a36Sopenharmony_ci
610662306a36Sopenharmony_ci	lksb = kzalloc(sizeof(*lksb), GFP_NOFS);
610762306a36Sopenharmony_ci	if (!lksb)
610862306a36Sopenharmony_ci		return -ENOMEM;
610962306a36Sopenharmony_ci
611062306a36Sopenharmony_ci	error = _create_lkb(ls, &lkb, lkb_id, lkb_id + 1);
611162306a36Sopenharmony_ci	if (error) {
611262306a36Sopenharmony_ci		kfree(lksb);
611362306a36Sopenharmony_ci		return error;
611462306a36Sopenharmony_ci	}
611562306a36Sopenharmony_ci
611662306a36Sopenharmony_ci	dlm_set_dflags_val(lkb, lkb_dflags);
611762306a36Sopenharmony_ci	lkb->lkb_nodeid = lkb_nodeid;
611862306a36Sopenharmony_ci	lkb->lkb_lksb = lksb;
611962306a36Sopenharmony_ci	/* user specific pointer, just don't have it NULL for kernel locks */
612062306a36Sopenharmony_ci	if (~lkb_dflags & BIT(DLM_DFL_USER_BIT))
612162306a36Sopenharmony_ci		lkb->lkb_astparam = (void *)0xDEADBEEF;
612262306a36Sopenharmony_ci
612362306a36Sopenharmony_ci	error = find_rsb(ls, name, len, 0, R_REQUEST, &r);
612462306a36Sopenharmony_ci	if (error) {
612562306a36Sopenharmony_ci		kfree(lksb);
612662306a36Sopenharmony_ci		__put_lkb(ls, lkb);
612762306a36Sopenharmony_ci		return error;
612862306a36Sopenharmony_ci	}
612962306a36Sopenharmony_ci
613062306a36Sopenharmony_ci	lock_rsb(r);
613162306a36Sopenharmony_ci	attach_lkb(r, lkb);
613262306a36Sopenharmony_ci	add_lkb(r, lkb, lkb_status);
613362306a36Sopenharmony_ci	unlock_rsb(r);
613462306a36Sopenharmony_ci	put_rsb(r);
613562306a36Sopenharmony_ci
613662306a36Sopenharmony_ci	return 0;
613762306a36Sopenharmony_ci}
613862306a36Sopenharmony_ci
613962306a36Sopenharmony_ciint dlm_debug_add_lkb_to_waiters(struct dlm_ls *ls, uint32_t lkb_id,
614062306a36Sopenharmony_ci				 int mstype, int to_nodeid)
614162306a36Sopenharmony_ci{
614262306a36Sopenharmony_ci	struct dlm_lkb *lkb;
614362306a36Sopenharmony_ci	int error;
614462306a36Sopenharmony_ci
614562306a36Sopenharmony_ci	error = find_lkb(ls, lkb_id, &lkb);
614662306a36Sopenharmony_ci	if (error)
614762306a36Sopenharmony_ci		return error;
614862306a36Sopenharmony_ci
614962306a36Sopenharmony_ci	error = add_to_waiters(lkb, mstype, to_nodeid);
615062306a36Sopenharmony_ci	dlm_put_lkb(lkb);
615162306a36Sopenharmony_ci	return error;
615262306a36Sopenharmony_ci}
615362306a36Sopenharmony_ci
6154