o2dlm: fix NULL pointer dereference in o2dlm_blocking_ast_wrapper
authorSrinivas Eeda <srinivas.eeda@oracle.com>
Tue, 10 Feb 2015 22:09:26 +0000 (14:09 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 10 Feb 2015 22:30:30 +0000 (14:30 -0800)
A tiny race between BAST and unlock message causes the NULL dereference.

A node sends an unlock request to master and receives a response.  Before
processing the response it receives a BAST from the master.  Since both
requests are processed by different threads it creates a race.  While the
BAST is being processed, lock can get freed by unlock code.

This patch makes bast to return immediately if lock is found but unlock is
pending.  The code should handle this race.  We also have to fix master
node to skip sending BAST after receiving unlock message.

Below is the crash stack

    BUG: unable to handle kernel NULL pointer dereference at 0000000000000048
    IP: o2dlm_blocking_ast_wrapper+0xd/0x16
    dlm_do_local_bast+0x8e/0x97 [ocfs2_dlm]
    dlm_proxy_ast_handler+0x838/0x87e [ocfs2_dlm]
    o2net_process_message+0x395/0x5b8 [ocfs2_nodemanager]
    o2net_rx_until_empty+0x762/0x90d [ocfs2_nodemanager]
    worker_thread+0x14d/0x1ed

[akpm@linux-foundation.org: coding-style fixes]
Signed-off-by: Srinivas Eeda <srinivas.eeda@oracle.com>
Reviewed-by: Mark Fasheh <mfasheh@suse.de>
Cc: Joel Becker <jlbec@evilplan.org>
Cc: Joseph Qi <joseph.qi@huawei.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
fs/ocfs2/dlm/dlmast.c

index b46278f9ae446ac1b139bd89c69649c66ea807b9..fd6bbbbd7d78df8f94534076f068f470c0f8f9d2 100644 (file)
@@ -385,8 +385,12 @@ int dlm_proxy_ast_handler(struct o2net_msg *msg, u32 len, void *data,
                head = &res->granted;
 
        list_for_each_entry(lock, head, list) {
-               if (lock->ml.cookie == cookie)
+               /* if lock is found but unlock is pending ignore the bast */
+               if (lock->ml.cookie == cookie) {
+                       if (lock->unlock_pending)
+                               break;
                        goto do_ast;
+               }
        }
 
        mlog(0, "Got %sast for unknown lock! cookie=%u:%llu, name=%.*s, "