aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/fs/dlm/lock.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--fs/dlm/lock.c18
1 files changed, 14 insertions, 4 deletions
diff --git a/fs/dlm/lock.c b/fs/dlm/lock.c
index 9d3ec359d5e3..865dc70a9dfc 100644
--- a/fs/dlm/lock.c
+++ b/fs/dlm/lock.c
@@ -1527,11 +1527,21 @@ static int find_lkb(struct dlm_ls *ls, uint32_t lkid, struct dlm_lkb **lkb_ret)
{
struct dlm_lkb *lkb;
- read_lock_bh(&ls->ls_lkbxa_lock);
+ rcu_read_lock();
lkb = xa_load(&ls->ls_lkbxa, lkid);
- if (lkb)
- kref_get(&lkb->lkb_ref);
- read_unlock_bh(&ls->ls_lkbxa_lock);
+ if (lkb) {
+ /* check if lkb is still part of lkbxa under lkbxa_lock as
+ * the lkb_ref is tight to the lkbxa data structure, see
+ * __put_lkb().
+ */
+ read_lock_bh(&ls->ls_lkbxa_lock);
+ if (kref_read(&lkb->lkb_ref))
+ kref_get(&lkb->lkb_ref);
+ else
+ lkb = NULL;
+ read_unlock_bh(&ls->ls_lkbxa_lock);
+ }
+ rcu_read_unlock();
*lkb_ret = lkb;
return lkb ? 0 : -ENOENT;