| From bcdfbec3c7a11794f47fa29d9890edc847da91b2 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Tue, 19 Nov 2024 15:56:44 -0500 |
| Subject: dlm: fix removal of rsb struct that is master and dir record |
| |
| From: Alexander Aring <aahringo@redhat.com> |
| |
| [ Upstream commit 134129520beaf3339482c557361ea0bde709cf36 ] |
| |
| 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: c217adfc8caa ("dlm: fix add_scan and del_scan usage") |
| Signed-off-by: Alexander Aring <aahringo@redhat.com> |
| Signed-off-by: David Teigland <teigland@redhat.com> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| fs/dlm/lock.c | 46 ++++++++++++++++++++++++++++++---------------- |
| 1 file changed, 30 insertions(+), 16 deletions(-) |
| |
| diff --git a/fs/dlm/lock.c b/fs/dlm/lock.c |
| index fc1d710166e92..c8ff88f1cdcf2 100644 |
| --- a/fs/dlm/lock.c |
| +++ b/fs/dlm/lock.c |
| @@ -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) { |
| -- |
| 2.39.5 |
| |