Skip to content

Commit

Permalink
ocfs2: do not set OCFS2_LOCK_UPCONVERT_FINISHING if nonblocking lock …
Browse files Browse the repository at this point in the history
…can not be granted at once

ocfs2_readpages() use nonblocking flag to avoid page lock inversion.  It
will trigger cluster hang because that flag OCFS2_LOCK_UPCONVERT_FINISHING
is not cleared if nonblocking lock cannot be granted at once.  The flag
would prevent dc thread from downconverting.  So other nodes cannot
acheive this lockres for ever.

So we should not set OCFS2_LOCK_UPCONVERT_FINISHING when receiving ast if
nonblocking lock had already returned.

Signed-off-by: joyce.xue <[email protected]>
Reviewed-by: Junxiao Bi <[email protected]>
Cc: Mark Fasheh <[email protected]>
Cc: Joel Becker <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
xuejiufei authored and torvalds committed Dec 11, 2014
1 parent dc17158 commit d1e7823
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 6 deletions.
37 changes: 31 additions & 6 deletions fs/ocfs2/dlmglue.c
Original file line number Diff line number Diff line change
Expand Up @@ -861,8 +861,13 @@ static inline void ocfs2_generic_handle_convert_action(struct ocfs2_lock_res *lo
* We set the OCFS2_LOCK_UPCONVERT_FINISHING flag before clearing
* the OCFS2_LOCK_BUSY flag to prevent the dc thread from
* downconverting the lock before the upconvert has fully completed.
* Do not prevent the dc thread from downconverting if NONBLOCK lock
* had already returned.
*/
lockres_or_flags(lockres, OCFS2_LOCK_UPCONVERT_FINISHING);
if (!(lockres->l_flags & OCFS2_LOCK_NONBLOCK_FINISHED))
lockres_or_flags(lockres, OCFS2_LOCK_UPCONVERT_FINISHING);
else
lockres_clear_flags(lockres, OCFS2_LOCK_NONBLOCK_FINISHED);

lockres_clear_flags(lockres, OCFS2_LOCK_BUSY);
}
Expand Down Expand Up @@ -1324,20 +1329,31 @@ static void lockres_add_mask_waiter(struct ocfs2_lock_res *lockres,

/* returns 0 if the mw that was removed was already satisfied, -EBUSY
* if the mask still hadn't reached its goal */
static int lockres_remove_mask_waiter(struct ocfs2_lock_res *lockres,
static int __lockres_remove_mask_waiter(struct ocfs2_lock_res *lockres,
struct ocfs2_mask_waiter *mw)
{
unsigned long flags;
int ret = 0;

spin_lock_irqsave(&lockres->l_lock, flags);
assert_spin_locked(&lockres->l_lock);
if (!list_empty(&mw->mw_item)) {
if ((lockres->l_flags & mw->mw_mask) != mw->mw_goal)
ret = -EBUSY;

list_del_init(&mw->mw_item);
init_completion(&mw->mw_complete);
}

return ret;
}

static int lockres_remove_mask_waiter(struct ocfs2_lock_res *lockres,
struct ocfs2_mask_waiter *mw)
{
unsigned long flags;
int ret = 0;

spin_lock_irqsave(&lockres->l_lock, flags);
ret = __lockres_remove_mask_waiter(lockres, mw);
spin_unlock_irqrestore(&lockres->l_lock, flags);

return ret;
Expand Down Expand Up @@ -1373,6 +1389,7 @@ static int __ocfs2_cluster_lock(struct ocfs2_super *osb,
unsigned long flags;
unsigned int gen;
int noqueue_attempted = 0;
int dlm_locked = 0;

ocfs2_init_mask_waiter(&mw);

Expand Down Expand Up @@ -1481,6 +1498,7 @@ static int __ocfs2_cluster_lock(struct ocfs2_super *osb,
ocfs2_recover_from_dlm_error(lockres, 1);
goto out;
}
dlm_locked = 1;

mlog(0, "lock %s, successful return from ocfs2_dlm_lock\n",
lockres->l_name);
Expand Down Expand Up @@ -1514,10 +1532,17 @@ static int __ocfs2_cluster_lock(struct ocfs2_super *osb,
if (wait && arg_flags & OCFS2_LOCK_NONBLOCK &&
mw.mw_mask & (OCFS2_LOCK_BUSY|OCFS2_LOCK_BLOCKED)) {
wait = 0;
if (lockres_remove_mask_waiter(lockres, &mw))
spin_lock_irqsave(&lockres->l_lock, flags);
if (__lockres_remove_mask_waiter(lockres, &mw)) {
if (dlm_locked)
lockres_or_flags(lockres,
OCFS2_LOCK_NONBLOCK_FINISHED);
spin_unlock_irqrestore(&lockres->l_lock, flags);
ret = -EAGAIN;
else
} else {
spin_unlock_irqrestore(&lockres->l_lock, flags);
goto again;
}
}
if (wait) {
ret = ocfs2_wait_for_mask(&mw);
Expand Down
6 changes: 6 additions & 0 deletions fs/ocfs2/ocfs2.h
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,12 @@ enum ocfs2_unlock_action {
* before the upconvert
* has completed */

#define OCFS2_LOCK_NONBLOCK_FINISHED (0x00001000) /* NONBLOCK cluster
* lock has already
* returned, do not block
* dc thread from
* downconverting */

struct ocfs2_lock_res_ops;

typedef void (*ocfs2_lock_callback)(int status, unsigned long data);
Expand Down

0 comments on commit d1e7823

Please sign in to comment.