Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
[cascardo/linux.git] / fs / dlm / lock.c
index 83f3d55..35502d4 100644 (file)
@@ -5886,6 +5886,78 @@ int dlm_user_convert(struct dlm_ls *ls, struct dlm_user_args *ua_tmp,
        return error;
 }
 
+/*
+ * The caller asks for an orphan lock on a given resource with a given mode.
+ * If a matching lock exists, it's moved to the owner's list of locks and
+ * the lkid is returned.
+ */
+
+int dlm_user_adopt_orphan(struct dlm_ls *ls, struct dlm_user_args *ua_tmp,
+                    int mode, uint32_t flags, void *name, unsigned int namelen,
+                    unsigned long timeout_cs, uint32_t *lkid)
+{
+       struct dlm_lkb *lkb;
+       struct dlm_user_args *ua;
+       int found_other_mode = 0;
+       int found = 0;
+       int rv = 0;
+
+       mutex_lock(&ls->ls_orphans_mutex);
+       list_for_each_entry(lkb, &ls->ls_orphans, lkb_ownqueue) {
+               if (lkb->lkb_resource->res_length != namelen)
+                       continue;
+               if (memcmp(lkb->lkb_resource->res_name, name, namelen))
+                       continue;
+               if (lkb->lkb_grmode != mode) {
+                       found_other_mode = 1;
+                       continue;
+               }
+
+               found = 1;
+               list_del_init(&lkb->lkb_ownqueue);
+               lkb->lkb_flags &= ~DLM_IFL_ORPHAN;
+               *lkid = lkb->lkb_id;
+               break;
+       }
+       mutex_unlock(&ls->ls_orphans_mutex);
+
+       if (!found && found_other_mode) {
+               rv = -EAGAIN;
+               goto out;
+       }
+
+       if (!found) {
+               rv = -ENOENT;
+               goto out;
+       }
+
+       lkb->lkb_exflags = flags;
+       lkb->lkb_ownpid = (int) current->pid;
+
+       ua = lkb->lkb_ua;
+
+       ua->proc = ua_tmp->proc;
+       ua->xid = ua_tmp->xid;
+       ua->castparam = ua_tmp->castparam;
+       ua->castaddr = ua_tmp->castaddr;
+       ua->bastparam = ua_tmp->bastparam;
+       ua->bastaddr = ua_tmp->bastaddr;
+       ua->user_lksb = ua_tmp->user_lksb;
+
+       /*
+        * The lkb reference from the ls_orphans list was not
+        * removed above, and is now considered the reference
+        * for the proc locks list.
+        */
+
+       spin_lock(&ua->proc->locks_spin);
+       list_add_tail(&lkb->lkb_ownqueue, &ua->proc->locks);
+       spin_unlock(&ua->proc->locks_spin);
+ out:
+       kfree(ua_tmp);
+       return rv;
+}
+
 int dlm_user_unlock(struct dlm_ls *ls, struct dlm_user_args *ua_tmp,
                    uint32_t flags, uint32_t lkid, char *lvb_in)
 {
@@ -6029,7 +6101,7 @@ static int orphan_proc_lock(struct dlm_ls *ls, struct dlm_lkb *lkb)
        struct dlm_args args;
        int error;
 
-       hold_lkb(lkb);
+       hold_lkb(lkb); /* reference for the ls_orphans list */
        mutex_lock(&ls->ls_orphans_mutex);
        list_add_tail(&lkb->lkb_ownqueue, &ls->ls_orphans);
        mutex_unlock(&ls->ls_orphans_mutex);
@@ -6217,7 +6289,7 @@ int dlm_user_purge(struct dlm_ls *ls, struct dlm_user_proc *proc,
 {
        int error = 0;
 
-       if (nodeid != dlm_our_nodeid()) {
+       if (nodeid && (nodeid != dlm_our_nodeid())) {
                error = send_purge(ls, nodeid, pid);
        } else {
                dlm_lock_recovery(ls);