--- /dev/null
+From c78a87d0a1fc885dfdbe21fd5e07787691dfb068 Mon Sep 17 00:00:00 2001
+From: David Teigland <teigland@redhat.com>
+Date: Thu, 18 Jun 2009 13:20:24 -0500
+Subject: [PATCH] dlm: fix plock use-after-free
+
+Fix a regression from the original addition of nfs lock support
+586759f03e2e9031ac5589912a51a909ed53c30a. When a synchronous
+(non-nfs) plock completes, the waiting thread will wake up and
+free the op struct. This races with the user thread in
+dev_write() which goes on to read the op's callback field to
+check if the lock is async and needs a callback. This check
+can happen on the freed op. The fix is to note the callback
+value before the op can be freed.
+
+Signed-off-by: David Teigland <teigland@redhat.com>
+Signed-off-by: Coly Li <coly.li@suse.de>
+---
+ fs/dlm/plock.c | 17 ++++++++++-------
+ 1 files changed, 10 insertions(+), 7 deletions(-)
+
+diff --git a/fs/dlm/plock.c b/fs/dlm/plock.c
+index 894a32d..16f682e 100644
+--- a/fs/dlm/plock.c
++++ b/fs/dlm/plock.c
+@@ -353,7 +353,7 @@ static ssize_t dev_write(struct file *file, const char __user *u, size_t count,
+ {
+ struct dlm_plock_info info;
+ struct plock_op *op;
+- int found = 0;
++ int found = 0, do_callback = 0;
+
+ if (count != sizeof(info))
+ return -EINVAL;
+@@ -366,21 +366,24 @@ static ssize_t dev_write(struct file *file, const char __user *u, size_t count,
+
+ spin_lock(&ops_lock);
+ list_for_each_entry(op, &recv_list, list) {
+- if (op->info.fsid == info.fsid && op->info.number == info.number &&
++ if (op->info.fsid == info.fsid &&
++ op->info.number == info.number &&
+ op->info.owner == info.owner) {
++ struct plock_xop *xop = (struct plock_xop *)op;
+ list_del_init(&op->list);
+- found = 1;
+- op->done = 1;
+ memcpy(&op->info, &info, sizeof(info));
++ if (xop->callback)
++ do_callback = 1;
++ else
++ op->done = 1;
++ found = 1;
+ break;
+ }
+ }
+ spin_unlock(&ops_lock);
+
+ if (found) {
+- struct plock_xop *xop;
+- xop = (struct plock_xop *)op;
+- if (xop->callback)
++ if (do_callback)
+ dlm_plock_callback(op);
+ else
+ wake_up(&recv_wq);
+--
+1.6.0.2
+