dlm: fix removal of rsb struct that is master and dir record

An rsb struct was not being removed in the case where it
was both the master and the dir record.  This case (master
and dir node) was missed in the condition for doing add_scan()
from deactivate_rsb().  Fixing this triggers a related WARN_ON
that needs to be fixed, and requires adjusting where two
del_scan() calls are made.

Fixes: c217adfc8c ("dlm: fix add_scan and del_scan usage")
Signed-off-by: Alexander Aring <aahringo@redhat.com>
Signed-off-by: David Teigland <teigland@redhat.com>
This commit is contained in:
Alexander Aring 2024-11-19 15:56:44 -05:00 committed by David Teigland
parent 78d4f34e21
commit 134129520b

View File

@ -824,9 +824,12 @@ static int find_rsb_dir(struct dlm_ls *ls, const void *name, int len,
r->res_first_lkid = 0;
}
/* A dir record will not be on the scan list. */
if (r->res_dir_nodeid != our_nodeid)
del_scan(ls, r);
/* we always deactivate scan timer for the rsb, when
* we move it out of the inactive state as rsb state
* can be changed and scan timers are only for inactive
* rsbs.
*/
del_scan(ls, r);
list_move(&r->res_slow_list, &ls->ls_slow_active);
rsb_clear_flag(r, RSB_INACTIVE);
kref_init(&r->res_ref); /* ref is now used in active state */
@ -989,10 +992,10 @@ static int find_rsb_nodir(struct dlm_ls *ls, const void *name, int len,
r->res_nodeid = 0;
}
del_scan(ls, r);
list_move(&r->res_slow_list, &ls->ls_slow_active);
rsb_clear_flag(r, RSB_INACTIVE);
kref_init(&r->res_ref);
del_scan(ls, r);
write_unlock_bh(&ls->ls_rsbtbl_lock);
goto out;
@ -1337,9 +1340,13 @@ static int _dlm_master_lookup(struct dlm_ls *ls, int from_nodeid, const char *na
__dlm_master_lookup(ls, r, our_nodeid, from_nodeid, true, flags,
r_nodeid, result);
/* A dir record rsb should never be on scan list. */
/* Try to fix this with del_scan? */
WARN_ON(!list_empty(&r->res_scan_list));
/* A dir record rsb should never be on scan list.
* Except when we are the dir and master node.
* This function should only be called by the dir
* node.
*/
WARN_ON(!list_empty(&r->res_scan_list) &&
r->res_master_nodeid != our_nodeid);
write_unlock_bh(&ls->ls_rsbtbl_lock);
@ -1430,16 +1437,23 @@ static void deactivate_rsb(struct kref *kref)
list_move(&r->res_slow_list, &ls->ls_slow_inactive);
/*
* When the rsb becomes unused:
* - If it's not a dir record for a remote master rsb,
* then it is put on the scan list to be freed.
* - If it's a dir record for a remote master rsb,
* then it is kept in the inactive state until
* receive_remove() from the master node.
* When the rsb becomes unused, there are two possibilities:
* 1. Leave the inactive rsb in place (don't remove it).
* 2. Add it to the scan list to be removed.
*
* 1 is done when the rsb is acting as the dir record
* for a remotely mastered rsb. The rsb must be left
* in place as an inactive rsb to act as the dir record.
*
* 2 is done when a) the rsb is not the master and not the
* dir record, b) when the rsb is both the master and the
* dir record, c) when the rsb is master but not dir record.
*
* (If no directory is used, the rsb can always be removed.)
*/
if (!dlm_no_directory(ls) &&
(r->res_master_nodeid != our_nodeid) &&
(dlm_dir_nodeid(r) != our_nodeid))
if (dlm_no_directory(ls) ||
(r->res_master_nodeid == our_nodeid ||
dlm_dir_nodeid(r) != our_nodeid))
add_scan(ls, r);
if (r->res_lvbptr) {