]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - fs/dlm/user.c
[DLM] fix basts for granted PR waiting CW
[linux-2.6-omap-h63xx.git] / fs / dlm / user.c
index 37aad3fe8949f2103574764e7303a5a17a3e6d0f..6438941ab1f8baf21e4ca88ce5d05b120b525f8b 100644 (file)
@@ -138,6 +138,36 @@ static void compat_output(struct dlm_lock_result *res,
 }
 #endif
 
+/* Figure out if this lock is at the end of its life and no longer
+   available for the application to use.  The lkb still exists until
+   the final ast is read.  A lock becomes EOL in three situations:
+     1. a noqueue request fails with EAGAIN
+     2. an unlock completes with EUNLOCK
+     3. a cancel of a waiting request completes with ECANCEL/EDEADLK
+   An EOL lock needs to be removed from the process's list of locks.
+   And we can't allow any new operation on an EOL lock.  This is
+   not related to the lifetime of the lkb struct which is managed
+   entirely by refcount. */
+
+static int lkb_is_endoflife(struct dlm_lkb *lkb, int sb_status, int type)
+{
+       switch (sb_status) {
+       case -DLM_EUNLOCK:
+               return 1;
+       case -DLM_ECANCEL:
+       case -ETIMEDOUT:
+       case -EDEADLK:
+               if (lkb->lkb_grmode == DLM_LOCK_IV)
+                       return 1;
+               break;
+       case -EAGAIN:
+               if (type == AST_COMP && lkb->lkb_grmode == DLM_LOCK_IV)
+                       return 1;
+               break;
+       }
+       return 0;
+}
+
 /* we could possibly check if the cancel of an orphan has resulted in the lkb
    being removed and then remove that lkb from the orphans list and free it */
 
@@ -184,25 +214,7 @@ void dlm_user_add_ast(struct dlm_lkb *lkb, int type)
                log_debug(ls, "ast overlap %x status %x %x",
                          lkb->lkb_id, ua->lksb.sb_status, lkb->lkb_flags);
 
-       /* Figure out if this lock is at the end of its life and no longer
-          available for the application to use.  The lkb still exists until
-          the final ast is read.  A lock becomes EOL in three situations:
-            1. a noqueue request fails with EAGAIN
-            2. an unlock completes with EUNLOCK
-            3. a cancel of a waiting request completes with ECANCEL
-          An EOL lock needs to be removed from the process's list of locks.
-          And we can't allow any new operation on an EOL lock.  This is
-          not related to the lifetime of the lkb struct which is managed
-          entirely by refcount. */
-
-       if (type == AST_COMP &&
-           lkb->lkb_grmode == DLM_LOCK_IV &&
-           ua->lksb.sb_status == -EAGAIN)
-               eol = 1;
-       else if (ua->lksb.sb_status == -DLM_EUNLOCK ||
-           (ua->lksb.sb_status == -DLM_ECANCEL &&
-            lkb->lkb_grmode == DLM_LOCK_IV))
-               eol = 1;
+       eol = lkb_is_endoflife(lkb, ua->lksb.sb_status, type);
        if (eol) {
                lkb->lkb_ast_type &= ~AST_BAST;
                lkb->lkb_flags |= DLM_IFL_ENDOFLIFE;
@@ -309,6 +321,22 @@ static int device_user_unlock(struct dlm_user_proc *proc,
        return error;
 }
 
+static int device_user_deadlock(struct dlm_user_proc *proc,
+                               struct dlm_lock_params *params)
+{
+       struct dlm_ls *ls;
+       int error;
+
+       ls = dlm_find_lockspace_local(proc->lockspace);
+       if (!ls)
+               return -ENOENT;
+
+       error = dlm_user_deadlock(ls, params->flags, params->lkid);
+
+       dlm_put_lockspace(ls);
+       return error;
+}
+
 static int create_misc_device(struct dlm_ls *ls, char *name)
 {
        int error, len;
@@ -534,6 +562,14 @@ static ssize_t device_write(struct file *file, const char __user *buf,
                error = device_user_unlock(proc, &kbuf->i.lock);
                break;
 
+       case DLM_USER_DEADLOCK:
+               if (!proc) {
+                       log_print("no locking on control device");
+                       goto out_sig;
+               }
+               error = device_user_deadlock(proc, &kbuf->i.lock);
+               break;
+
        case DLM_USER_CREATE_LOCKSPACE:
                if (proc) {
                        log_print("create/remove only on control device");