[Ocfs2-devel] [PATCH] ocfs2/dlm: ignore cleaning the migration mle that is inuse
xuejiufei
xuejiufei at huawei.com
Wed Dec 30 23:15:33 PST 2015
Hi Junxiao,
On 2015/12/31 11:05, Junxiao Bi wrote:
> On 12/30/2015 05:56 PM, xuejiufei wrote:
>> Hi Junxiao,
>> You are right. But it may happen that mle->woken is set to 1 in
>> dlm_clean_migration_mle() just after atomic_read() in
>> dlm_migrate_lockres(). Actually we trigger this BUG when dlm_send_one_lockres()
>> return error.
> Yes, that's possible because of that 5s timeout wakeup, I think this
> timeout is useless and can be removed?
>>
>> And I think dlm_migrate_lockres() should not set owner to target and return 0
>> when mle->woken is set to 1 in dlm_clean_migration_mle(). This is another problem?
> Yes, it should be fixed, or the lockres owner will be set to a down node
> wrongly. Can the following fix these two issue?
>
It can not fix the first issue when dlm_send_one_lockres() or
dlm_mark_lockres_migrating() return error, right?
>
> diff --git a/fs/ocfs2/dlm/dlmmaster.c b/fs/ocfs2/dlm/dlmmaster.c
> index 84f2f8079466..d0380ea62340 100644
> --- a/fs/ocfs2/dlm/dlmmaster.c
> +++ b/fs/ocfs2/dlm/dlmmaster.c
> @@ -2618,39 +2618,22 @@ fail:
>
>
> /* wait for new node to assert master */
> - while (1) {
> - ret = wait_event_interruptible_timeout(mle->wq,
> - (atomic_read(&mle->woken) == 1),
> - msecs_to_jiffies(5000));
> -
> - if (ret >= 0) {
> - if (atomic_read(&mle->woken) == 1 ||
> - res->owner == target)
> - break;
> -
> - mlog(0, "%s:%.*s: timed out during migration\n",
> - dlm->name, res->lockname.len, res->lockname.name);
> - /* avoid hang during shutdown when migrating lockres
> - * to a node which also goes down */
> - if (dlm_is_node_dead(dlm, target)) {
> - mlog(0, "%s:%.*s: expected migration "
> - "target %u is no longer up, restarting\n",
> - dlm->name, res->lockname.len,
> - res->lockname.name, target);
> - ret = -EINVAL;
> - /* migration failed, detach and clean up mle */
> - dlm_mle_detach_hb_events(dlm, mle);
> - dlm_put_mle(mle);
> - dlm_put_mle_inuse(mle);
> - spin_lock(&res->spinlock);
> - res->state &= ~DLM_LOCK_RES_MIGRATING;
> - wake = 1;
> - spin_unlock(&res->spinlock);
> - goto leave;
> - }
> - } else
> - mlog(0, "%s:%.*s: caught signal during migration\n",
> - dlm->name, res->lockname.len, res->lockname.name);
> + wait_event(mle->wq, ((atomic_read(&mle->woken) == 1) ||
> + (atomic_read(&mle->woken) == 2)));
> +
> + /* migrate target down */
> + if (atomic_read(&mle->woken) == 2) {
> + mlog(0, "%s:%.*s: expected migration "
> + "target %u is no longer up, restarting\n",
> + dlm->name, res->lockname.len,
> + res->lockname.name, target);
> + ret = -EINVAL;
> + dlm_put_mle_inuse(mle);
> + spin_lock(&res->spinlock);
> + res->state &= ~DLM_LOCK_RES_MIGRATING;
> + wake = 1;
> + spin_unlock(&res->spinlock);
> + goto leave;
> }
>
> /* all done, set the owner, clear the flag */
> @@ -3227,7 +3210,7 @@ static void dlm_clean_migration_mle(struct
> dlm_ctxt *dlm,
>
> spin_lock(&mle->spinlock);
> __dlm_unlink_mle(dlm, mle);
> - atomic_set(&mle->woken, 1);
> + atomic_set(&mle->woken, 2);
> spin_unlock(&mle->spinlock);
>
> wake_up(&mle->wq);
>
> Thanks,
> Junxiao.
>
>
>>
>> Thanks
>> Jiufei.
>>
>> On 2015/12/30 10:52, Junxiao Bi wrote:
>>> Hi Jiufei,
>>>
>>> When target node down, mle is cleared from
>>> dlm_do_local_recovery_cleanup()->dlm_clean_master_list()->dlm_clean_migration_mle()?
>>> mle->woken is set to 1 in dlm_clean_migration_mle(), so the code to
>>> detect target node down(if (dlm_is_node_dead(dlm, target))) will never
>>> be run in dlm_migrate_lockres()?
>>>
>>>
>>> 2621 while (1) {
>>> 2622 ret = wait_event_interruptible_timeout(mle->wq,
>>> 2623 (atomic_read(&mle->woken)
>>> == 1),
>>> 2624 msecs_to_jiffies(5000));
>>> 2625
>>> 2626 if (ret >= 0) {
>>> 2627 if (atomic_read(&mle->woken) == 1 ||
>>> 2628 res->owner == target)
>>> 2629 break;
>>> 2630
>>> 2631 mlog(0, "%s:%.*s: timed out during
>>> migration\n",
>>> 2632 dlm->name, res->lockname.len,
>>> res->lockname.name);
>>> 2633 /* avoid hang during shutdown when
>>> migrating lockres
>>> 2634 * to a node which also goes down */
>>> 2635 if (dlm_is_node_dead(dlm, target)) {
>>> 2636 mlog(0, "%s:%.*s: expected migration "
>>> 2637 "target %u is no longer up,
>>> restarting\n",
>>> 2638 dlm->name, res->lockname.len,
>>> 2639 res->lockname.name, target);
>>> 2640 ret = -EINVAL;
>>> 2641 /* migration failed, detach and
>>> clean up mle */
>>> 2642 dlm_mle_detach_hb_events(dlm, mle);
>>> 2643 dlm_put_mle(mle);
>>> 2644 dlm_put_mle_inuse(mle);
>>> 2645 spin_lock(&res->spinlock);
>>> 2646 res->state &= ~DLM_LOCK_RES_MIGRATING;
>>> 2647 wake = 1;
>>> 2648 spin_unlock(&res->spinlock);
>>> 2649 goto leave;
>>> 2650 }
>>> 2651 } else
>>> 2652 mlog(0, "%s:%.*s: caught signal during
>>> migration\n",
>>> 2653 dlm->name, res->lockname.len,
>>> res->lockname.name);
>>> 2654 }
>>>
>>>
>>> Thanks,
>>> Junxiao.
>>> On 12/28/2015 03:44 PM, xuejiufei wrote:
>>>> We have found that migration source will trigger a BUG that the
>>>> refcount of mle is already zero before put when the target is
>>>> down during migration. The situation is as follows:
>>>>
>>>> dlm_migrate_lockres
>>>> dlm_add_migration_mle
>>>> dlm_mark_lockres_migrating
>>>> dlm_get_mle_inuse
>>>> <<<<<< Now the refcount of the mle is 2.
>>>> dlm_send_one_lockres and wait for the target to become the
>>>> new master.
>>>> <<<<<< o2hb detect the target down and clean the migration
>>>> mle. Now the refcount is 1.
>>>>
>>>> dlm_migrate_lockres woken, and put the mle twice when found
>>>> the target goes down which trigger the BUG with the following
>>>> message:
>>>> "ERROR: bad mle: ".
>>>>
>>>> Signed-off-by: Jiufei Xue <xuejiufei at huawei.com>
>>>> Reviewed-by: Joseph Qi <joseph.qi at huawei.com>
>>>> ---
>>>> fs/ocfs2/dlm/dlmmaster.c | 26 +++++++++++++++-----------
>>>> 1 file changed, 15 insertions(+), 11 deletions(-)
>>>>
>>>> diff --git a/fs/ocfs2/dlm/dlmmaster.c b/fs/ocfs2/dlm/dlmmaster.c
>>>> index 936e11b..b713140 100644
>>>> --- a/fs/ocfs2/dlm/dlmmaster.c
>>>> +++ b/fs/ocfs2/dlm/dlmmaster.c
>>>> @@ -2519,6 +2519,11 @@ static int dlm_migrate_lockres(struct dlm_ctxt *dlm,
>>>> spin_lock(&dlm->master_lock);
>>>> ret = dlm_add_migration_mle(dlm, res, mle, &oldmle, name,
>>>> namelen, target, dlm->node_num);
>>>> + /* get an extra reference on the mle.
>>>> + * otherwise the assert_master from the new
>>>> + * master will destroy this.
>>>> + */
>>>> + dlm_get_mle_inuse(mle);
>>>> spin_unlock(&dlm->master_lock);
>>>> spin_unlock(&dlm->spinlock);
>>>>
>>>> @@ -2554,6 +2559,7 @@ fail:
>>>> if (mle_added) {
>>>> dlm_mle_detach_hb_events(dlm, mle);
>>>> dlm_put_mle(mle);
>>>> + dlm_put_mle_inuse(mle);
>>>> } else if (mle) {
>>>> kmem_cache_free(dlm_mle_cache, mle);
>>>> mle = NULL;
>>>> @@ -2571,17 +2577,6 @@ fail:
>>>> * ensure that all assert_master work is flushed. */
>>>> flush_workqueue(dlm->dlm_worker);
>>>>
>>>> - /* get an extra reference on the mle.
>>>> - * otherwise the assert_master from the new
>>>> - * master will destroy this.
>>>> - * also, make sure that all callers of dlm_get_mle
>>>> - * take both dlm->spinlock and dlm->master_lock */
>>>> - spin_lock(&dlm->spinlock);
>>>> - spin_lock(&dlm->master_lock);
>>>> - dlm_get_mle_inuse(mle);
>>>> - spin_unlock(&dlm->master_lock);
>>>> - spin_unlock(&dlm->spinlock);
>>>> -
>>>> /* notify new node and send all lock state */
>>>> /* call send_one_lockres with migration flag.
>>>> * this serves as notice to the target node that a
>>>> @@ -3312,6 +3307,15 @@ top:
>>>> mle->new_master != dead_node)
>>>> continue;
>>>>
>>>> + if (mle->new_master == dead_node && mle->inuse) {
>>>> + mlog(ML_NOTICE, "%s: target %u died during "
>>>> + "migration from %u, the MLE is "
>>>> + "still keep used, ignore it!\n",
>>>> + dlm->name, dead_node,
>>>> + mle->master);
>>>> + continue;
>>>> + }
>>>> +
>>>> /* If we have reached this point, this mle needs to be
>>>> * removed from the list and freed. */
>>>> dlm_clean_migration_mle(dlm, mle);
>>>>
>>>
>>>
>>> .
>>>
>>
>
>
> .
>
More information about the Ocfs2-devel
mailing list