struct gdlm_plock_info info;
 };
 
+struct plock_xop {
+       struct plock_op xop;
+       void *callback;
+       void *fl;
+       void *file;
+       struct file_lock flc;
+};
+
+
 static inline void set_version(struct gdlm_plock_info *info)
 {
        info->version[0] = GDLM_PLOCK_VERSION_MAJOR;
 {
        struct gdlm_ls *ls = lockspace;
        struct plock_op *op;
+       struct plock_xop *xop;
        int rv;
 
-       op = kzalloc(sizeof(*op), GFP_KERNEL);
-       if (!op)
+       xop = kzalloc(sizeof(*xop), GFP_KERNEL);
+       if (!xop)
                return -ENOMEM;
 
+       op = &xop->xop;
        op->info.optype         = GDLM_PLOCK_OP_LOCK;
        op->info.pid            = fl->fl_pid;
        op->info.ex             = (fl->fl_type == F_WRLCK);
        op->info.start          = fl->fl_start;
        op->info.end            = fl->fl_end;
        op->info.owner          = (__u64)(long) fl->fl_owner;
+       if (fl->fl_lmops && fl->fl_lmops->fl_grant) {
+               xop->callback   = fl->fl_lmops->fl_grant;
+               locks_init_lock(&xop->flc);
+               locks_copy_lock(&xop->flc, fl);
+               xop->fl         = fl;
+               xop->file       = file;
+       } else
+               xop->callback   = NULL;
 
        send_op(op);
-       wait_event(recv_wq, (op->done != 0));
+
+       if (xop->callback == NULL)
+               wait_event(recv_wq, (op->done != 0));
+       else
+               return -EINPROGRESS;
 
        spin_lock(&ops_lock);
        if (!list_empty(&op->list)) {
                                  (unsigned long long)name->ln_number);
        }
 
-       kfree(op);
+       kfree(xop);
+       return rv;
+}
+
+/* Returns failure iff a succesful lock operation should be canceled */
+static int gdlm_plock_callback(struct plock_op *op)
+{
+       struct file *file;
+       struct file_lock *fl;
+       struct file_lock *flc;
+       int (*notify)(void *, void *, int) = NULL;
+       struct plock_xop *xop = (struct plock_xop *)op;
+       int rv = 0;
+
+       spin_lock(&ops_lock);
+       if (!list_empty(&op->list)) {
+               printk(KERN_INFO "plock op on list\n");
+               list_del(&op->list);
+       }
+       spin_unlock(&ops_lock);
+
+       /* check if the following 2 are still valid or make a copy */
+       file = xop->file;
+       flc = &xop->flc;
+       fl = xop->fl;
+       notify = xop->callback;
+
+       if (op->info.rv) {
+               notify(flc, NULL, op->info.rv);
+               goto out;
+       }
+
+       /* got fs lock; bookkeep locally as well: */
+       flc->fl_flags &= ~FL_SLEEP;
+       if (posix_lock_file(file, flc, NULL)) {
+               /*
+                * This can only happen in the case of kmalloc() failure.
+                * The filesystem's own lock is the authoritative lock,
+                * so a failure to get the lock locally is not a disaster.
+                * As long as GFS cannot reliably cancel locks (especially
+                * in a low-memory situation), we're better off ignoring
+                * this failure than trying to recover.
+                */
+               log_error("gdlm_plock: vfs lock error file %p fl %p",
+                               file, fl);
+       }
+
+       rv = notify(flc, NULL, 0);
+       if (rv) {
+               /* XXX: We need to cancel the fs lock here: */
+               printk("gfs2 lock granted after lock request failed;"
+                                               " dangling lock!\n");
+               goto out;
+       }
+
+out:
+       kfree(xop);
        return rv;
 }
 
 
        rv = op->info.rv;
 
+       if (rv == -ENOENT)
+               rv = 0;
+
        kfree(op);
        return rv;
 }
        op->info.start          = fl->fl_start;
        op->info.end            = fl->fl_end;
 
+
        send_op(op);
        wait_event(recv_wq, (op->done != 0));
 
 
        rv = op->info.rv;
 
-       if (rv == 0)
-               fl->fl_type = F_UNLCK;
-       else if (rv > 0) {
+       fl->fl_type = F_UNLCK;
+       if (rv == -ENOENT)
+               rv = 0;
+       else if (rv == 0 && op->info.pid != fl->fl_pid) {
                fl->fl_type = (op->info.ex) ? F_WRLCK : F_RDLCK;
                fl->fl_pid = op->info.pid;
                fl->fl_start = op->info.start;
        }
        spin_unlock(&ops_lock);
 
-       if (found)
-               wake_up(&recv_wq);
-       else
+       if (found) {
+               struct plock_xop *xop;
+               xop = (struct plock_xop *)op;
+               if (xop->callback)
+                       count = gdlm_plock_callback(op);
+               else
+                       wake_up(&recv_wq);
+       } else
                printk(KERN_INFO "gdlm dev_write no op %x %llx\n", info.fsid,
                        (unsigned long long)info.number);
        return count;